文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

vue实现双向数据绑定

2024-04-02 19:55

关注

本文实例为大家分享了vue实现双向数据绑定的具体代码,供大家参考,具体内容如下

vue中数组与对象采用了不同的绑定方式

1.vue对象数据绑定

(1)数据侦测

在js中,我们使用Object.defineProperty()和ES6的proxy来对对象进行侦测

在vue2.x中使用的是Object.defineProperty()来对对象进行数据侦测,我们首先对Object.defineProperty进行封装,有如下的代码:


function defineReactive(data, key, val){
    if(typeof val === 'object') new Observer(val)
    let dep = new Dep();
    Object.defineProperty(data, key, val) {
    enumerable: true,
    configurable: true,
    get: function () {
        dep.depend();
        return val;
    },
    set: function() {
        if(val === newVal) {
            return ;
        }
        val = newVal;
        dep.notify()
    }
}
}

需要传递的参数只有data, key, val,每当从data中的key中读取数据的时候触发get,修改的数据的时候触发set

(2)依赖收集

先收集依赖,等到属性发生改变的时候,再把收集到的依赖循环触发一遍就好了,在getter中收集依赖,在setter中触发依赖

依赖类Dep


export default class Dep {
    constructor() {
        this.subs = []
    }
    
    addSub() {
        this.subs.push(sub)
    }
    
    removeSub(sub) {
        remove(this.subs, sub)
    }
    
    depend() {
        if(window.target) {
            this.addSub(window.target)
        }
    }
    
    notify() {
        const subs = this.subs.slice()
        for(let i = 0, l = subs.length; i < l; i++) {
            subs[i].update()
        }
    }
}
 
function remove(arr, item) {
    if(arr.length) {
        const index = arr.indexOf(item)
        if(index > -1) {
            return arr.splice(index, 1)
        }
}
}

watcher类是我们收集的依赖


export default class Watcher {
    constructor(vm, expOrFn, cb) {
        this.vm = vm
        this.getter = parsePath(expOrFn)
        this.cb = cb
        this.value = this.get()
    }
    
    get() {
        window.target = this
        let value = this.getter.call(this.vm, this.vm)
        window.target = undefined
        return value
    }
    
    update() {
        const oldValue = this.value
        this.value = this.get()
        this.cb.call(this.vm, this.value, oldValue)
    }
}

(3)递归侦测所有key (Observer) 


export class Observer {
    constructor(value) {
        this.value = value;
        
        if(!Array.isArray(value)) {
            this.walk(value)
        }
    }
    walk(obj) {
        const keys = Object.keys(obj)
        for(let i = 0; i < keys.length; i++) {
            defineReactive(obj, keys[i], obj[keys[i]])
        }
    }
}

Observer类就是将对象的所有属性变为响应式的

2.Array的变化侦测

(1)数组中追踪变化用的是拦截器覆盖原型方法


const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto);
//和数组原型一样的对象作为拦截器
['push','pop','shift','unshift','splice','sort','reverse'].forEach(function (method) {
    const original = arrayProto[method]
    Object.defineProperty(arrayMethods, method, {
        value: function mutator(...args) {
              return original.apply(this, args)
        },
        enumerable: false,
        writable: true,
        configurable: true
    })
})

拦截器覆盖原型只有一句话


value.__proto__ = arrayMethods

如果没有__proto__属性,vue将会把这些arrayMethods挂载到被侦测的数组上

数组与对象类似,都是在getter中收集依赖,而数组触发依赖实在拦截器里面

数组的依赖保存在Observer实例上,依赖必须是getter和拦截器中都可以访问到的

__ob__是不可枚举属性,这个属性的值就是当前Observer实例

把Dep实例保存在Observer的属性上,如果value已经有__ob__属性,则不需要重复创建Observer实例,避免重复侦测value的变化

像数组的依赖发送通知


this.__ob__.dep.notify();

(2).侦测数据变化的具体方法

循环数组中的每一项,执行observe函数来侦测变化


observeArray(items) {
    for(let i = 0; l = items.length; i < l; i++) {
        observe(items[i]);    
    }
}

数组需要侦测新的元素

通过拦截push,unshift,splice等方法,并且把args存储在inserted中


if(inserted) ob.observeArray(inserted)

总结:

Array追踪变化的方式和Object不一样,所以我们通过创建拦截器去覆盖数组原型的方式来追踪变化,为了不污染全局Array.prototype,我们在Observer中只针对需要侦测变化的数组使用__proto__来覆盖原型。

Array收集依赖的方式和Object一样,都在getter中收集,在拦截器中触发,依赖保存在Observer实例上。在Observer上,我们每个侦测的数据都标记上了__ob__,并把this(Observer)保存在__ob__上,主要是为了保证同一数据只被侦测一次,另外可以很方便的通过__ob__从而拿到Observer实例上保存的依赖。数组需要循环把每一个数组项都变成响应式的,当数组中新增元素的时候,我们把参数提取出来,然后使用observeArray对新增的数据进行变化侦测,对于数组,只能拦截原型方法,对于一些特有的方法就无法拦截。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯