最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 浅谈Vue响应式原理

    正文概述 掘金(芋圆1392)   2020-12-29   461

    Vue.js 的核心包括一套“响应式系统”。

    “响应式”,是指当数据改变后,Vue 会通知到使用该数据的代码。例如,视图渲染中使用了数据,数据改变后,视图也会自动更新。

    对于官网上关于响应式数据的描述,并不能让人短时间内明白其原理。下面我将按照我的理解分析一下Vue2.0响应式核心代码实现。

    Vue中响应式数据分为:对象类型{}和数组类型[]

    对象类型 {}

    我们若想要实现响应式,需要以下类和方法:

    • 数据data
    • 数据监听器defineReactive
    • 订阅者(更新视图)watcher
    • 维护订阅者dep
    • 状态active

    实现原理: 对象内部通过defineReactive方法,使用Object.defineProperty将属性进行劫持(只会劫持已经存在的属性)。

    假设页面上有容器appdata存放响应式变量,当data中的值改变时,容器内的数值也会发生变化。

        <div id="app"></div>
        
        <script>
            let data = {
                count:0
            }
            app.innerHTML = data.count
        </script>
    

    1.添加视图更新watcher

        <div id="app"></div>
        <script>
            let data = {
                count:0
            }
            // 定义watcher函数,传入参数为函数,且立即执行
            let watcher = (fn)=>{
                fn();
            }
    
            watcher(()=>{
                // 更换app内容
                app.innerHTML = data.count;
            })
        </script>
    

    watcher所执行的操作 将页面上的内容更新=>视图更新

    2.实现数据监听器

    将data中的属性依次增加get()set()方法,这样当用户取值的时候,当作模版收集起来。待数据变化通知模版数据更新。

        <script>
            let data = {
                count:0
            }
            // 数据监听器
            function defineReactive(obj) {
                //每一个属性都重新定义get、set
                for(let key in obj){
                	let value = obj[key]
                    Object.defineProperty(obj,key,{
                        // 当data中的值“出现”的时候,执行get()
                        get(){
                        	//将获取的原始值返回
                            return value;
                        },
                         // 当data中的值“改变”的时候,执行get()
                        set(newValue){
                            value = newValue
                        }
                    })
                }
            }
            //劫持data中的数据
            defineReactive(data)
    
            //此时的a没有被数据监听器监测到,属于“后来者”不受劫持
            data.a = 10;
    
            // 定义watcher函数,传入参数为函数,且立即执行
            let watcher = (fn)=>{
                fn();
            }
    
            watcher(()=>{
                // 取值
                app.innerHTML = data.count;
            })
        </script>
    

    3. 当数据改变时更新视图

       <div id="app"></div>
       <script>
           let data = {
               count:0
           }
           //需要执行的视图内容
           let active;
           // 数据监听器
           function defineReactive(obj) {
               for(let key in obj){
                   let value = obj[key];
                   //存放当前属性相关的所有方法
                   let dep = [];
                   Object.defineProperty(obj,key,{
                       // 当data中的值“出现”的时候,执行get()
                       get(){
                           //(3)
                           if(active){
                               dep.push(active)
                           }
                           return value
                       },
                        // 当data中的值“改变”的时候,执行get()
                       set(newValue){
                           value = newValue
                           dep.forEach(active=>active())
                       }
                   })
               }
           }
           //劫持data中的数据
           defineReactive(data)
    
    
           // 定义watcher函数,传入参数为函数,且立即执行
           let watcher = (fn)=>{
               active = fn;
               //(1)
               fn();
               //(4)
               active = null;
           }
    
           watcher(()=>{
               // 更换app内容
               //(2)
               app.innerHTML = data.count;
           })
       </script>
    

    浅谈Vue响应式原理

    当定义watcher时,会依次执行(1)=>(2)=>(3)=>(4)。 每个属性都拥有自己的dep属性,存放它所存放的watcher,当属性变化后会同志自己对应的watcher去更新。

    Vue2.0响应式用的是Object.defineProperty Vue3.0响应式用的是proxy

    data中的数据存在多层嵌套的时候,如果用Object.defineProperty,内部会进行递归,影响性能。proxy提升性能,但是不兼容ie11。

    数组类型 []

    数组考虑性能原因没有用defineProperty对数组的每一项进行拦截,而是选择对数组原型上的方法进行重写(push,pop,shift,unshift,splice,sort,reverse)只有这7种方法会重写数组

        <div id="app"></div>
        <script>
            let data = [1,2,3];
            // 获取数组所有方法-原型链
            let originArray = Array.prototype;
            // 浅拷贝
            let arrayMethods = Object.create(originArray);
            // 数据监听器
            function defineReactive(obj) {
                // 函数劫持,重写方法。可以添加自己想要执行的内容
                arrayMethods.push = function (...args) {
                    // 更改this指向
                    originArray.push.call(this,...args);
                    render();
                }
                // 挂载到原型上
                obj.__proto__ = arrayMethods
            }
            defineReactive(data)
    
            // 视图渲染
            function render() {
                app.innerHTML = data;
            }
            render();
           
        </script>
    

    浅谈Vue响应式原理

    在Vue中修改数组的索引和长度是无法监控到的。需要通过以上7种变异方法修改数组才会触发数组对应的watcher进行更新。数组中如果是对象类型也会进行递归劫持。

    如果想要更改索引,可以通过Vue.$set来进行处理,内部核心代码是splice方法


    起源地下载网 » 浅谈Vue响应式原理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元