vue响应式简单实现

代码练习生
• 阅读 1680

最近在网上搜到部很棒的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是手动添加的字面量属性当我访问它的时候并没有被监听到

let obj = {
      foo: 'hahah',
      name: 'zs',
      age: 20,
};

Object.defineProperty( data, 'foo', {
          get(){
            console.log('我被访问了');
            return 'hahah'
          },
          set( newVal ){
            console.log('我被改变了', newVal);
          }
        } )
}

vue响应式简单实现

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

window.Dep = class Dep{
      constructor(){
        this.subscribes = new Set()
      }

      depend(){
        if( activeUpdate ){
          this.subscribes.add( activeUpdate )
        }
      }

      notify(){
        this.subscribes.forEach( v => v() );
      }
}

let activeUpdate;

function autorun( update ){
      function wrappUpdate(){
        activeUpdate = wrappUpdate
        update()
        activeUpdate = null
      }
      wrappUpdate()
}

let dep = new Dep()

autorun( () => {
      dep.depend()
      console.log('update');
 } )

dep.notify()

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

<p></p>
<button>点击改变</button>
let state = {
      name: 'zs',
      age: 20
}
window.Dep = class Dep{
      constructor(){
        this.subscribe = new Set()
      }

      depend(){
        if( actvieUpdate ){
          this.subscribe.add( actvieUpdate )
        }
      }

      notify(){
        this.subscribe.forEach( v => v() )
      }
}

let actvieUpdate;

function obersver( data ){
      let dep = new Dep()
      Object.keys( data ).forEach( v => {
      let realVal = data[ v ]
      Object.defineProperty( data, v, {
          get(){
            //收集依赖
            console.log('属性被访问了');
            dep.depend()
            return realVal
          },
          set( newVal ){
            console.log('属性被设置了', newVal);
            realVal = newVal
            //发布跟新
            dep.notify()
          }
        } )
      } )
}

function autorun( update ){
  function wraapUpdate(){
    actvieUpdate = wraapUpdate
    update()
    actvieUpdate = null
   }
   wraapUpdate()
}

obersver( state )

let p = document.querySelector('p')
render()
let button = document.querySelector('button')
button.onclick = () => {
  state.name = 'ls'
}
function render(){
  p.innerText = state.name
}

autorun( render )

vue响应式简单实现 vue响应式简单实现

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

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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
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
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Karen110 Karen110
3年前
​一篇文章总结一下Python库中关于时间的常见操作
前言本次来总结一下关于Python时间的相关操作,有一个有趣的问题。如果你的业务用不到时间相关的操作,你的业务基本上会一直用不到。但是如果你的业务一旦用到了时间操作,你就会发现,淦,到处都是时间操作。。。所以思来想去,还是总结一下吧,本次会采用类型注解方式。time包importtime时间戳从1970年1月1日00:00:00标准时区诞生到现在
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
代码练习生
代码练习生
Lv1
男 · 前端开发
修炼摸鱼之道
文章
1
粉丝
2
获赞
7
热门文章

暂无数据