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>

 

相关实践学习
Github实时数据分析与可视化
基于Github Archive公开数据集,将项目、行为等20+种事件类型数据实时采集至Hologres进行分析,并搭建可视化大屏。
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
相关文章
|
5天前
|
JavaScript
vue消息订阅与发布
vue消息订阅与发布
|
2天前
|
JavaScript
理解 Vue 的 setup 应用程序钩子
【10月更文挑战第3天】`setup` 函数是 Vue 3 中的新组件选项,在组件创建前调用,作为初始化逻辑的入口。它接收 `props` 和 `context` 两个参数,内部定义的变量和函数需通过 `return` 暴露给模板。`props` 包含父组件传入的属性,`context` 包含组件上下文信息。`setup` 可替代 `beforeCreate` 和 `created` 钩子,并提供类似 `data`、`computed` 和 `methods` 的功能,支持逻辑复用和 TypeScript 类型定义。
20 11
|
4天前
|
JavaScript
vue尚品汇商城项目-day07【vue插件-50.(了解)表单校验插件】
vue尚品汇商城项目-day07【vue插件-50.(了解)表单校验插件】
13 4
|
4天前
|
JavaScript
vue尚品汇商城项目-day07【51.路由懒加载】
vue尚品汇商城项目-day07【51.路由懒加载】
15 4
|
4天前
|
JavaScript
vue尚品汇商城项目-day07【vue插件-54.(了解)生成二维码插件】
vue尚品汇商城项目-day07【vue插件-54.(了解)生成二维码插件】
14 2
|
JavaScript 测试技术 容器
Vue2+VueRouter2+webpack 构建项目
1). 安装Node环境和npm包管理工具 检测版本 node -v npm -v 图1.png 2). 安装vue-cli(vue脚手架) npm install -g vue-cli --registry=https://registry.
1039 0
|
7天前
|
JavaScript
vue组件中的插槽
本文介绍了Vue中组件的插槽使用,包括单个插槽和多个具名插槽的定义及在父组件中的使用方法,展示了如何通过插槽将父组件的内容插入到子组件的指定位置。
|
6天前
|
JavaScript 前端开发 IDE
Vue学习笔记5:用Vue的事件监听 实现数据更新的实时视图显示
Vue学习笔记5:用Vue的事件监听 实现数据更新的实时视图显示
|
6天前
|
JavaScript 前端开发 API
Vue学习笔记4:用reactive() 实现数据更新的实时视图显示
Vue学习笔记4:用reactive() 实现数据更新的实时视图显示
|
5天前
|
JavaScript 前端开发
Vue学习笔记8:解决Vue学习笔记7中用v-for指令渲染列表遇到两个问题
Vue学习笔记8:解决Vue学习笔记7中用v-for指令渲染列表遇到两个问题
下一篇
无影云桌面