首页 > 语言 > JavaScript > 正文

这应该是最详细的响应式系统讲解了

2024-05-06 15:36:44
字体:
来源:转载
供稿:网友

前言

本文从一个简单的双向绑定开始,逐步升级到由defineProperty和Proxy分别实现的响应式系统,注重入手思路,抓住关键细节,希望能对你有所帮助。

一、极简双向绑定

首先从最简单的双向绑定入手:

// html<input type="text" id="input"><span id="span"></span>
// jslet input = document.getElementById('input')let span = document.getElementById('span')input.addEventListener('keyup', function(e) { span.innerHTML = e.target.value})

以上似乎运行起来也没毛病,但我们要的是数据驱动,而不是直接操作dom:

// 操作obj数据来驱动更新let obj = {}let input = document.getElementById('input')let span = document.getElementById('span')Object.defineProperty(obj, 'text', { configurable: true, enumerable: true, get() {  console.log('获取数据了')  return obj.text }, set(newVal) {  console.log('数据更新了')  input.value = newVal  span.innerHTML = newVal }})input.addEventListener('keyup', function(e) { obj.text = e.target.value})

以上就是一个简单的双向数据绑定,但显然是不足的,下面继续升级。

二、以defineProperty实现响应系统

在Vue3版本来临前以defineProperty实现的数据响应,基于发布订阅模式,其主要包含三部分:Observer、Dep、Watcher。

1. 一个思路例子

// 需要劫持的数据let data = { a: 1, b: {  c: 3 }}// 劫持数据dataobserver(data)// 监听订阅数据data的属性new Watch('a', () => {  alert(1)})new Watch('a', () => {  alert(2)})new Watch('b.c', () => {  alert(3)})

以上就是一个简单的劫持和监听流程,那对应的observer和Watch该如何实现?

2. Observer

observer的作用就是劫持数据,将数据属性转换为访问器属性,理一下实现思路:

①Observer需要将数据转化为响应式的,那它就应该是一个函数(类),能接收参数。
②为了将数据变成响应式,那需要使用Object.defineProperty。
③数据不止一种类型,这就需要递归遍历来判断。

// 定义一个类供传入监听数据class Observer { constructor(data) {  let keys = Object.keys(data)  for (let i = 0; i < keys.length; i++) {   defineReactive(data, keys[i], data[keys[i]])  } }}// 使用Object.definePropertyfunction defineReactive (data, key, val) { // 每次设置访问器前都先验证值是否为对象,实现递归每个属性 observer(val) // 劫持数据属性 Object.defineProperty(data, key, {  configurable: true,  enumerable: true,  get () {   return val  },  set (newVal) {   if (newVal === val) {    return   } else {    data[key] = newVal    // 新值也要劫持    observer(newVal)   }  } })}// 递归判断function observer (data) { if (Object.prototype.toString.call(data) === '[object, Object]') {  new Observer(data) } else {  return }}// 监听objobserver(data)            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选