vue 2.0 实现数据响应式变化的原理

241 阅读1分钟

初始化文件夹,并安装vue

cnpm init -y

cnpm add vue

在根目录下新建html文档(index.html)

VS code 生成html模板的快捷键:! + tab

引入vue.js

    <script src="./node_modules/vue/dist/vue.js"></script>

创建vue实例,实现数据绑定

<div id="app">{{msg}}</div>

let vm = new Vue({
    data:{  //把data里的数据绑定到视图上,其实就是模板引擎 ejs的原理(with),把data作为上下文
        msg:"hello"
    },
    el:"#app"  //将实例挂载到普通的dom元素  不能是body、html
})
vm.msg = "aaa"

vue2.0 实现数据响应式变化 用的是Object.defineProperty (不支持数组)

模拟数据响应式渲染

let obj = {
    name:"张三",
    location:{
        x:100,y:100
    }
}
function render(){
    console.log('渲染视图')
}
//监听
function observer(obj){
    if(typeof obj == 'object'){
        for(let key in obj){
            defineReactive(obj,key,obj[key])
        }
    }
}
function defineReactive(data,key,value){
    observer(value)
    Object.defineProperty(data,key,{
        get(){
            return value
        },
        set(newValue){
            render()
            value = newValue
        }
    })
}
observer(obj)
obj.location.x=200

以上代码可以监听对象原有属性的修改,如果想要新增一个属性则监听不到,有2种解决办法:

$set(obj,'a',1) //可以随意对象新增属性 包含根级obj

obj.location = {...obj.location,a:1} //因为监听的是obj里面的属性,所以不能监听obj本身

$set 原理

function $set(data,key,value){
    defineReactive(data,key,value)
}

如果是数组,需要重写数组的方法

let methods = ['push','pop','shift','unshift','splice','sort','reverse'];//只对这7种会改变原数组的方法重写
//拿到数组原型上的方法 
let arrProto = Array.ProtoType;
//Object.create()创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
let proto = Object.create(arrProto)
methods.forEach( method=>{
    proto[method] = function(){  //AOP
        render();
        arrProto[method].call(this,...arguments)
    }
})
function render(){
    //渲染元素
}
function observer(obj){
    if(Array.isArray(obj)){
        obj.__proto__ = proto
        return
    }
    if(typeof obj == 'object'){
        //如果是对象。。。如上
    }
}
let arr=[1,2,3,4,5]
observer(arr)
//$set  $Set(arr,0,10)
function $set(data,key,value){
    if(Array.isArray(data)){
    //把数组第0位改为1 内部使用splice  因为可改变原数组,重写了这个方法
        return data.splice(key,1,value)
    }
}

//不能修改数组长度,例如 arr.length--

//不支持数组内容发生变化 必须通过以上7种方法出发更新 或者替换成新的数组