大家好!在本文中,我们将讨论一个相当不寻常的主题,由于某种原因我没有找到有关该主题的信息,尽管它在现代 javascript 框架和用于创建用户界面的库中非常有用,因为在某些情况下,应用该概念可以帮助将 dom 的处理速度提高数倍。
名称是有条件的,但本质很重要。
术语“通常状态”是指由于状态管理器或框架或库的内部功能而直接保存的数据。 vue.js 中状态的示例:
createapp({ setup() { return { count:ref(0); }; }, template: `<div> <button @click="count++">click!</button> <div>clicks: {{ count }}</div> </div>`, }).mount("#app");
在这种情况下,状态直接存储在对象中,该对象在框架的预定义方法中返回。
因此,dom 节点可以通过不同的语法结构依赖于给定的状态。在示例中,这样的构造是字符串 {{ clicks }} ,它由于字符串插值而更改为当前数据。
此外,常用的语法结构是“循环”。循环是一个关键字,可以是属性,也可以是显式定义 dom 节点创建的方法,具体取决于来自状态的元素数量和值本身。循环示例:
<template> <tr v-for="{ id, label } of rows" :key="id" :class="{ danger: id === selected }" :data-label="label" v-memo="[label, id === selected]" > <td class="col-md-1">{{ id }}</td> <td class="col-md-4"> <a @click="select(id)">{{ label }}</a> </td> <td class="col-md-1"> <a @click="remove(id)"> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span> </a> </td> <td class="col-md-6"></td> </tr> </template>
假设我们想要更新一个元素的类。我们的数据以对象数组的形式出现。很明显,键必须在对象中显式指定:您可以通过键获取双大括号中的类的值,但这是主要问题,因为它很慢。
为了证实我的话,我将采用cample.js框架的基准测试(在开发过程中我刚刚注意到了类似的问题)。在那里可以清楚地看到,直接依赖于正常状态数据的类比使用临时 view 状态的类设置得慢。
让我们使用cample.js的两个版本:3.2.0-alpha.45和3.2.1-beta.0。其中有一行“select row”(4行),这正是主要区别:
数据取自 126 和 128 基准测试版本。
从图中可以看出,一个结果与另一个结果相差几乎一倍半。我想了很久,为什么会这样呢?我曾经认为代码只是速度慢,但事实不同。 如果数据处于常规状态,那么即使我们只更改 n 序数对象中属性值中的一个字母,也有必要遍历所有数据。
const olddata = [ { id: 1, label: "text 1", }, { id: 2, label: "text 2" }, { id: 3, label: "text 3", } ]; const newdata = [ { id: 1, label: "text 11", // 1 iteration, one letter has changed, but we're still looking further }, { id: 2, label: "text 2" }, // 2 iteration { id: 3, label: "text 3", // 3 iteration } ];
因此,它总是很慢,但这是逻辑上正确的方法,也是所有用于创建用户界面的现代框架和库的主要笑话。但除了这种方法还有什么其他选择呢?
特别是对于这样的问题,当需要引入与主状态分离的状态,以免多次遍历元素时,您可以在代码中使用某种概念,该概念将允许您不绑定对于一个对象,但是对于一个元素。这个概念是一个临时的 view 状态。
其本质如下:我们为每个元素创建一个单独的数组。它将位于模块本身的代码中,我们在回调函数中提供与该数组交互的用户方法。因此,该模块将存储大约以下代码:
{ el:li, temporaryviewstate:[{class:"value"}] }
在项目中是这样的:
setclass: [ (setdata, event, eachtemporaryviewstate) => () => { const { settemporaryviewstate, cleartemporaryviewstate } = eachtemporaryviewstate; cleartemporaryviewstate(); settemporaryviewstate(() => { return { class: "value" }; }); }, "updateclass", ],
此外,这个数组只能在调用回调函数时创建,或者简单地为所有元素创建一个数组。这将允许我们不绑定到来自正常状态的数据,而是绑定到我们想要更新的特定元素。也就是说,我们创建一个可以清除和重写的临时状态。这非常适合我们想要处理不受控制的元素的情况:
<!-- Controlled --> <input type="text" value="{{ value }}" ::change="setValue()" /> <!-- Uncontrolled --> <input type="text" class="{{ temporaryViewState.class }}" />
也就是说,它根本不直接依赖于平常的状态,所以在dom中,这个节点可以说是静态的(如果我们制作一个节点模板,那么这个元素就会跳过)。
因此,我们有一个仅依赖于特定元素和回调函数的状态。使用“循环”时,您不必遍历整个数据数组来更新一个元素中的一个字母。只需为特定元素调用特定函数并更新特定类就足够了。
这将使您能够在使用数据和 dom 时快速获得结果。很有可能在现代框架和库中应用这个概念并使用它。