computed set 自定义参数_完全理解Vue的渲染watcher、computed和user watcher

本文深入探讨Vue的渲染过程、数据响应式、computed和watch的实现原理,通过逐步构建核心功能,解释如何实现数据的响应式、初始渲染、依赖收集与更新,以及computed和watch的工作方式,帮助读者全面理解Vue的内部机制。
摘要由CSDN通过智能技术生成
6df7e24581cc400af60c13709176680f.png

作者:Naice

https://segmentfault.com/a/1190000023196603

这篇文章将带大家全面理解vuewatchercomputeduser watcher,其实computeduser watcher都是基于Watcher来实现的,我们通过一个一个功能点去敲代码,让大家全面理解其中的实现原理和核心思想。所以这篇文章将实现以下这些功能点:

  • 实现数据响应式
  • 基于渲染wather实现首次数据渲染到界面上
  • 数据依赖收集和更新
  • 实现数据更新触发渲染watcher执行,从而更新ui界面
  • 基于watcher实现computed
  • 基于watcher实现user watcher

废话不要多说,先看下面的最终例子。

c4f246fe3aef7100477a486acfadd926.gif

例子看完之后我们就直接开工了。

准备工作

首先我们准备了一个index.html文件和一个vue.js文件,先看看index.html的代码

html>
"en">

  "UTF-8">
  全面理解vue的渲染watcher、computed和user atcher


  
"root">

  
  


index.html里面分别有一个id是root的div节点,这是跟节点,然后在script标签里面,引入了vue.js,里面提供了Vue构造函数,然后就是实例化Vue,参数是一个对象,对象里面分别有data 和 render 函数。然后我们看看vue.js的代码:

function Vue (options) {
    
  this._init(options) // 初始化
  this.$mount() // 执行render函数
}
Vue.prototype._init = function (options) {
  const vm = this
  vm.$options = options // 把options挂载到this上
  if (options.data) {
    initState(vm) // 数据响应式
  }
  if (options.computed) {
    initComputed(vm) // 初始化计算属性
  }
  if (options.watch) {
    initWatch(vm) // 初始化watch
  }
}

vue.js代码里面就是执行this._init()this.$mount()this._init的方法就是对我们的传进来的配置进行各种初始化,包括数据初始化initState(vm)、计算属性初始化initComputed(vm)、自定义watch初始化initWatch(vm)this.$mount方法把render函数渲染到页面中去、这些方法我们后面都写到,先让让大家了解整个代码结构。下面我们正式去填满我们上面写的这些方法。

实现数据响应式

要实现这些watcher首先去实现数据响应式,也就是要实现上面的initState(vm)这个函数。相信大家都很熟悉响应式这些代码,下面我直接贴上来。

function initState(vm) {
    
  let data = vm.$options.data; // 拿到配置的data属性值
  // 判断data 是函数还是别的类型
  data = vm._data = typeof data === 'function' ? data.call(vm, vm) : data || {};
  const keys = Object.keys(data);
  let i = keys.length;
  while(i--) {
    // 从this上读取的数据全部拦截到this._data到里面读取
    // 例如 this.name 等同于  this._data.name
    proxy(vm, '_data', keys[i]);
  }
  observe(data); // 数据观察
}

// 数据观察函数
function observe(data) {
  if (typeof data !== 'object' && data != null) {
    return;
  }
  return new Observer(data)
}

// 从this上读取的数据全部拦截到this._data到里面读取
// 例如 this.name 等同于  this._data.name
function proxy(vm, source, key) {
  Object.defineProperty(vm, key, {
    get() {
      return vm[source][key] // this.name 等同于  this._data.name
    },
    set(newValue) {
      return vm[source][key] = newValue
    }
  })
}

class Observer{
  constructor(value) {
    this.walk(value) // 给每一个属性都设置get set
  }
  walk(data) {
    let keys = Object.keys(data);
    for (let i = 0, len = keys.length; i       let key = keys[i]
      let value = data[key]
      defineReactive(data, key, value) // 给对象设置get set
    }
  }
}

function defineReactive(data, key, value) {
  Object.defineProperty(data, key, {
    get() {
      return value
    },
    set(newValue) {
      if (newValue == value) return
      observe(newValue) // 给新的值设置响应式
      value = newValue
    }
  })
  observe(value); // 递归给数据设置get set
}

重要的点都在注释里面,主要核心就是给递归给data里面的数据设置getset,然后设置数据代理,让 this.name 等同于 this._data.name。设置完数据观察,我们就可以看到如下图的数据了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值