You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
By default, Vue performs DOM updates **asynchronously**. Whenever a data change is observed, it will open a queue and buffer all the data changes that happen in the same event loop. If the same watcher is triggered multiple times, it will be pushed into the queue only once. Then, in the next event loop "tick", Vue flushes the queue and performs only the necessary DOM updates. Internally Vue uses `MutationObserver` if available for the asynchronous queuing and falls back to `setTimeout(fn, 0)`.
76
+
默认情况下,Vue 执行 DOM 更新**异步**,只要观察到的数据更改,它将打开一个队列和缓冲区发生的所有数据更改在相同的事件循环。如果相同的观察者多次触发,它将会只有一次推送到队列。然后,在接下来的事件循环"时钟"中,Vue 刷新队列并执行仅有必要的 DOM 更新。Vue内部使用`MutationObserver` 如果可用的异步队列调用回调`setTimeout(fn, 0)`.
98
77
99
-
For example, when you set `vm.someData = 'new value'`, the DOM will not update immediately. It will update in the next "tick", when the queue is flushed. Most of the time we don't need to care about this, but it can be tricky when you want to do something that depends on the post-update DOM state. Although Vue.js generally encourages developers to think in a "data-driven" fashion and avoid touching the DOM directly, sometimes it might be necessary to get your hands dirty. In order to wait until Vue.js has finished updating the DOM after a data change, you can use `Vue.nextTick(callback)` immediately after the data is changed. The callback will be called after the DOM has been updated. For example:
There is also the `vm.$nextTick()` instance method, which is especially handy inside components, because it doesn't need global `Vue` and its callback's `this` context will be automatically bound to the current Vue instance:
It should be noted that Vue's computed properties are **not** simple getters. Each computed property keeps track of its own reactive dependencies. When a computed property is evaluated, Vue updates its dependency list and caches the returned value. The cached value is only invalidated when one of the tracked dependencies have changed. Therefore, as long as the dependencies did not change, accessing the computed property will directly return the cached value instead of calling the getter.
144
-
145
-
Why do we need caching? Imagine we have an expensive computed property **A**, which requires looping through a huge Array and doing a lot of computations. Then we may have other computed properties that in turn depend on **A**. Without caching, we would be executing **A**’s getter many more times than necessary!
146
-
147
-
Because of computed property caching, the getter function is not always called when you access a computed property. Consider the following example:
148
-
149
-
```js
150
-
var vm =newVue({
151
-
data: {
152
-
message:'hi'
153
-
},
154
-
computed: {
155
-
example:function () {
156
-
returnDate.now() +this.message
157
-
}
158
-
}
159
-
})
160
-
```
161
-
162
-
The computed property `example` has only one dependency: `vm.message`. `Date.now()` is **not** a reactive dependency, because it has nothing to do with Vue's data observation system. Therefore, when you programmatically access `vm.example`, you will find the timestamp remains the same unless `vm.message` triggers a re-evaluation.
163
-
164
-
In some use cases, you may want to preserve the simple getter-like behavior, where every time you access `vm.example` it simply calls the getter again. You can do that by turning off caching for a specific computed property:
165
-
166
-
```js
167
-
computed: {
168
-
example: {
169
-
cache:false,
170
-
get:function () {
171
-
returnDate.now() +this.message
172
-
}
173
-
}
174
-
}
175
-
```
176
-
177
-
Now, every time you access `vm.example`, the timestamp will be up-to-date. **However, note this only affects programmatic access inside JavaScript; data-bindings are still dependency-driven.** When you bind to a computed property in the template as `{% raw %}{{ example }}{% endraw %}`, the DOM will only be updated when a reactive dependency has changed.
178
-
179
-
We've covered most of the basics - now it's time to take a deep dive! One of Vue's most distinct features is the unobtrusive reactivity system. Models are just plain JavaScript objects. When you modify them, the view updates. It makes state management very simple and intuitive, but it's also important to understand how it works to avoid some common gotchas. In this section, we are going to dig into some of the lower-level details of Vue's reactivity system.
180
-
181
-
## How Changes Are Tracked
182
-
183
-
When you pass a plain JavaScript object to a Vue instance as its `data` option, Vue will walk through all of its properties and convert them to getter/setters using [Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). This is an ES5-only and un-shimmable feature, which is why Vue doesn't support IE8 and below.
184
-
185
-
The getter/setters are invisible to the user, but under the hood they enable Vue to perform dependency-tracking and change-notification when properties are accessed or modified. One caveat is that browser consoles format getter/setters differently when converted data objects are logged, so you may want to install [vue-devtools](https://github.com/vuejs/vue-devtools) for a more inspection-friendly interface.
186
-
187
-
Every component instance has a corresponding **watcher** instance, which records any properties "touched" during the component's render as dependencies. Later on when a dependency's setter is triggered, it notifies the watcher, which in turn causes the component to re-render.
188
-
189
-

190
-
191
-
## Change Detection Caveats
192
-
193
-
Due to the limitations of modern JavaScript (and the abandonment of `Object.observe`), Vue **cannot detect property addition or deletion**. Since Vue performs the getter/setter conversion process during instance initialization, a property must be present in the `data` object in order for Vue to convert it and make it reactive. For example:
194
-
195
-
```js
196
-
var vm =newVue({
197
-
data: {
198
-
a:1
199
-
}
200
-
})
201
-
// `vm.a` is now reactive
202
-
203
-
vm.b=2
204
-
// `vm.b` is NOT reactive
205
-
```
206
-
207
-
Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it's possible to add reactive properties to a nested object using the `Vue.set(object, key, value)` method:
208
-
209
-
```js
210
-
Vue.set(vm.someObject, 'b', 2)
211
-
```
212
-
213
-
You can also use the `vm.$set` instance method, which is just an alias to the global `Vue.set`:
214
-
215
-
```js
216
-
this.$set(this.someObject, 'b', 2)
217
-
```
218
-
219
-
Sometimes you may want to assign a number of properties to an existing object, for example using `Object.assign()` or `_.extend()`. However, new properties added to the object will not trigger changes. In such cases, create a fresh object with properties from both the original object and the mixin object:
220
-
221
-
```js
222
-
// instead of `Object.assign(this.someObject, { a: 1, b: 2 })`
There are also a few array-related caveats, which were discussed earlier in the [list rendering section](/guide/list.html#Caveats).
227
-
228
-
## Declaring Reactive Properties
229
-
230
-
Since Vue doesn't allow dynamically adding root-level reactive properties, this means you have to initialize you instances by declaring all root-level reactive data properties upfront, even just with an empty value:
231
-
232
-
```js
233
-
var vm =newVue({
234
-
data: {
235
-
// declare message with an empty value
236
-
message:''
237
-
},
238
-
template:'<div>{{ message }}</div>'
239
-
})
240
-
// set `message` later
241
-
vm.message='Hello!'
242
-
```
243
-
244
-
If you don't declare `message` in the data option, Vue will warn you that the render function is trying to access a property that doesn't exist.
245
-
246
-
There are technical reasons behind this restriction - it eliminates a class of edge cases in the dependency tracking system, and also makes Vue instances play nicer with type checking systems. But there is also an important consideration in terms of code maintainability: the `data` object is like the schema for your component's state. Declaring all reactive properties upfront makes the component code easier to understand when revisited later or read by another developer.
247
-
248
-
## Async Update Queue
249
-
250
-
In case you haven't noticed yet, Vue performs DOM updates **asynchronously**. Whenever a data change is observed, it will open a queue and buffer all the data changes that happen in the same event loop. If the same watcher is triggered multiple times, it will be pushed into the queue only once. This buffered de-duplication is important in avoiding unnecessary calculations and DOM manipulations. Then, in the next event loop "tick", Vue flushes the queue and performs the actual (already de-duped) work. Internally Vue uses `MutationObserver` if available for the asynchronous queuing and falls back to `setTimeout(fn, 0)`.
251
-
252
-
For example, when you set `vm.someData = 'new value'`, the component will not re-render immediately. It will update in the next "tick", when the queue is flushed. Most of the time we don't need to care about this, but it can be tricky when you want to do something that depends on the post-update DOM state. Although Vue.js generally encourages developers to think in a "data-driven" fashion and avoid touching the DOM directly, sometimes it might be necessary to get your hands dirty. In order to wait until Vue.js has finished updating the DOM after a data change, you can use `Vue.nextTick(callback)` immediately after the data is changed. The callback will be called after the DOM has been updated. For example:
253
-
254
-
```html
255
-
<divid="example">{{ message }}</div>
256
-
```
257
-
258
-
```js
259
-
var vm =newVue({
260
-
el:'#example',
261
-
data: {
262
-
message:'123'
263
-
}
264
-
})
265
-
vm.message='new message'// change data
266
-
vm.$el.textContent==='new message'// false
267
-
Vue.nextTick(function () {
268
-
vm.$el.textContent==='new message'// true
269
-
})
270
-
```
271
-
272
-
There is also the `vm.$nextTick()` instance method, which is especially handy inside components, because it doesn't need global `Vue` and its callback's `this` context will be automatically bound to the current Vue instance:
0 commit comments