zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    SpringCloud微服务初步认识
    SpringCloud-Hystrix:服务熔断与降级
    List接口下重要集合源码分析
    高频面试题:手写一个LRU
    Java基础面试题面经整理(持续更新)
    Redis高可用之主从复制
    Redis过期键删除和内存淘汰
    Redis持久化(RDB与AOF)
    了解Redis事务
    Redis入门与安装
  • 原文地址:https://www.cnblogs.com/zx-fjs/p/13342061.html
Copyright © 2011-2022 走看看