IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue2和vue3响应式原理 -> 正文阅读

[JavaScript知识库]vue2和vue3响应式原理

vue2和vue3响应式原理


一、问题分析?

1.如何实现数据变了,视图也跟着变?核心是:如何知道对象的属性值被修改了?
2.如何实现一个数据变量,多出视图跟着变?
3.如何保证视图改变,数据也跟这改变?
这个问题也是最简单的,我们只需要给表单监听input事件,通过e.tatget.value实时获取表单值,设置给对象中对应的属性

二、Object.defineProperty

使用方法:

var obj = {a:1,b:2}
Object.defineProperty(obj,"a",{
	相关配置项.....
})

6个配置项(4个酱油,2个重要)

value:设置属性的值
writable:如果是false,则代表属性值不让修改
configurable:如果是false,后续不能再次通过Object.defineProperty()配置,也不能通过delete删除该属性
enumerable:是否可以枚举,
get:拦截获取对象属性的动作
set:拦截设置对象属性值的动作

三、实现一个简单的响应式代码

   const obj = {a:1,b:2}
	const newObj = {}
    function observe(){
        Object.keys(obj).forEach(key=>{
            Object.definePropertery(newOjb,key,{
                get(){
                    return obj[key]
                },
                // 通过set获取数据的变化
                set(val){
                    obj[key]=val
                    // 修改值后可以做相关dom数据的更新
                }
            })
        })
    }
	observe(obj)

通过上述的案例明白了问题分析中的第一个问题,要想明白第二个问题,就需要知道什么是观察者模式

四、观察者模式

概念:观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个目标对象,当这个目标对象的状态发生变化时,会通知所有的观察者

// 观察者构造函数
function EventCenter(){
    this.guanjia = {
        
    }
}

// 添加观察者
EventCenter.Prototype.$on(EventName,cb){
    // 如果存在 就往数组中添加一个观察者函数
    if(this.guanjia.EventName){
        this.guanjia.EventName.push(cb)
    }else{
        // 不存在就初始化一个数组,并存放
        this.guanjia.EventName=[cb]
    }
}

// 用来发布事件发
EventCenter.Prototype.$emit(EventName){
    // 如果存在 就依次执行数组中全部的监听者函数
    if(this.guanjia.EventName){
        this.guanjia.EventName.forEach(fn=>fn())
    }
    // 不存在就不做响应
}

总结:问题分析中的第二个问题迎刃而解

解决了上述全部问题,那么下面实现一个vue(乞丐版)

五、实现一个简易的vue

模仿vue实现一个简单的mvvm,做到数据改变能影响视图,视图变化数据也会改变

案例HTML结构模板如下:

  <div id="app">
    <h2 v-html="salary"></h2>
    <input type="text" v-model="salary">
    <p v-html="salary"></p>
    <div v-html="bonus"></div>
  </div>

JS实现代码分两个部分,一个是观察者一个是mvvm,代码分别如下:

  1. 观察者从第四点中的代码复用
  2. 实现一个MVVM如下
// 首先导入上述观察者模式的代码
function MVVM(options){
    const {data,el}=options
    // 实例化一个观察者对象
    const ec = new EventCenter()
    Object.keys(data).forEach(key=>{
        Object.defineProperty(this,key,{
            set(val){
                console.log(`有人设置了${key}属性,值为${val}`)
                data[key]=val
                // 数据一旦改变,就发布key属性值改变的事件
                ec.$emit(key,val)
            },
            get(){
                console.log(`有人读取了${key}属性`)
                return data[key]
            }
        })
    })
    
    // 获取传入el对应的节点元素
    const rootNode = document.querySelector(el)
    // 将伪数组转化真实数组进行遍历
   	Array.from(rootNode.children).forEach(node=>{
        // 判断每个节点有没有v-html属性
        if(node.hasAttribute("v-html")){
            // 有就给节点初始值,首先获取v-html属性对应的属性值
           let key = node.getAttribute("v-html")
           // 初始化节点数据
           node.innerHTML= this[key] 
           // 添加对key属性变化的观察者, 
           ec.$on(key,()=>{
              node.innerHTML= this[key] 
           })
        }else if(node.hasAttribute("v-model")){
            // 1.显示初始值
            let key = node.getAttribute("v-model")
            node.value =  this[key]
            // 2.数据改变,页面也要更改
            ec.$on(key,()=>{
              node.innerHTML= this[key] 
            })
            // 3.用户设置,数据更者改变    
            // 实现步骤如下:监听表单的input事件,通过事件对象获取value属性,然后设置value值
            node.addEventListener("input",(e)=>{
               	this[key] = e.target.value  // 然后就会被set监听到,最终实现数据的双向绑定
            }) 
    	}
    }) 
}

new MVVM({
    el:"#app",
    data:{
        salary:20000,
        bonus:1000
    }
})

六、vue3实现响应式

vue3通过ES6新增的Proxy来实现响应式

var obj = {a:1,b:2}

var newObj = new Proxy(obj,{
   	// set的三个参数分别是:target:代理对象 props:设置的属性名 value:设置的属性值
    set(target,prop,value){
       target[prop]=value
    },
    // get的两个参数分别是:target:代理对象 props:设置的属性名 
    get(target,prop){
        return  target[prop]
    }
})

七、vue2和vue3实现响应式的区别

1.效率更高一些
Proxy可以处理一类动作
Object.defineProperty只能处理某个具体属性名,而且需要通过循环遍历属性
2. 能直接监控数组的操作
vue2.0其实不能直接监控数组的操作

  • 数组长度的变化不会直接去更新页面,(数组和对象不一样)
  • 通过数组小编修改数组元素,页面也不会更新

vue2.0动态添加属性的时候也不是响应式的

  • 因为在数据初始化阶段,vue才会对每一个属性进行Object.defineProperty拦截,后续添加的属性,vue根本拦截不到

八、浅淡vue2为什么不能直接监控数组的操作

为什么尤大大不监控数组的操作?
因为Object.defineProperty要监听到对象的具体属性,数组的属性又是一堆索引,并没有什么语义化,而且可能数

组的长度非常大,就极容易导致性能过低.所以尤大大没用使用Object.defineProperty来监听数组的操作

而是尤大大通过拦截了数组的7个方法(官网有写哪7个),用户只有调用这7个方法时候,vue2才能感知数组的变化,

才能更新视图

拦截的7个数组方法:
push,pop,shifr,unshift,reserve,splice,sort

九、自我总结

vue2在初始化的时候,遍历所有的数据属性,然后通过Object.defineproperty进行数据劫持,在渲染模板的时候,在结和观察者模式,对属性的改变进行监听函数,并且加入到一个数组里面,当某一个属性发现改变时候,就会被set拦截,在set函数中发布属性的改变,这样对这个属性用到的地方都会执行页面的更新

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-23 15:40:27  更:2021-12-23 15:41:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:44:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码