In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly introduces "how to make localStorage responsive in Vue". In daily operation, I believe many people have doubts about how to make localStorage responsive in Vue. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the questions of "how to make localStorage responsive in Vue". Next, please follow the editor to study!
Responsiveness is one of the most important features of Vue.js. If you don't know what's going on behind the scenes, it's also one of the most mysterious places. For example, why can't it be used for objects and arrays, but not for other things like localStorage?
Let's answer this question and let Vue responsiveness be used with localStorage when solving this problem.
If you run the following code, you will see that the counter appears as a static value and does not change as we expected, because setInterval changed the value in localStorage.
New Vue ({el: "# counter", data: () = > ({counter: localStorage.getItem ("counter")}), computed: {even () {return this.counter% 2 = = 0;}}, template: `Counter: {{counter}} Counter is {{even? 'even':' odd'}} `); / / some-other-file.js setInterval (() = > {const counter = localStorage.getItem ("counter"); localStorage.setItem ("counter", + counter + 1);}, 1000)
Although the counter property in the Vue.js instance is responsive, it does not change because we have changed its source in localStorage.
There are several solutions, and perhaps the best one is to use Vuex and keep the stored values synchronized with localStorage. But what if we need something as simple as this one? We need to take a closer look at how Vue.js 's responsive system works.
Responsiveness in Vue
When Vue initializes the component instance, it observes the data option. This means that it will iterate through all the attributes in the data and use Object.defineProperty to convert them to getter/setter. By setting a custom setter for each property, Vue can know when the property has changed and can notify dependents who need to respond to the change. How does it know which dependents depend on an attribute? By accessing getters, it can register when calculated properties, observer functions, or rendering functions access data properties.
/ / core/instance/state.js function initData () {/ /... Observe (data)} / / core/observer/index.js export function observe (value) {/ /. New Observer (value) / /...} export class Observer {/ /... Constructor (value) {/ /... This.walk (value)} walk (obj) {const keys = Object.keys (obj) for (let I = 0; I
< keys.length; i++) { defineReactive(obj, keys[i]) } } } export function defineReactive (obj, key, ...) { const dep = new Dep() // ... Object.defineProperty(obj, key, { // ... get() { // ... dep.depend() // ... }, set(newVal) { // ... dep.notify() } }) } 所以,为什么 localStorage 不响应?因为它不是具有属性的对象。 但是等一下,我们也不能用数组定义getter和setter,但Vue中的数组仍然是反应式的。这是因为数组在Vue中是一种特殊情况。为了拥有响应式的数组,Vue在后台重写了数组方法,并与Vue的响应式系统进行了修补。 我们可以对 localStorage 做类似的事情吗? 覆盖localStorage函数 首先尝试通过覆盖localStorage方法来修复最初的示例,以跟踪哪些组件实例请求了localStorage项目。 // LocalStorage项目键与依赖它的Vue实例列表之间的映射。 const storeItemSubscribers = {}; const getItem = window.localStorage.getItem; localStorage.getItem = (key, target) =>{console.info ("Getting", key); / / collect dependent Vue instances if (! storeItemSubscribers [key]) storeItemSubscribers [key] = []; if (target) storeItemSubscribes [key] .push (target); / / call the original function return getItem.call (localStorage, key);}; const setItem = window.localStorage.setItem; localStorage.setItem = (key, value) = > {console.info ("Setting", key, value) / / Update the value if (storeItemSubscribers [key]) {storeItemSubscribes [key] .forEach ((dep) = > {if (dep.hasOwnProperty (key)) dep [key] = value;}) in the relevant Vue instance;} / / call the original function setItem.call (localStorage, key, value);} New Vue ({el: "# counter", data: function () {return {counter: localStorage.getItem ("counter", this) / / We now need to pass "this"}}, computed: {even () {return this.counter% 2 = = 0;}}, template: `Counter: {{counter}} Counter is {{even? 'even':' odd'}} `}); setInterval (() = > {const counter = localStorage.getItem ("counter"); localStorage.setItem ("counter", + counter + 1);}, 1000)
In this example, we redefine getItem and setItem to collect and notify components that depend on the localStorage project. In the new getItem, we notice which component requests which project, and in setItems, we contact all the components that request the project and override their data properties.
In order for the above code to work, we must pass a reference to the component instance to getItem, which changes its function signature. We can no longer use the arrow function, because otherwise we wouldn't have the correct this value.
If we want to do better, we must dig deeper. For example, how do we track dependents without explicitly passing them on?
How Vue collects dependencies
For inspiration, we can go back to Vue's responsive system. We have previously seen that when accessing a data property, the getter of the data property causes the caller to subscribe to further changes to the property. But how does it know who made the call? When we get a data attribute, its getter function does not have any input as to who the caller is. The Getter function has no input, so how does it know who wants to register as a dependent?
Each data property maintains a list of dependencies that need to be responded to in the Dep class. If we delve deeper into this class, we can see that the dependency has been defined in the static target variable as long as the dependency is registered. This goal is determined by a very mysterious Watche class. In fact, these observers are actually notified when the data properties change, and they initiate the re-rendering of the component or the recalculation of the calculated properties.
But who are they?
When Vue makes the data option observable, it also creates a watcher for each calculated property function and all watch functions (which should not be confused with the Watcher class) and the render function for each component instance. The observer is like the companion of these functions. They mainly do two things:
When they are created, they evaluate the function. This triggers a collection of dependencies.
When they are told that a value they depend on has changed, they will rerun their function. This will eventually recalculate a calculated attribute or re-render the entire component.
Before observers call their responsible function, an important step occurs: they set themselves as the target of static variables in the Dep class. This ensures that responsive data properties are registered as dependents when they are accessed.
Track who called localStorage
We can't do this completely because we can't use the internal mechanism of Vue. However, we can use the idea of Vue that the observer can set the target to a static property before calling the function for which it is responsible. Can we set a reference to the component instance before calling localStorage?
If we assume that localStorage is called when setting the data option, we can insert it into beforeCreate and created. Both hooks are triggered before and after initializing the data option, so we can set a target variable, then clear it, and reference the current component instance (which we can access in the lifecycle hook). Then, in our custom acquirer, we can register the target as a dependency.
The last thing we need to do is to make these lifecycle hooks part of all our components, and we can do this through a global mix of the entire project.
/ / Mapping between the LocalStorage project key and the list of Vue instances that depend on it const storeItemSubscribers = {}; / the Vue instance currently initializing let target = undefined; const getItem = window.localStorage.getItem; localStorage.getItem = (key) = > {console.info ("Getting", key); / / collect dependent Vue instance if (! storeItemSubscribers [key]) storeItemSubscribers [key] = []; if (target) storeItemSubscribers [key] .push (target) / / call the original function return getItem.call (localStorage, key);}; const setItem = window.localStorage.setItem; localStorage.setItem = (key, value) = > {console.info ("Setting", key, value); / / Update the value if (storeItemSubscribers [key]) {storeItemSubscripts [key] .forEach ((dep) = > {if (dep.hasOwnProperty (key)) dep [key] = value;}) in the relevant Vue instance) } / / call the original function setItem.call (localStorage, key, value);}; Vue.mixin ({beforeCreate () {console.log ("beforeCreate", this._uid); target = this;}, created () {console.log ("created", this._uid); target = undefined;}})
Now, when we run the first example, we will get a counter that increments by one number per second.
New Vue ({el: "# counter", data: () = > ({counter: localStorage.getItem ("counter")}), computed: {even () {return this.counter% 2 = = 0;}}, template: `Counter: {{counter}} Counter is {{even? 'even':' odd'}} `); setInterval (() = > {const counter = localStorage.getItem ("counter"); localStorage.setItem ("counter", + counter + 1);}, 1000); at this point, the study on "how to make localStorage responsive in Vue" is over, hoping to solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.