Vue響應(yīng)式原理
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <meta http-equiv="X-UA-Compatible" content="IE=edge">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? ? <title>Document</title>
</head>
<body>
? ? <div id="app">
? ? ? ? <input type="text" v-model="message">
? ? ? ? {{message}}
? ? </div>
? ?
? ? <script>
? ? ? ? class Vue{
? ? ? ? ? ? constructor(options){
? ? ? ? ? ? ? ? // 1.保存數(shù)據(jù)
? ? ? ? ? ? ? ? this.$options=options
? ? ? ? ? ? ? ? this.$data=options.data
? ? ? ? ? ? ? ? this.$el=options.el
? ? ? ? ? ? ? ? // 2.將data添加到響應(yīng)式系統(tǒng)中
? ? ? ? ? ? ? ? new Observer(this.$data)
? ? ? ? ? ? ? ? // 3.代理this.$data的數(shù)據(jù)
? ? ? ? ? ? ? ? Object.keys(this.$data).forEach(key=>{
? ? ? ? ? ? ? ? ? ? this._proxy(key)
? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? // 4.處理el
? ? ? ? ? ? ? ? new Compiler(this.$el,this)
? ? ? ? ? ? }
? ? ? ? ? ?
? ? ? ? ? ? _proxy(key){
? ? ? ? ? ? ? ? ? ? Object.defineProperty(this,key,{
? ? ? ? ? ? ? ? ? ? ? ? configurable:true,
? ? ? ? ? ? ? ? ? ? ? ? enumerable:true,
? ? ? ? ? ? ? ? ? ? ? ? set(newValue){
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.$data[key] = newValue
? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? get(){
? ? ? ? ? ? ? ? ? ? ? ? ? ? return this.$data[key]
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? }
? ? ? ? }
? ? ? ? class Observer{
? ? ? ? ? ? constructor(data){
? ? ? ? ? ? ? ? this.data=data
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? Object.keys(data).forEach(key=>{
? ? ? ? ? ? ? ? ? ? this.defineReactive(this.data,key,data[key])
? ? ? ? ? ? ? ? })
? ? ? ? ? ? }
? ? ? ? ? ? ? ? defineReactive(data,key,val){
? ? ? ? ? ? ? ? ? ? // 一個屬性就是一個Dep對象
? ? ? ? ? ? ? ? ? ? const dep =new Dep()
? ? ? ? ? ? ? ? ? ? Object.defineProperty(data,key,{
? ? ? ? ? ? ? ? ? ? ? ? configurable:true,
? ? ? ? ? ? ? ? ? ? ? ? enumerable:true,
? ? ? ? ? ? ? ? ? ? ? ? set(newValue){
? ? ? ? ? ? ? ? ? ? ? ? ? ? if(newValue==val){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? val = newValue
? ? ? ? ? ? ? ? ? ? ? ? ? ? dep.notify()
? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? get(){
? ? ? ? ? ? ? ? ? ? ? ? ? ? if(Dep.target){
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dep.addSub(Dep.target)
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? return val
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? }
? ? ? ? }
? ? ? ?
? ? ? ? class Dep{
? ? ? ? ? ? constructor(){
? ? ? ? ? ? ? ? this.subs=[]
? ? ? ? ? ? }
? ? ? ? ? ? addSub(sub){
? ? ? ? ? ? ? ? this.subs.push(sub)
? ? ? ? ? ? }
? ? ? ? ? ? notify(){
? ? ? ? ? ? ? ? this.subs.forEach(sub=>{
? ? ? ? ? ? ? ? ? ? sub.upDate()
? ? ? ? ? ? ? ? })
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? class Watcher{
? ? ? ? ? ? constructor(node,name,vm){
? ? ? ? ? ? ? ? this.node = node
? ? ? ? ? ? ? ? this.name = name
? ? ? ? ? ? ? ? this.vm = vm
? ? ? ? ? ? ? ? Dep.target=this
? ? ? ? ? ? ? ? this.upDate()
? ? ? ? ? ? ? ? Dep.target=null
? ? ? ? ? ? }
? ? ? ? ? ?
? ? ? ? ? ? upDate(){
? ? ? ? ? ? ? ? this.node.nodeValue = this.vm[this.name]
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? const reg = /\{\{(.*)\}\}/
? ? ? ? class Compiler{
? ? ? ? ? ? constructor(el,vm){
? ? ? ? ? ? ? ? this.el=document.querySelector(el)
? ? ? ? ? ? ? ? this.vm=vm
? ? ? ? ? ? ? ? console.log(vm,"這是vm")
? ? ? ? ? ? ? ? this.frag=this._createFragment() ?//創(chuàng)建代碼片段,讓片段和頁面的代碼形成映射關(guān)系
? ? ? ? ? ? ? ? this.el.appendChild(this.frag)
? ? ? ? ? ? }
? ? ? ? ? ? _createFragment(){
? ? ? ? ? ? ? ? const frag =document.createDocumentFragment() ?//后面要添加到el中
? ? ? ? ? ? ? ? let child;
? ? ? ? ? ? ? ? while(child=this.el.firstChild){ ? //每次遍歷后會移除
? ? ? ? ? ? ? ? ? ? this._compile(child)
? ? ? ? ? ? ? ? ? ? frag.appendChild(child)
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? return frag
? ? ? ? ? ? }
? ? ? ? ? ? _compile(node){
? ? ? ? ? ? ? ? if(node.nodeType===1){ ? //nodeType===1 表示是標(biāo)簽節(jié)點
? ? ? ? ? ? ? ? ? ? const attrs = node.attributes
? ? ? ? ? ? ? ? ? ? if(attrs.hasOwnProperty('v-model')){
? ? ? ? ? ? ? ? ? ? ? ? const name = attrs['v-model'].nodeValue
? ? ? ? ? ? ? ? ? ? ? ? console.log(node,"這是node")
? ? ? ? ? ? ? ? ? ? ? ? node.value=this.vm[name]
? ? ? ? ? ? ? ? ? ? ? ? node.addEventListener('input',e=>{
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.vm[name]=e.target.value
? ? ? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? if(node.nodeType===3){ ? ?//nodeType===2表示是文本節(jié)點
? ? ? ? ? ? ? ? ? ? console.log(reg.test(node.nodeValue))
? ? ? ? ? ? ? ? ? ? if(reg.test(node.nodeValue)){
? ? ? ? ? ? ? ? ? ? ? ? const name = RegExp.$1.trim() ?//$1 拿到正則中第一個分組 ?“()” 中的東西 ?即為變量名 此代碼中的message
? ? ? ? ? ? ? ? ? ? ? ? console.log(name);
? ? ? ? ? ? ? ? ? ? ? ? new Watcher(node,name,this.vm)
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? </script>
? ? <script>
? ? const app = new Vue({
? ? ? ? el:"#app",
? ? ? ? data:{
? ? ? ? ? ? message:"我是一條message"
? ? ? ? }
? ? })
? ? </script>
</body>
</html>