首页 | 投资 | 产业 | 创投 | 保险 | 公司 | 企业 | 商业 | 消费 | 行情 | 经营 | 商品 | 基金 |
写几行代码,了解响应式原理-环球新资讯

发稿时间:2023-05-03 17:11:32 来源: 博客园
作者:袁首京

原创文章,转载时请保留此声明,并给出原文连接。


【资料图】

作为当下的开发人员,无论是不是前端,可能都会频繁的与 React、Vue、Svelte、Solidjs 等等打交道。也许你已经很清楚它们背后的运作原理,那不必往下看了。如果还不是很清楚,那咱们可以一起写几行代码,来瞅一眼这些响应式框架背后的思路。

响应式框架最根本的功能其实只有一条:当数据发生变化时,让界面随之发生变化

如何达成这一点呢?粗略的想一下就会觉得,首先要在数据和与之对应的 HTML 元素之间建立绑定关系。可以以某种方式给特定的 HTML 元素打个标记,然后当与此元素相关的值发生变更时,我们就能通过这个标记找到此元素,然后动态的改变它展示出来的值。

比如如下 HTML 模板片断:

{{ current_time }}

我们可以定义一个模板编译函数:

function compile(tpl) {  const re = /(\{\{\s+)(\w+)(\s+\}\})/m;  const mg = tpl.match(re);  return tpl.replace(">{{", " vid="" + mg[2] + "">{{").replace(mg[0], "");}

执行该函数,就会给相关元素打上 vid 标记:

> compile("

{{current_time}}

")

这样如果需要,我们就可以很方便的找到页面上需要响应的元素:

const vel = document.querySelector("[vid=current_time]");

接下来是数据部分。如何监测数据的变化呢?一种方案是使用代理。假如我们有如下数据对象:

{  current_time: "2023-05-03T05:14:46.176Z";}

可以使用如下函数,为其生成一个代理,拦截其赋值操作:

function reactive(data) {  return new Proxy(data, {    set(target, property, value) {      const prev = target[property];      target[property] = value;      if (prev !== value) {        const vel = document.querySelector(`[vid=${property}]`);        vel.innerHTML = value;      }      return true;    },  });}

接下来,就可以面向数据编程了:

const data = reactive({  current_time: "2023-05-03T05:14:46.176Z",});setInterval(() => {  data.current_time = new Date().toISOString();}, 1000);

最终效果如下:

以下是完整代码:

                  Document        
<script> function compile(tpl) { const re = /(\{\{\s+)(\w+)(\s+\}\})/m; const mg = tpl.match(re); return tpl.replace(">{{", " vid="" + mg[2] + "">{{").replace(mg[0], ""); } function reactive(data) { return new Proxy(data, { set(target, property, value) { const prev = target[property]; target[property] = value; if (prev !== value) { const vel = document.querySelector(`[vid=${property}]`); vel.innerHTML = value; } return true; }, }); } const app = { tpl: "

{{ current_time }}

", data: { current_time: "2023-05-03T05:14:46.176Z", }, mount() { const rootEl = document.querySelector("#root"); rootEl.innerHTML = compile(this.tpl); this.data = reactive(this.data); this.mounted(); }, mounted() { setInterval(() => { this.data.current_time = new Date().toISOString(); }, 1000); }, }; document.addEventListener("DOMContentLoaded", () => { app.mount(); }); </script>
责任编辑:admin

标签: