Vue2的双向数据绑定技术点

Vue2的双向数据绑定技术点

1. 数组的reduce()方法

  • 应用场景一:如何实现数组的累加?
const arr = [3,7,8,9,0,123];
//  function 1
let total = 0;
arr.forEach((item)=>{
    total += item;
})
// anymore ?

reduce语法: arr.reduce(function(prev,nowValue,currentIndex,Array),initial)

解析:

  • 对于数组arr中的每一项,调用一次function。
  • 可以通过initial给function指定初始值(第一个元素执行function的prev),如果没有指定initial,则会从第二项开始执行function,此时的prev的值为第一个元素。

侧重点:滚雪球

// function 2
let total = arr.reduce((prev,value)=>{
    return prev+value;
})
  • 应用场景2:链式获取对象的属性值。
//如何通过reduce获取到Pikaqiu的最喜欢颜色?
const Pikaqiu = {
    name : '皮卡丘',
    info :{
        favourite:{
            color:'yellow',
        },
    },
}

看到这里,可能有小伙伴一头雾水,但是当我们拥有一个对象属性的数组,那么就可以使用reduce方法进行滚雪球式地获取属性了。

//传入根节点(对象)作为初始值
const attrs = ['info','favourite','color'];
let ans = attrs.reduce((newObj,key)=>{
    return newObj[key];
},Pikaqiu)
console.log(ans);//yellow

或许你会说,这不需要我们提前手动写好我们对象的一层层属性吗?实际上没啥用。

但是,当你再去使用Vue的模板字符串的时候,思路就此打开…

  1. 假设我们在HTML里面使用了模板字符串<div>{{info.favourite.color}}</div>
  2. 通过{{}}我们获取到了一个字符串 info.favourite.color

大声告诉我, ~把大象装进冰箱需要几步? ~如何将上面的字符串转成我们需要的数组?

let attrStr = 'info.favourite.color';
let attrs = attrStr.split('.');
//箭头函数更短小精悍写法:省略花括号和return
let ans2 = attrs.reduce((newObj,key)=> newObj[key],Pikaqiu);
console.log(ans2);// yellow

2. 发布订阅模式

  • Dep:收集依赖/收集订阅

  • 要求:

    • 首先,有个数组专门来存放所有的订阅信息。
    • 其次,还要提供一个向数组中追加订阅信息的方法。
    • 然后,还要提供一个循环,循环触发数组中的每个订阅信息。
  • 属性:

    • subs:存放所有订阅者的信息
    • addSub:添加订阅者
    • notify:发布通知
  • Watcher:订阅者的类,负责订阅一些事件。

    • callback:存储回调函数
    • update:触发回调函数

下面我们创建最基本的Dep和Watcher对象

class Dep{
    constructor(){
        this.subs = [];//存放所有订阅者信息
    }
    addSub(watcher){
        this.subs.push(watcher);
    }
    //通知所有订阅者
    notify(){
        //...根据订阅者的更新方法进行编辑
        this.subs.forEach((watcher)=> watcher.update());
    }
}
//订阅者
class Watcher{
    constructor(callbackFunction){
        this.callback = callbackFunction;
    }
    update(){
        this.callback();
    }
}

接着我们构造几个订阅者,实现一个最简单的发布订阅。

  1. 我们把训练师小智(xiaozhi)当成发布者,宝可梦当作订阅者。
  2. 每当小智需要与别人战斗的时候,就通知(notify)所有自己收服的宝可梦(或者说每一个订阅了这个Dep的watcher)。
  3. 此时,所有的宝可梦都被唤醒来干活了(update)。
const w1 = new Watcher(()=>{
    console.log("我是1号订阅者皮卡丘");
})
const w2 = new Watcher(()=>{
    console.log("我是2号订阅者喷火龙");
})
const xiaozhi = new Dep();//创建
xiaozhi.addSub(w1);//收服皮卡丘
xiaozhi.addSub(w2);//收服喷火龙
xiaozhi.notify();//通知所有宝可梦干活
  • 理解Vue:

    • 只要我们为Vue中的data数据重新赋值了,这个赋值的动作,会被Vue监听到。(具体怎么监听到的,需要通过defineProperty()进行数据劫持)
    • vue只需要把数据的变化通知到每一个订阅者(notify
    • 订阅者(DOM元素)根据最新的数据,更新 自己的内容即可。

3. Object.defineProperty()

vue2的数据代理的原理,使用该方法进行数据劫持。 Vue3使用Proxy代理。

//class Person(){...}
//person = new Person();

//_data 代理 data
Object.defineProperty(person,"_data",{
    value:18,
    enumerable:true,//控制属性是否可以被枚举
    writable:true,//控制属性是否可以被修改
    configurable:true,//控制属性是否可以被删除
    //通过set()劫持赋值操作
    set:function(value){
        //在此方法中,我们可以在此调用更新DOM的方法
        data = value;
    },
    //通过get()劫持取值操作
    get:function(){
        return data;
    }
})
class Vue{
    constructor(options){
        this.$data = options.data;//调用数据劫持的方法
        Observe(this.$data);
        
        //属性代理,直接找vm要属性值,那么就可以返回$data的数据给它。便利使用者。
        Object.keys(this.$data).forEach(key=>{
            Object.defineProperty(this,key,{
                enumerable:true,
                configurable:true,
                get(){
                    return this.$data[key]
                },
                set(newValue){
                    this.$data[key] = newValue;
                },
            })
        })
        
    }
    
}
//定义一个数据劫持方法
function Observe(obj){
    // 我们需要考虑递归的情况,即属性也是一个对象的情况
    // 递归终止条件
    if(!obj || typeof obj !== 'object') return ;
    
    //通过Object.keys(obj)获取到当前obj上的每一个属性。
    console.log(Object.keys(obj));
    Object.keys(obj).forEach(key=>{
        //当我们拿到一个子节点的时候
        let value = obj[key];
        Observe(value);//进入子节点
        //为当前的key所对应的属性,添加getter和setter
        Object.defineProperty(obj,'key',{
            enumerable:true,
            configurable:true,
            get(){
                console.log(`有人获取了${key}的值`)
                return value;
            },
            set(newVal){
                value = newVal;
                Observe(value);//深度更新里面的内容,假如我直接将字符串name修改为一个嵌套的对象。
            }
        })
    })
}

注意:

  1. 对象的数据劫持与数组的不同

    上述的数据劫持仅仅针对对象的数据拦截。而没有对数组进行数据劫持。Vue2中对数组的数据代理实现完全不同于对象的。而是通过修改数组的变异方法来实现的。

  2. 通过$data来代理实际data里面的数据

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

如果皮卡会coding

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

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

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

打赏作者

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

抵扣说明:

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

余额充值