vue2.0数据劫持原理

vue2.0数据劫持原理

vue2.0数据劫持

数据劫持的意义?

一个数据操作,我们希望在他做赋值的过程当中,我们还可以给他增加一些事情,比如说像这个视图上的改变,我们希望的是当你数据变化的这个过程当中,那我们就拦截这些行为,在这个行为的这个过程当中,还能做更多的事,而不是单纯的操作数据

数据劫持都做了哪些事呢?

首先,new了一个vue实例,传参options如:new Vue({el:"#app",data(){return {}title:‘xxx’,testArr:[1,2,3]}})。这里只讲data,data是一个函数,需要执行之后才能拿到数据对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HvqQmp6A-1623068431810)(C:\Users\YuPeng Zheng\AppData\Roaming\Typora\typora-user-images\image-20210606161111128.png)]

然后,到vue/index.js中,声明了Vue构造函数。任何一个程序都会有初始化的过程。然后在他的原型上挂在了一个init方法,把options挂载到vm实例上vm.$options = options,然后再进行initState(vm)初始化数据状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mmRkAsY6-1623068431815)(C:\Users\YuPeng Zheng\AppData\Roaming\Typora\typora-user-images\image-20210606161125192.png)]

然后,initState(init.js)中,进行初始化各种数据的状态,可能会有data,watch,computed。。。等等。这里只讲data。initData(vm),判断data的类型,是函数就执行是对象就直接返回对象并赋值到vm._data

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kUBuUpee-1623068431816)(C:\Users\YuPeng Zheng\AppData\Roaming\Typora\typora-user-images\image-20210606161036850.png)]

然后,为了解决访问方式,更改this指向,使得vm.data.title变为vm.title,就进行代理劫持。proxy.js,循环data,并且调用proxyData(vm,"-data".key),Object.fineProperty将vm.tilte解析为vm.-data.title,这样就改写了访问方式,把data中的每个对象都变成这样的访问方式,并且此时还对vm._-data进行观察observe(vm.-data)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6u8nIUYr-1623068431818)(C:\Users\YuPeng Zheng\AppData\Roaming\Typora\typora-user-images\image-20210606161053286.png)]

再然后,observe.js。判断类型不是对象不是数组或者为null直接return,否则观察者进行观察他,new Observer(data)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xLkiHiSj-1623068431820)(C:\Users\YuPeng Zheng\AppData\Roaming\Typora\typora-user-images\image-20210606160922043.png)]

然后,Observer.js,判断数组还是对象,分别处理,对象就递归调用observe,数组就重写数组方法,再进行观察里面的对象。

对象的时候:Observer的原型上挂载walk(data),然后遍历data,进行响应式数据劫持,defineReactiveData(data,key,value)。这里面就是obeject.defineProperty的递归执行了,然后再利用get()set(),reactive.js(defineReactiveData)中,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q8B5toxF-1623068431821)(C:\Users\YuPeng Zheng\AppData\Roaming\Typora\typora-user-images\image-20210606160806193.png)]

数组的时候:array.js读取config.js中的数组处理的几种方法,因为数组操作会更改原数组,也是要监测到他数组变化的过程,去做一些其他的事情,(例如视图更新)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HX43GzUZ-1623068431822)(C:\Users\YuPeng Zheng\AppData\Roaming\Typora\typora-user-images\image-20210606162310298.png)]

数组变化的时候还要劫持数组的元素就需要observerArr.js

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aj1yb6QV-1623068431823)(C:\Users\YuPeng Zheng\AppData\Roaming\Typora\typora-user-images\image-20210606162443903.png)]

总之就是来回的执行observe,数组操作很巧妙。

1,首先配置webpack,使用webpack搭建服务

2,然后更改创建各项文件夹及文件。

3,模拟vue引入,手动创建vue文件夹以及index.js,webpack中重写路径,当import vue from 'vue’的时候会指向vue文件夹下的index.js

4,new一个vue实例,并传参

import Vue from 'vue'

let vm = new Vue({
    el:'#app',
    data(){
        return{
            order:'目标数据',
            myObj:{
                status:'故障',
                type:{
                    name:'类型1'
                }
            }
        }
    }
})

5,那么该vue接收里面的options。

//单独拿出去  初始化数据的方法
import {initState} from './init'

function Vue(options){
    this._init(options)

}
//实际vue就是将很多方法和数据挂载到vue的原型上
//只看data  一定会有一个初始化的方法  初始化数据
Vue.prototype._init = function(options){
    var vm = this   //赋值保存this
    vm.$options = options
    //初始化数据状态
    initState(vm);
}
export default Vue

6,initState.js,初始化状态,判断data的类型,如果是函数,就得执行他,否则直接vm.data.order是拿不到里面的数据的

import proxyData from './proxy'
function initState(vm){
    // console.log(vm)
    var options = vm.$options
    //针对不同的数据都要初始化 可能options还会有computed  watch 都要分别init
    if(options.data){
        initData(vm)
    }
}

function initData(vm){
    var data = vm.$options.data;  //保留data原数据  接收原数据
    //需要判断data是对象的话就执行他并接收他执行的返回结果  如果是对象就。。
    data = vm._data = typeof data === 'function'?data.call(vm):data||{}
    //到上面这一步还不能进行劫持  数据访问需要  vm._data.order而不能直接通过vm.order拿到
    //下面用代理实现他
    //原理是在访问的时候进行拦截 重新定义它
    for(var key in data){
        proxyData(vm,'_data',key)
    }
}

export{
    initState
}

7,proxyData.js,进行劫持,当界面获取、设置data里面的数据的时候,就会进入这里进行劫持,去掉_data,使得访问数据的方式从vm._data.order变成vm.order。

function proxyData(vm,target,key){
    Object.defineProperty(vm,key,{
        get(){
            return vm[target][key]
        },
        set(newVal){
            vm[target][key] = newVal
        }
    })
}
export default proxyData

但是至此以上也仅仅是改变了访问data里面数据的方式而已。但是还并没有对data里面的数据或data里面的对象里面的数据进行劫持。(所谓劫持就是在获取或赋值的时候进行拦截,让他重新返回或者走一步自定义的逻辑),还需要对每一项数据进行代理劫持。

8,观察者observe.js,观察vm.data

import defineReactiveData from './reactive'
function observe(data){
    if(typeof(data)!=='object'||data===null)return
    return new Observer(data)
}
function Observer(data){
    //处理数组
    if(Array.isArray(data)){

    }else{  //处理对象
        this.walk(data)
    }
}
Observer.prototype.walk = function(data){
    var keys = Object.keys(data)
    for (var i=0;i<keys.length;i++){
        var key = keys[i]
        var value = data[key]

        //
        defineReactiveData(data,key,value)
    }
}
export default observe

9,在reactive.js中进行数据劫持,因为data[key]里面的还有可能是对象,就需要递归执行

import observe from './observe'
function defineReactiveData(data,key,value){
    //这个时候的value有可能还是个对象  递归执行观察
    observe(value)
    Object.defineProperty(data,key,{
        get(){
            console.log('响应式数据:获取',value)
            return value
        },
        set(newValue){
            if(newValue===value)return
            value = newValue
        }
    })
}

export default defineReactiveData

以上完成了对data以及data中的对象以及data.obj.obj的劫持,还需要对当中的数组进行劫持,但是操作数组的很多方法都会改变原数组,所以需要自己定义这些数组方法。

10,未整理完,后续补全

码云地址:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_小郑有点困了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值