计算机系统应用教程网站

网站首页 > 技术文章 正文

vue双向数据绑定原理 vue双向数据绑定原理简书

btikc 2024-10-12 13:25:00 技术文章 7 ℃ 0 评论

前置技术点

1、数组reduce()方法
应用场景:下次操作的初始值,依赖于上次操作的返回值

  • 数值的累加计算
 //一个数组的所有项累加
    const arr = [2,3,4,6,2,12,34,56]; 
    //    一般实现方案 
    let total = 0;
    arr.forEach((item) => {
        total += item;
    })
    console.log('total--',total);

    // 数组的reduce方法,会循环当前的数组,侧重于进行“滚雪球”操作
    // 数组.reduce(函数,初始值)
    // 数组.reduce ((上次计算的结果,当前循环的Item项) => {},0)
    // const 累加的结果 = 数组.reduce((上次计算的结果,当前循环的Item项) => {return 上次的结果+ 当前循环的Item项},0)
    const total2 = arr.reduce((val,item)=>{
        return val+ item;
    })
    console.log('total2--',total2);
  • 链式获取对象属性的值

2、发布订阅模式

  1. Dep类
  • 负责进行依赖收集
  • 首先,有个数组,专门用来存放所有的订阅信息
  • 其次,还要提供一个向数组中追加订阅信息的方法
  • 最后,还要提供一个循环,循环触发数组中的每个订阅信息
    注:只要我们为Vue中data数据重新赋值了,这个赋值的动作,会被Vue监听到,
    然后vue要把数据的变化通知每个订阅者,
    接下来,订阅者(DOM元素)要根据最新的数据,更新自己的内容
  1. Watcher 类
  • 负责订阅一些事件

3、 使用object.defineProperty()进行数据劫持
1. 通过get()劫持取值操作
2. 通过set()劫持赋值操作

    //定义一个数据劫持的方法
    function Observe(obj){
        //这是递归的终止条件
        if(!obj || typeof obj!='object') return;
        //通过Object.keys(obj)获取当前obj上的每个属性
        Object.keys(obj).forEach((key) => {
            //当前被循环的key所对应的属性值
            let value = obj[key];
            //当前被循环的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);
                }
            })
        })
    }

为什么methods对象下的法可以通过this获得data下的属性

  //属性代理
   object.key((this.$data).forEach((key) => {
       object.defineProperty(this,key,{
           enumerable: true,
           configurable: true,
           get(){
               return this.$data[key];
           },
           set(newValue){
               this.$data[key] = newValue;
           }
       })
   }))

对html结构进行模板编译

//对html结构进行模板编译的方法
function Compile(el,vm){
    //获取el对应的DOM元素
    vm.$el = document.querySelector(el);
    
    //创建文档碎片,提高DOM操作的性能
    const fragment = document.createDocumentFragment();
    while ((childNode = vm.$el.firstChild)){
        fragment.appendChild(childNode)
    }

    //进行模板编译
    vm.$el.appendChild(fragment);

 
}
   //负责对DOM模板进行编译的方法
    function replace(){
        //定义匹配插值表达式的正则
        const regMustache = /\{\{\s*(S+)\s*\}\}/

        //证明当前的node节点是一个文本子节点,需要进行正则的替换
        if(node.nodeType === 3){
            //注意:文本子节点,也是一个DOM对象,如果要获取文本子节点的字符串内容,需要调用textContent属性获取
            const text = node.textContent;
            const execResult = regMustache.exec(text);

            console.log(execResult)
            if(execResult){
                const value = execResult[1].split('.').reduce((newObj,k)=>newObj[k],vm);
                node.textContent = text.replace(regMustache,value)
            }
            //终止递归的条件
            return 
        }

        //证明不是文本节点,可能是一个DOM元素,需要进行递归处理
        node.childNodes.forEach((child) => replace(child));
    }

最简单的发布订阅

// 最简单的发布订阅模式


// 收集依赖/收集订阅者
class Dep {
  constructor(){
    //这个subs数组,用来存放所有订阅者的信息
    this.subs = [];
  }
  //向subs数组中,添加订阅者信息
  addSub(watcher){
    this.subs.push(watcher);
  }


// 发布通知的方法
notify(){
  this.subs.forEach((watcher) => watcher.update());
}

}

//订阅者的类

class Watcher{

  // cb回调函数中,记录着当前Watcher如何更新自己的文本内容
// 但是,只知道如何更新自己还不行,还必须拿到最新的数据
// 因此 还需要在new Watcher 期间,把vm 也传递过来(因为vm中保存着最新的数据)
// 除此之外,还需知道,在vm身上众多数据中,哪个数据,才是当前自己需要的数据
// 因此, 必须在new Watcher期间,指定watcher对应的数据名字

  constructor(vm,key,cb){
    this.vm = vm;
    this.key = key;
    this.cb = cb;
  }
  // watcher 的实例,需要有update函数,从而让发布者能够通知我们进行更新
  update(){
    this.cb()
  }
}

const w1 = new Watcher(() =>{
  console.log('我是第一个订阅者')
})

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表