• Vue-如何实现响应式


    写在前面:总算在今天仔仔细细的看了一遍双向数据绑定的帖子,其实之前也看了很多,都是自己理解能力不太够,再一个静不下心(哭)。看完之后进行一下总结。如有理解不到位的欢迎指正,谢谢。

    Vue的响应式:其实就是通过数据的改变去驱动DOM视图的变化。这里是Vue最核心的内容。初始化时通过Object.defineProperty进行绑定,设置通知的机制。当编译生成的渲染函数被实际渲染的时候,就会触发getter进行依赖收集,在数据变化的时候,触发setter进行更新。

    首先一个小小入门例子。假设<p>标签的内容会随着obj中数据的改变而变化.。

    1 <div id="app">
    2         <p id="name"></p>
    3     </div>
    4     <script>
    5         var obj={}
    6         obj.name="软软"//操作Object.defineProperty来使得name数据的改变影响p标签
    7     </script>

    通过Object.defineProperty(obj, prop, descriptor)来实现。 obj:要在其上定义属性的对象。prop:要定义或修改的属性的名称。descriptor:将被定义或修改的属性描述符。 

     1 <div id="app">
     2         <p id="name"></p>
     3 </div>
     4 <script>
     5      var obj={};
     6      Object.defineProperty(obj,'name',{
     7             get(){
     8                 return document.querySelector('#name').innerHTML;
     9             },
    10             set(newVal){
    11                 document.querySelector('#name').innerHTML=newVal
    12             }
    13       })
    14    obj.name="软软"//操作Object.defineProperty来使得name数据的改变影响p标签
    15 </script>

    接下来创建一个新的newVue.js。通过使用new NewVue(.....)来实现vue的响应式

     1 class NewVue{
     2     constructor(options){//接收所想要配置的对象就像是new Vue({data:{...}})
     3         this.$options=options;//先缓存一下options一会其他的类要用到
     4         //数据响应化
     5         this.$data=options.data;//拿出{data:{}}的数据
     6         this.observe(this.$data);//对data中的数据进行观察.
     7     }
     8     observe(value){
     9         //为了语句健壮性,先判断是否存在这个value,不存在就返回了
    10         if(!value||typeof value !='object'){
    11             return;
    12         }
    13         //遍历该对象
    14         Object.keys(value).forEach(key=>{
    15             
    16             this.defineReactive(value,key,value[key])
    17         })
    18     }
    19     //定义数据响应式函数
    20     defineReactive(obj,key,val){
    21         this.observe(val)//为了递归实现类似{data:{foo.bar:"xxx"}}中的foo.bar这种数据嵌套的问题
    22         Object.defineProperty(obj,key,{
    23             get(){
    24                 return val;
    25             },
    26             set(newVal){
    27                 if(newVal==val){
    28                     return;
    29                 }
    30                 val=newVal;
    31                 console.log(`${key}属性更新了:${val}`)
    32             }
    33         })
    34     }
    35 }

    创建一个index.html实现这个响应式

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script src="newVue.js"></script>
        <script>
            const app=new NewVue({
                data:{
                    test:"fjs是粑粑",
                    foo:{
                        bar:"bar"
                    }
                }
            });
            app.$data.test="hello fjs";
            app.$data.foo.bar="oh bar"
        </script>
    </body>
    </html>

    最终实现的结果:

     依赖收集

     1 class NewVue{
     2     constructor(options){
     3         this.$options=options;
     4         this.$data=options.data;
     5         this.observe(this.$data);
     6         //模拟一下watcher创建
     7         new Watcher();
     8         this.$data.test;
     9         new Watcher();
    10         this.$data.foo.bar;
    11     }
    12     observe(value){
    13         if(!value||typeof value !='object'){
    14             return;
    15         }
    16         Object.keys(value).forEach(key=>{
    17             this.defineReactive(value,key,value[key])
    18         })
    19     }
    20 
    21     defineReactive(obj,key,val){
    22         this.observe(val)
    23         const dep=new Dep()
    24         Object.defineProperty(obj,key,{
    25             get(){
    26                 Dep.target&&dep.addDep(Dep.target)
    27                 return val;
    28             },
    29             set(newVal){
    30                 if(newVal==val){
    31                     return;
    32                 }
    33                 val=newVal;
    34                 dep.notify();//通知所有的watcher进行更新
    35             }
    36         })
    37     }
    38 }
    39 
    40 class Dep{//订阅器
    41     constructor(){
    42         this.deps=[];//在deps中存放若干依赖,也就是watcher(订阅者).这个依赖其实就是属性值发生改变的属性
    43     
    44     }
    45     addDep(dep){//增加依赖
    46         this.deps.push(dep)
    47     }
    48     notify(){//通知所有的依赖(watcher)去做更新
    49         this.deps.forEach(dep=>dep.update())
    50     }
    51 }
    52 
    53 class Watcher{//订阅者其实就是用来做具体更新的那个对象
    54     constructor(){
    55         //将当前这个Watcher实例指定到Dep的静态属性target
    56         Dep.target=this;//这个target只有一个,当有第二个watcher出现时就会覆盖成第二个watcher
    57     }
    58     update(){
    59         console.log('属性更新了!!!')
    60     }
    61 }
  • 相关阅读:
    数据类型装换
    变量及数据类型
    27 网络通信协议 udp tcp
    26 socket简单操作
    26 socket简单操作
    14 内置函数 递归 二分法查找
    15 装饰器 开闭原则 代参装饰器 多个装饰器同一函数应用
    12 生成器和生成器函数以及各种推导式
    13 内置函数 匿名函数 eval,exec,compile
    10 函数进阶 动态传参 作用域和名称空间 函数的嵌套 全局变量
  • 原文地址:https://www.cnblogs.com/zx-fjs/p/13342061.html
Copyright © 2020-2023  润新知