类别:媒体报道 发布时间:2021-01-05 浏览人次:
响应式是Vue.js的最大特色之一。如果你不知道幕后情况,它也是最神秘的地方之一。例如,为什么它不能用于对象和数组,而不能用于诸如 localStorage 之类的其他东西
让我们回答这个问题,在解决这个问题时,让Vue响应式与 localStorage 一起使用。
如果运行以下代码,则会看到计数器显示为静态值,并且不会像我们期望的那样发生变化,这是因为setInterval在 localStorage 中更改了该值。
new Vue({ el: "#counter", data: () = ({ counter: localStorage.getItem("counter") }), computed: { even() { return this.counter % 2 == 0; template: ` div div Counter: {{ counter }} /div div Counter is {{ even 'even' : 'odd' }} /div /div ` });
尽管Vue.js实例中的 counter 属性是响应式的,但它不会因为我们更改了它在 localStorage 中的来源而更改。
有多种解决方案,最好的也许是使用Vuex,并保持存储值与 localStorage 同步。但如果我们需要像本例中那样简单的东西呢 我们要深入了解一下Vue.js的响应式系统是如何工作的。
Vue 中的响应式
当Vue初始化组件实例时,它将观察data选项。这意味着它将遍历数据中的所有属性,并使用 Object.defineProperty 将它们转换为getter/setter。通过为每个属性设置自定义设置器,Vue可以知道属性何时发生更改,并且可以通知需要对更改做出反应的依赖者。它如何知道哪些依赖者依赖于一个属性 通过接入getters,它可以在计算的属性、观察者函数或渲染函数访问数据属性时进行注册。
// core/instance/state.js function initData () { // ... observe(data) }
所以,为什么 localStorage 不响应 因为它不是具有属性的对象。
但是等一下,我们也不能用数组定义getter和setter,但Vue中的数组仍然是反应式的。这是因为数组在Vue中是一种特殊情况。为了拥有响应式的数组,Vue在后台重写了数组方法,并与Vue的响应式系统进行了修补。
我们可以对 localStorage 做类似的事情吗
覆盖localStorage函数
首先尝试通过覆盖localStorage方法来修复最初的示例,以跟踪哪些组件实例请求了localStorage项目。
// LocalStorage项目键与依赖它的Vue实例列表之间的映射。 const storeItemSubscribers = {}; const getItem = window.localStorage.getItem; localStorage.getItem = (key, target) = { ("Getting", key); // 收集依赖的Vue实例 if (!storeItemSubscribers[key]) storeItemSubscribers[key] = []; if (target) storeItemSubscribers[key].push(target); // 调用原始函数 return getItem.call(localStorage, key); const setItem = window.localStorage.setItem; localStorage.setItem = (key, value) = { ("Setting", key, value); // 更新相关Vue实例中的值 if (storeItemSubscribers[key]) { storeItemSubscribers[key].forEach((dep) = { if (dep.hasOwnProperty(key)) dep[key] = value; }); // 调用原始函数 setItem.call(localStorage, key, value); };
在这个例子中,我们重新定义了 getItem 和 setItem,以便收集和通知依赖 localStorage 项目的组件。在新的 getItem 中,我们注意到哪个组件请求了哪个项目,在 setItems 中,我们联系所有请求该项目的组件,并重写它们的数据属性。
为了使上面的代码工作,我们必须向 getItem 传递一个对组件实例的引用,这就改变了它的函数签名。我们也不能再使用箭头函数了,因为否则我们就不会有正确的 this 值。
如果我们想做得更好,就必须更深入地挖掘。例如,我们如何在不显式传递依赖者的情况下跟踪它们
Vue如何收集依赖关系
为了获得启发,我们可以回到Vue的响应式系统。我们之前曾看到,访问数据属性时,数据属性的 getter 将使调用者订阅该属性的进一步更改。但是它怎么知道是谁做的调用呢 当我们得到一个数据属性时,它的 getter 函数没有任何关于调用者是谁的输入。Getter函数没有输入,它怎么知道谁要注册为依赖者呢
每个数据属性维护一个需要在Dep类中进行响应的依赖项列表。如果我们在此类中进行更深入的研究,可以看到只要在注册依赖项时就已经在静态目标变量中定义了依赖项。这个目标是由一个非常神秘的Watche类确定的。实际上,当数据属性更改时,将实际通知这些观察程序,并且它们将启动组件的重新渲染或计算属性的重新计算。
但是,他们又是谁
当Vue使 data 选项可观察时,它还会为每个计算出的属性函数以及所有watch函数(不应与Watcher类混为一谈)以及每个组件实例的render函数创建watcher。观察者就像这些函数的伴侣。他们主要做两件事:
当它们被创建时,它们会评估函数。这将触发依赖关系的集合。 当他们被通知他们所依赖的一个值发生变化时,他们会重新运行他们的函数。这将最终重新计算一个计算出的属性或重新渲染整个组件。在观察者调用其负责的函数之前,有一个重要的步骤发生了:他们将自己设置为Dep类中静态变量的目标。这样可以确保在访问响应式数据属性时将它们注册为从属。
追踪谁调用了localStorage
我们无法完全做到这一点,因为我们无法使用Vue的内部机制。但是,我们可以使用Vue的想法,即观察者可以在调用其负责的函数之前,将目标设置为静态属性。我们能否在调用 localStorage 之前设置对组件实例的引用
如果我们假设在设置 data 选项时调用了 localStorage,则可以将其插入 beforeCreate 和 created 中。这两个挂钩在初始化data选项之前和之后都会被触发,因此我们可以设置一个目标变量,然后清除该变量,并引用当前组件实例(我们可以在生命周期挂钩中访问该实例)。然后,在我们的自定义获取器中,我们可以将该目标注册为依赖项。
我们要做的最后一点是使这些生命周期挂钩成为我们所有组件的一部分,我们可以通过整个项目的全局混合来做到这一点。
// LocalStorage项目键与依赖它的Vue实例列表之间的映射 const storeItemSubscribers = {}; // 当前正在初始化的Vue实例 let target = undefined; const getItem = window.localStorage.getItem; localStorage.getItem = (key) = { ("Getting", key); // 收集依赖的Vue实例 if (!storeItemSubscribers[key]) storeItemSubscribers[key] = []; if (target) storeItemSubscribers[key].push(target); // 调用原始函数 return getItem.call(localStorage, key); const setItem = window.localStorage.setItem; localStorage.setItem = (key, value) = { ("Setting", key, value); // 更新相关Vue实例中的值 if (storeItemSubscribers[key]) { storeItemSubscribers[key].forEach((dep) = { if (dep.hasOwnProperty(key)) dep[key] = value; }); // 调用原始函数 setItem.call(localStorage, key, value); Vue.mixin({ beforeCreate() { console.log("beforeCreate", this._uid); target = this; created() { console.log("created", this._uid); target = undefined; });
现在,当我们运行第一个示例时,我们将获得一个计数器,该计数器每秒增加一个数字。
new Vue({ el: "#counter", data: () = ({ counter: localStorage.getItem("counter") }), computed: { even() { return this.counter % 2 == 0; template: ` div div Counter: {{ counter }} /div div Counter is {{ even 'even' : 'odd' }} /div /div ` });
我们的思想实验结束
当我们解决了最初的问题时,请记住这主要是一个思想实验。它缺少一些功能,例如处理已删除的项目和未安装的组件实例。它还具有一些限制,例如组件实例的属性名称需要与存储在 localStorage 中的项目相同的名称。就是说,主要目标是更好地了解Vue响应式在幕后的工作方式并充分利用这一点,因此,我希望你能从所有这些事情中受益。
到此这篇关于如何在Vue中使localStorage具有响应式的文章就介绍到这了,更多相关Vue localStorage响应式内容请搜索凡科以前的文章或继续浏览下面的
怎样在Vue中使localStorage具备响应式(观念试验) 本文关键详细介绍了怎样在Vue中使localStorage具备响应式,文中根据案例编码给大伙儿详细介绍的十分详尽,对大伙儿的学习培训或工作...
2021-01-05现阶段客户已慢慢加快向移动互联网网销售市场迁移,从而由此可见,移动互联网网现阶段的发展趋势室内空间极大,做为公司经营来讲,除开必须在PC端站住脚后跟以外,还务必向移动...
2021-01-05Vue完成电脑鼠标历经文本显示信息飘浮框实际效果的实例编码 本文关键详细介绍了Vue完成电脑鼠标历经文本显示信息飘浮框实际效果,原文中根据实例编码详细介绍的十分详尽,...
2021-01-05微信小程序开发设计 红姐助推精确高效率获得客户 红姐开发设计精英团队为公司出示百度搜索、淘宝网和手机微信微信小程序开发设计服务,精确联接客户,不用免费下载,扫二维码...
2021-01-05博观智能化联合上海市万家重做升級英中文响应式官方网站公布時间:2020/05/21来源于: 万家互联网字体样式:大中小型企业,以“用 AI 技术性持续造就与基本建设智能化幸福社会发展...
2021-01-05一:查验robots.txt Robots.txt是检索模块爬取网站时浏览的网页页面,当发觉网站被罚时,便是查验robots.txt文档。不仅要人力细心查验,也必须网站站长专用工具来认证是不是有不正...
2021-01-05