首页 > 其他分享 >vue等框架的响应式原理(简化)

vue等框架的响应式原理(简化)

时间:2024-11-25 20:26:35浏览次数:2  
标签:showData1 vue const get data 响应 简化 func data1

初次发布于我的个人文档

本文简要介绍一下如何实现一个简化版的类vue的响应式。

1.假装不知道响应式

如果我们不知道vue等响应式框架,那么又该如何手动实现类似的功能呢?

先来看这么一个简单的页面

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <title>My Program</title>
  </head>
  <body>
    <h1 id="data1"></h1>
    <p id="data2"></p>
    <p id="data3"></p>
  </body>
</html>

现在,如果这里的三个data需要变动,与此同时我们还希望页面进行所谓的“重新渲染”即让页面也跟着数据的变动变化应该怎么做呢?

首先,要写js代码让这几个标签有内容对吗?

只需要封装这三个函数即可

      const showData1 = (data) => {
        document.getElementById("data1").innerHTML = data.data1;
      };
      const showData2 = (data) => {
        document.getElementById("data2").innerHTML = data.data2;
      };
      const showData3 = (data) => {
        document.getElementById("data3").innerHTML = data.data3;
      };

对于旧数据,只需要调用函数传入即可,例如

      const showData1 = (data) => {
        document.getElementById("data1").innerHTML = data.data1;
      };
      const showData2 = (data) => {
        document.getElementById("data2").innerHTML = data.data2;
      };
      const showData3 = (data) => {
        document.getElementById("data3").innerHTML = data.data3;
      };
      const data = {
        data1: "Hello World!",
        data2: "This is a paragraph.",
        data3: "This is another paragraph.",
      };
      showData1(data);
      showData2(data);
      showData3(data);

但是接下来如果要更改data1,你会发现页面并不会变化,除非你重新调用showData1。

例如,这段代码就实现了3秒后变化data1并使得页面发生变化。

      const showData1 = (data) => {
        document.getElementById("data1").innerHTML = data.data1;
      };
      const showData2 = (data) => {
        document.getElementById("data2").innerHTML = data.data2;
      };
      const showData3 = (data) => {
        document.getElementById("data3").innerHTML = data.data3;
      };
      const data = {
        data1: "Hello World!",
        data2: "This is a paragraph.",
        data3: "This is another paragraph.",
      };
      showData1(data);
      showData2(data);
      showData3(data);
      setTimeout(() => {
        data1 = "Welcome to my program.";
        showData1(data1);
      }, 3000);

2.针对特殊变量实现响应式

所以手动实现响应式的关键,就是在改变变量的时候再次调用showData函数。

然而每次都手动去调用肯定是很麻烦而且不优雅的。

很容易想到,只要重载对应变量的set方法就可以了。

      const showData1 = (data) => {
        document.getElementById("data1").innerHTML = data.data1;
      };
      const showData2 = (data) => {
        document.getElementById("data2").innerHTML = data.data2;
      };
      const showData3 = (data) => {
        document.getElementById("data3").innerHTML = data.data3;
      };
      const data = {
        _data1: "Hello World!", // 使用一个下划线前缀来存储data1实际的值
        data2: "This is a paragraph.",
        data3: "This is another paragraph.",
      };
      Object.defineProperty(data, "data1", {
        get: function () {
          return this._data1; // 使用存储的实际值
        },
        set: function (value) {
          this._data1 = value; // 更新存储的实际值
          showData1(value); // 调用showData1来更新页面上的内容
        },
      });
      showData1(data);
      showData2(data);
      showData3(data);
      setTimeout(() => {
        data.data1 = "Welcome to my program."; // 使用新设置的setter
      }, 3000);

这样就完成了对data1的封装。

类似地,可以自己手动完成对data2 data3的封装。

然而,这并不是什么好的选择,自己动手还是太累了。

3.尝试封装为一般化工具

所以我们要来尝试封装成一般化的工具!

我们来手写一个封装或者说观察函数,来观察这个对象,为这个对象的所有字段都重写get和set方法就可以了。

      function watch(obj) {
        for (const key in obj) {
          let innerValue = obj[key];
          Object.defineProperty(obj, key, {
            get: function () {
              return innerValue;
            },
            set: function (value) {
              innerValue = value;
            },
          });
        }
      }

也就是这样。

但是接下来你会发现,我们不知道应该调用哪些函数了。

不妨回过头想想,手动实现的时候你是怎么知道要调用showData1这个函数的。

我们为什么不把三个showData函数全部调用一遍呢?

是不是因为showData1这个函数使用了data1这个变量啊,或者说就是这个函数调用了data1的get方法。

所以,我们应该先重写get方法,记录哪个函数使用了get方法。

那我怎么知道是哪个函数正在使用get方法呢?

解决方案是,让这个函数使用get方法前手动在全局变量上记录自己,然后get函数访问全局变量获取信息。

原本我们的调用是

      showData1(data);

现在改为

      showData1(data);

接着,data1的get方法只需要访问全局变量window.__func就知道谁正在调用get方法了。

      function watch(obj) {
        for (const key in obj) {
          let innerValue = obj[key];
          let funcs = [];
          Object.defineProperty(obj, key, {
            get: function () {
              if (window.__func &&!funcs.includes(window.__func)) {
                funcs.push(window.__func);
              }
              return innerValue;
            },
            set: function (value) {
              innerValue = value;
            },
          });
        }
      }

这就实现了依赖收集。

然后呢,在有函数调用set方法的时候,只需要调用funcs里面的所有函数即可,也就是派发更新。

      function watch(obj) {
        for (const key in obj) {
          let innerValue = obj[key];
          let funcs = [];
          Object.defineProperty(obj, key, {
            get: function () {
              if (window.__func &&!funcs.includes(window.__func)) {
                funcs.push(window.__func);
              }
              return innerValue;
            },
            set: function (value) {
              for (let i = 0; i < funcs.length; i++) {
                funcs[i]();
              }
              innerValue = value;
            },
          });
        }
      }

4.设计代理

但是,每次在调用get方法前还要自己手动设置全局变量还是太麻烦。如何把这个过程也自动化呢?

其实我们就是想加强调用了属性get方法的函数的功能,而由于我们做的是通用组件又不好直接修改函数本身。

这时,可以建一个新的对象或者函数,由它代理,或者说替代我们访问旧的函数或对象。

例如

      function runFunc(func) {
        window.__func = func;
        func();
        window.__func = null;
      }

以后,用户想调用func就使用runFunc代理,由runFunc替用户访问func。现在只要用户用这个函数访问func并且设置了被watch的对象,那么就实现了响应式了。

标签:showData1,vue,const,get,data,响应,简化,func,data1
From: https://www.cnblogs.com/ColaBlack/p/18548475

相关文章

  • 《花100块做个摸鱼小网站! 》第十篇—响应式布局适配PC端和移动端
    ⭐️基础链接导航⭐️服务器→☁️阿里云活动地址看样例→......
  • VUE|学习笔记①
    目录npm创建失败问题解决安装所有依赖如何启动一个vue项目终止项目快捷键自己写一个App组件写一个简单效果vsCode设置自动保存Vue.jsdevtools检查工具最近开始学习一下vue,想要快速入手,也不知道应该看什么课程比较合适,这里我选择看b站上尚硅谷禹神的Vue3教程。这里......
  • VUE|学习笔记②(Vue3核心语法)
     目录OptionsAPI与CompositionAPIsetup概述setup的返回值setup与OptionsAPIsetup语法糖expor报错:应为声明或语句。ts(1128)ref创建:基本类型的响应式数据reactive创建:对象类型的响应式数据ref创建:对象类型的响应式数据ref对比reactivetoRefs与toRef computed......
  • vue+laravel使用微信Natvite支付
    Navite支付介绍Native支付是指商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模式。适用于PC网站、实体店单品或订单、媒体广告支付等场景1.先阅读微信支付接入前的准备文档文档连接:Native支付接入前准备2.php下载插件composerrequirewechatpay/we......
  • 使用 Vue 2 和 ECharts 构建 3D 柱状图
    使用Vue2和ECharts构建3D柱状图在现代前端开发中,Vue.js是一个非常流行的框架,它提供了强大的响应式数据绑定和组件化开发,使得前端开发更加灵活高效。而ECharts是一个开源的可视化图表库,具有强大的功能支持,能够轻松生成交互式和美观的数据可视化图表。结合Vue和......
  • Vue 单页应用(SPA)与多页应用(MPA)设计
    Vue单页应用(SPA)与多页应用(MPA)设计在前端开发中,Vue是一个非常受欢迎的框架,因其高效、灵活而被广泛使用。而在Vue项目中,我们经常会遇到单页应用(SPA)和多页应用(MPA)这两种设计模式。今天,我们就来聊聊这两者的区别、优缺点以及如何在Vue中实现它们。一、什么是单页应用(SP......
  • Vue3.0 实操学习笔记
    安装 node.js安装 https://nodejs.org/en安装后执行node-v查看是否有异常以及npm-v查看是否异常调整为淘宝镜像,cnpm-v查看是否异常npminstall-gcnpm--registry=https://registry.npm.taobao.orgVue安装以及安装脚手架 vue-V查看是否异常cnpmi-......
  • 推荐 vue 最好用非常强大表格组件 vxe-table,vue 哪个表格组件好用
    vxe-table是一个全功能vue表格库,非常强大的功能基本可以满足对表格对表格的一切需求。不管是普通列表,大数据列表。可编辑表格,数据校验、Excel单元格选择、复制粘贴等。。。官网:https://vxetable.cngitee安装npminstallvxe-pc-ui@4.3.5vxe-table@4.9.6//...import......
  • Vue Devtools的下载和安装
    1.下载下载地址:https://github.com/vuejs/vue-devtools/tree/v5.1.1 下载下来zip包。解压到指定文件夹 2.安装依赖在这个目录,执行npminstall命令进行依赖安装 3.修改配置打开解压目录vue-devtools-master下的shells/Chrome/manifest.json文件,将代码"persistent":fal......
  • (系列十二)Vue3+.Net8实现用户登录(超详细登录文档)
    说明  该文章是属于OverallAuth2.0系列文章,每周更新一篇该系列文章(从0到1完成系统开发)。   该系统文章,我会尽量说的非常详细,做到不管新手、老手都能看懂。   说明:OverallAuth2.0是一个简单、易懂、功能强大的权限+可视化流程管理系统。友情提醒:本篇文章是属于系......