Vue响应式原理详细讲解

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
数据可视化DataV,5个大屏 1个月
简介: Vue响应式原理详细讲解

面试官:请你简单的说说什么是Vue的响应式。


小明:mvvm就是视图模型模型视图,只有数据改变视图就会同时更新。


面试官:说的很好,回去等通知吧。


小明:....


Vue响应式原理


先看官方的说法


0ea6d5e0b3d14036ac6100da2e486d2b.png


简单理解就是实例data,Vue通过遍历data中所有对象通过Observer劫持监听所以属性,然后数据一旦发生变化,就通知编译解析变化,更新视图。


首先创建一个data,需要将data变成响应式数据,创建Observer 函数传值data,如果data不是一个对象或者是空就不用处理直接return

 <script>
        function Observer(targer){
            if(typeof targer !== 'object' || targer ===null){
                return targer
            }
        }
        const data = {
            name:'海海',
            age:18,
            info:{
                address:'广州'
            },
            fava:[1,2,3,4,5]
        }
        Observer(data)
    </script

其他的处理


这里只处理数组,其他


判断是否等于数组,如果等于,如果不等于就循环target,声明响应式函数 defineReactive


传值targer,循环的key和targer[key],然后在 defineReactive调用我们的 Object.defineProperty

 function Observer(targer){
            if(typeof targer !== 'object' || targer ===null){
                return targer
            }
            if(Array.isArray(targer)) {
                // 数组
            }else{
                for(let key in targer){
                    // 响应式数据的函数
                    defineReactive(targer,key,targer[key])
                }
            }
        }

Object.defineProperty


  (Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。)


传入我们的参数


拿到get set方法


get


初始值 直接return 我们的value


set


第一个参数是最新的值 newValue


判断如果我们传入的value和newValue不相等,那么就把newValue赋值给value

        function defineReactive(targer,key,value){
            Object.defineProperty(targer,key,{
                get(){
                    return value
                },
                set(newValue){
                    if(newValue !== value) {
                        value =newValue
                    }
                }
            })
        }

   

那么问题又来了,如果是一个对象需要监听,我们刚刚的操作只监听到了第一层,如果监听的内容是上面的info就相当于监听了整个对象,答案也很简单,我们只需要在调用defineReactive的时候在调用一次Observer在进入一次循环,当不是object就自动结束了

        function defineReactive(targer,key,value){
            Observer(value)
            Object.defineProperty(targer,key,{
                get(){
                    return value
                },
                set(newValue){
                    if(newValue !== value) {
                        value =newValue
                    }
                }
            })
        }

   

视图更新


我们这里在模仿一下视图更新 定义函数 updataView

        function updataView(){
            console.log('视图更新了')
        }

   

调用


727041968edf460ab1a40d03e03a6883.png


显示视图更新。


数组


先定义一个值 oldArrayProperty 然后将Array.prototype赋值给oldArrayProperty,


然后针对原型对象创建 Object.create()


定义一个 arrProto 来接收。


然后声明数组  ['push','pop','unshift','shift','reverse','sort','splice']  进行循环

   const oldArrayProperty =Array.prototype
   const arrProto = Object.create(oldArrayProperty)
   const fn = ['push','pop','unshift','shift','reverse','sort','splice']
        fn.forEach((method)=>{
            arrProto[method] = function(){
            } 
        })

然后调用更新视图 updataView  return 将oldArrayProperty对应的方法匹配上return出来

        const oldArrayProperty =Array.prototype
        const arrProto = Object.create(oldArrayProperty)
        const fn = ['push','pop','unshift','shift','reverse','sort','splice']
        fn.forEach((method)=>{
            arrProto[method] = function(){
                updataView()
                return oldArrayProperty[method].call(this,...arguments)
            } 
        })

 

然后回到Observer方法中,将arrProto赋值给 targer的__proto__原型链上,最后在将targer循环调用Observer,进行数据更新。

  if(Array.isArray(targer)) {
                // 数组
                targer.__proto__ =arrProto
                for(let i=0;i<targer.length;i++) {
                    Observer(targer[i])
                }
            }


测试


6a48386b5fc14b3aa6abd69ca6b503b8.png


到这里我们的监听数据变化并自动更新就完成了。


完整代码

    <script>
        function defineReactive(targer,key,value){
            Observer(value)
            Object.defineProperty(targer,key,{
                get(){
                    return value
                },
                set(newValue){
                    if(newValue !== value) {
                        value =newValue
                        updataView()
                    }
                }
            })
        }
        const oldArrayProperty =Array.prototype
        const arrProto = Object.create(oldArrayProperty)
        const fn = ['push','pop','unshift','shift','reverse','sort','splice']
        fn.forEach((method)=>{
            arrProto[method] = function(){
                updataView()
                return oldArrayProperty[method].call(this,...arguments)
            } 
        })
        function Observer(targer){
            if(typeof targer !== 'object' || targer ===null){
                return targer
            }
            if(Array.isArray(targer)) {
                // 数组
                targer.__proto__ =arrProto
                for(let i=0;i<targer.length;i++) {
                    Observer(targer[i])
                }
            }else{
                for(let key in targer){
                    // 响应式数据的函数
                    defineReactive(targer,key,targer[key])
                }
            }
        }
        function updataView(){
            console.log('视图更新了')
        }
        const data = {
            name:'海海',
            age:18,
            info:{
                address:'广州'
            },
            fava:[1,2,3,4,5]
        }
        Observer(data)
    </script>

 

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
相关文章
|
4天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
vue学习第四章
|
4天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
vue学习第九章(v-model)
|
4天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
vue学习第十章(组件开发)
|
9天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
9天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
6月前
|
JavaScript API
【vue实战项目】通用管理系统:api封装、404页
【vue实战项目】通用管理系统:api封装、404页
76 3
|
6月前
|
人工智能 JavaScript 前端开发
毕设项目-基于Springboot和Vue实现蛋糕商城系统(三)
毕设项目-基于Springboot和Vue实现蛋糕商城系统
|
6月前
|
JavaScript Java 关系型数据库
毕设项目-基于Springboot和Vue实现蛋糕商城系统(一)
毕设项目-基于Springboot和Vue实现蛋糕商城系统
175 0
|
6月前
|
JavaScript 前端开发 API
Vue3+Vite+TypeScript常用项目模块详解
现在无论gitee还是github,越来越多的前端开源项目采用Vue3+Vite+TypeScript+Pinia+Elementplus+axios+Sass(css预编译语言等),其中还有各种项目配置比如eslint 校验代码工具配置等等,而我们想要进行前端项目的二次开发,就必须了解会使用这些东西,所以作者写了这篇文章进行简单的介绍。
144 0
Vue3+Vite+TypeScript常用项目模块详解
|
6月前
|
设计模式 JavaScript
探索 Vue Mixin 的世界:如何轻松复用代码并提高项目性能(上)
探索 Vue Mixin 的世界:如何轻松复用代码并提高项目性能(上)
探索 Vue Mixin 的世界:如何轻松复用代码并提高项目性能(上)
下一篇
无影云桌面