vue响应式简单实现

最近在网上搜到部很棒的vue视频,尤大亲自讲解( 之前也看到过但是这次是有中文字幕版的 )虽然之前也有看过别的vue源码解析对着老师的demo敲代码但是还是一知半解( 还是自己太菜了/(ㄒoㄒ)/~~ ),不过这次再看遍尤大的讲解理解又更深了一点,所以突发奇想要不写篇博客吧,就这样我的第一篇博客诞生了( 主要是觉得简历上贴个个人博客 github地址应该会加分吧O(∩_∩)O ),这次跟着视频实现了vue响应式的mini版,源码一下子接受不了我们就从简单的实现开始吧(●'◡'●)

首先vue的响应式主要是在Observer dep watch这几个类中实现得。这次先不管watch,先实现数据的响应式和依赖收集发布跟新。

大概思路: 先创建obersver函数内部使用 defineProperty 进行数据的拦截,再创建 Dep 类里面有两个方法 depend 和 notify,depend用来收集依赖,notify用来发布跟新

obersver中主要用到了defineProperty的get set两个方法,当访问对象属性的时候就会触发get函数,get函数中返回的数据就是你访问属性得到的数据。改变值得时候就会触发set函数,set函数接受一个参数即被赋予的新值。但是如果是后期手动在对象中添加属性就不会被 defineProperty 拦截所以vue中动态添加属性要用vue.$set()。下面代码中可以看出bar是手动添加的字面量属性当我访问它的时候并没有被监听到

1let obj = { 2 foo: 'hahah', 3 name: 'zs', 4 age: 20, 5}; 6 7Object.defineProperty( data, 'foo', { 8 get(){ 9 console.log('我被访问了'); 10 return 'hahah' 11 }, 12 set( newVal ){ 13 console.log('我被改变了', newVal); 14 } 15 } ) 16}

image

现在来实现Dep类,首先声明了autorun函数内部传入跟新的回调函数在回调中使用depend绑定依赖关系然后声明全局变量 activeUpdate 储存当前正在运行的函数,Dep中声明depend函数订阅当前正在运行的函数,notify中遍历 subscribes 触发所有跟新的方法,可以在autorun做点事情,当对象属性被改变的时候就会触发autorun中的函数

1window.Dep = class Dep{ 2 constructor(){ 3 this.subscribes = new Set() 4 } 5 6 depend(){ 7 if( activeUpdate ){ 8 this.subscribes.add( activeUpdate ) 9 } 10 } 11 12 notify(){ 13 this.subscribes.forEach( v => v() ); 14 } 15} 16 17let activeUpdate; 18 19function autorun( update ){ 20 function wrappUpdate(){ 21 activeUpdate = wrappUpdate 22 update() 23 activeUpdate = null 24 } 25 wrappUpdate() 26} 27 28let dep = new Dep() 29 30autorun( () => { 31 dep.depend() 32 console.log('update'); 33 } ) 34 35dep.notify()

最后我们可以结合上面两部分实现mini版的响应式,先把state中的数据绑定到模板上。然后封装Obersver方法,既然 defineproperty 只能监听单个属性那就只能用遍历的方法对所有属性进行监听,然后在get函数中收集依赖,set函数中发布跟新。当点击按钮时name就会被改变p元素中的内容也会发生变化

1<p></p> 2<button>点击改变</button>
1let state = { 2 name: 'zs', 3 age: 20 4} 5window.Dep = class Dep{ 6 constructor(){ 7 this.subscribe = new Set() 8 } 9 10 depend(){ 11 if( actvieUpdate ){ 12 this.subscribe.add( actvieUpdate ) 13 } 14 } 15 16 notify(){ 17 this.subscribe.forEach( v => v() ) 18 } 19} 20 21let actvieUpdate; 22 23function obersver( data ){ 24 let dep = new Dep() 25 Object.keys( data ).forEach( v => { 26 let realVal = data[ v ] 27 Object.defineProperty( data, v, { 28 get(){ 29 //收集依赖 30 console.log('属性被访问了'); 31 dep.depend() 32 return realVal 33 }, 34 set( newVal ){ 35 console.log('属性被设置了', newVal); 36 realVal = newVal 37 //发布跟新 38 dep.notify() 39 } 40 } ) 41 } ) 42} 43 44function autorun( update ){ 45 function wraapUpdate(){ 46 actvieUpdate = wraapUpdate 47 update() 48 actvieUpdate = null 49 } 50 wraapUpdate() 51} 52 53obersver( state ) 54 55let p = document.querySelector('p') 56render() 57let button = document.querySelector('button') 58button.onclick = () => { 59 state.name = 'ls' 60} 61function render(){ 62 p.innerText = state.name 63} 64 65autorun( render )

image image

视频地址: https://www.bilibili.com/video/BV1d4411v7UX?p=4&t=545

( 个人理解,如有不对,欢迎指正 😊 )

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

KVM调整cpu和内存

一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid