简单的响应式demo

Vue 最标志性的功能就是其低侵入性的响应式系统。组件状态都是由响应式的 JavaScript 对象组成的。当更改它们时,视图会随即自动更新。------出自vue《深入响应式系统》第一段

正文

对于熟悉或稍有了解Vue的开发者来说,响应式机制早已深入人心,其核心理念在于当数据发生变化时,能够自动更新与之相关的页面元素。

最近,在抖音上频繁地看到某前端培训机构的视频,我好奇地点击进去,并认真观看了他们的公开课。在最后的视频中有介绍到响应式,我茅塞顿开,决定记录下这些知识点并与大家分享。

在传统的HTML和JavaScript开发中,我们经常遇到一个问题:当我们通过变量和函数将数据渲染到页面上后,一旦变量值发生变化,就需要重新执行函数来更新页面。这种手动触发更新的方式既繁琐又容易出错。那么,是否有一种方法能够自动在变量值变化时调用相关的函数,从而实现页面的自动更新呢?

答案是肯定的,这就涉及到了JavaScript中的一个内置方法Object.defineProperty。

该方法用于直接在一个对象上定义新属性,或者修改一个对象的现有属性。同时提供了对数据属性的更底层访问以及定义 getter 和 setter 的能力,利用这一能力,我们可以监听对象属性的变化,并在属性值发生变化时自动执行相应的函数,从而实现页面的自动更新。

语法

js 复制代码
Object.defineProperty(obj, propertyName, descriptor)
  • obj:要定义属性的对象。

  • propertyName:要定义或修改的属性的名称或 Symbol。

  • descriptor:这个属性的描述符。必须是一个对象,可以具有以下属性:

    • value :属性的值,默认为 undefined。
    • writable :如果为 true,属性的值可以被重写。默认为 false。
    • enumerable :如果为 true,则属性会被枚举(例如,通过 for...in 循环或 Object.keys())。默认为 false。
    • configurable :如果为 true,属性可以被删除或修改。默认为 false。
    • get:一个函数,作为 getter,当访问此属性时会被调用。
    • set:一个函数,作为 setter,当修改此属性时会被调用。

demo代码

在HTML文件中,我们可以定义一个输入框(<input />元素)来接收用户输入的文本。然后将第一个字符显示在#firstName中,将其余字符串显示在#lastName中。

html 复制代码
<div id="app">
  <div>
    姓名:<input id="name" />
  </div>
  <p id="firstName"></p>
  <p id="lastName"></p>
</div>
js 复制代码
// 将对象变为响应式
function reactive(obj) {
  const newObj = {
    ...obj,
  }
  for (const key in newObj) {
    let internalValue = newObj[key];
    const funcSet = new Set();
    Object.defineProperty(newObj, key, {
      get: function () {
        // 依赖收集,记录:是哪个函数在用该属性
        if (window.__func) {
          funcSet.add(window.__func);
        }
        return internalValue;
      },
      set: function (val) {
        internalValue = val;
        // 派发更新,运行:执行用该属性的函数
        funcSet.forEach(func => {
          func();
        })
      },
    });
  }
  return newObj;
}

// 准备方法
function autorun(fn) {
  window.__func = fn;
  fn();
  window.__func = null;
}

const info = reactive({
  name: '',
})

// 显示姓氏
function showFirstName() {
  document.querySelector('#firstName').textContent = '姓:' + (info.name[0] ?? '');
}

// 显示名字
function showLastName() {
  document.querySelector('#lastName').textContent = '名:' + info.name.slice(1);
}

autorun(showFirstName);
autorun(showLastName);

document.querySelector('#name').addEventListener('input', e => {
  info.name = e.target.value
})

在深入探讨响应式机制时,我们可以看到,addEventListener 并没有直接用于重新执行渲染方法(如 showFirstName、showLastName)。相反,当对象属性被访问(get)时,与之相关的函数会被收集起来。随后,当这些属性发生更新(set)时,先前收集的函数将依次被执行,从而实现数据的自动响应和页面的动态更新。

虽然此示例代码在功能性和完整性上还有待加强,但作为展示响应式原理的入门案例,它已经足够直观和易懂。

因此,我们可以对响应式机制做出如下简洁而明确的定义:响应式是一种编程范式,它使得数据变化时能够自动触发并执行与之相关的函数,从而保持应用程序的实时性和动态性。

相关推荐
A黄俊辉A3 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
honkun63 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19913 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
雪芽蓝域zzs3 天前
第26章:ECharts 自定义主题 + 页面一键切换主题(深色 / 浅色两套)
vue.js·echars
雪芽蓝域zzs3 天前
第22章:ECharts 图表联动(多图表交互联动)
vue.js·echars
daols883 天前
vue 表格组件 vxe-table 实现虚拟滚动与无需滚动加载
vue.js·vxe-table
雪芽蓝域zzs3 天前
第18章:ECharts 折线图 + 标记点、标记线,自定义 tooltip
vue.js·echars
雪芽蓝域zzs3 天前
第24章:ECharts 地图组件(基础行政区地图,若依 Vue3)
vue.js·echars
计算机毕设定制辅导-无忧学长3 天前
《基于Vue的流浪动物救助中心管理系统的设计与实现》
java·vue.js·spring boot·流浪动物救助中心管理系统
雪芽蓝域zzs3 天前
第25章:地图下钻交互(点击省份,切换到对应省份城市地图)
vue.js·echars