对与数据、计算等无关的变量的反应性 [英] Reactivity on Variables Not Associated With Data, Computed, etc

查看:24
本文介绍了对与数据、计算等无关的变量的反应性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

vue.js 上进行了大量试验和阅读之后,我使用组件等处理了我的第一个应用程序.我发现将外部对象与数据关联并弄清楚在哪些条件下很棘手 Vue 将这些外部实体与 data/computed/watch/props 属性绑定.我的组件遇到了一些奇怪的惊喜,我决定使用 codepen 探索一些案例.例如,我主要关心的是当您在 data 部分有 a: b, 并且 b 是一个外部实体,如值、数组,一个对象,简单的还是深度嵌套的,主要是如何绑定到{{a}}v-bind中的DOM.

After much trials and reading on vue.js, I tackled my first app with components, etc. I found tricky to associate external object to data and figure out in which conditions Vue binds those external entities with the data/computed/watch/props attributes. I ran into some strange surprises with my components and I decided to explore some cases with codepen. My main concern is for example when you have a: b, in the data section and b is an external entity like a value, an array, an object, simple or deeply nested, how does it work with binding to the DOM in {{a}} and v-bind mainly.

令我惊讶的是,在这些测试中,我第一次看到 {{b}} 也是响应式的.为什么不呢,因为 b 是在 data 部分声明的.当我尝试 {{c}} 时,事情变得很奇怪,其中 c 是一个不存在于 Vue 对象中的外部实体.DOM 对 c 也有反应!

To my surprise during those tests, was first to see {{b}} was reactive too. Why not, because b is declared in the data section. Things become strange when I tried {{c}} where c is an external entity not present anywhere in the Vue object. DOM was reactive to c too!

更奇怪的是,我只在 HTML/模板部分观察到这种现象:watch 只对 acomputed 有反应 ab 但不在 c 上.

More strangely, I observed this phenomenon only in HTML/template part: watch only reacts on a and computed on a and b but not on c.

我还观察到 props 似乎对 abc 具有反应性.

I also observed props seem to be reactive on a, b, and c.

所有这些测试都组合在一个 codepen 中,我在其中设置了通过 setInterval 移动的外部数据.它在这里:https://codepen.io/Djee/pen/qwXjRw

All these tests are combined in a codepen where I set my external data moving by a setInterval. It's here: https://codepen.io/Djee/pen/qwXjRw

更广泛地说,我发现没有任何文章或材料解决我第一次提到的那些方面,特别是这种自动绑定对象的直接绑定在车把中,并且在 Vue 对象.我错过了什么?是否有一些材料探索/解释这些方面?感谢您的帮助.

More broadly, I found no article or material addressing those aspects I first mention and specifically not this kind of auto-binding of objects directly bound in handlebars and live without being mentioned anywhere in the Vue object. Did I miss something? Is there some material exploring/explaining those aspects? Thanks for the help.

PS:在我的项目中,我发现在created()函数中使用this.$watch(cb, {deep: true});观看.对我来说另一个奇怪的东西,在写作时没有包含在这个 codepen 中.也许我会添加它.

PS: in my project, I found using this.$watch(cb, {deep: true}); in the created() function is more powerful than watch. Another oddity for me, not included in this codepen, as of writing. Maybe I'll add it.

推荐答案

我认为这是您问题的关键部分:

I think this is the key part of your question:

如何绑定到 DOM

您编写 codepen 的方式使这看起来像是一个简单的问题,但这里涉及的几个阶段并不是很明显.

The way you've written your codepen makes this appear like a straightforward question but there are several stages involved here that aren't immediately obvious.

  1. 当您创建 Vue 实例时,container 元素的内容将用作模板.然后丢弃 DOM 节点本身.理解这一点很重要,因为它与许多其他框架的工作方式有很大不同.您没有将任何内容绑定到这些 DOM 节点,它们只是模板.
  2. 然后将该模板编译为 render 函数.Vue 将调用这个 render 函数来渲染组件.
  3. 在渲染过程中,render 函数返回虚拟 DOM (VDOM) 节点.其中一些节点将对应于 HTML 元素,而其他节点将引用子组件.子组件将依次渲染,最终,一旦所有组件都渲染完毕,一切都会减少到只有 HTML VDOM 节点.
  4. 在初始渲染期间,这些 HTML VDOM 节点相当直接地转换为 HTML DOM.在更新(重新渲染)期间,新的 VDOM 会与之前的 VDOM 进行比较,实际的 DOM 只会在发生更改的地方更新.
  1. When you create the Vue instance the contents of your container element are used as a template. The DOM nodes themselves are then thrown away. This is important to understand as it differs significantly from how many other frameworks work. You aren't binding anything to those DOM nodes, they are just the template.
  2. That template is then compiled down into a render function. It is this render function that Vue will call to render the component.
  3. During rendering the render function returns virtual DOM (VDOM) nodes. Some of these nodes will correspond to HTML elements while others will refer to child components. The child component will be rendered in turn and eventually, once all components are rendered, everything reduces down to just HTML VDOM nodes.
  4. During the initial render these HTML VDOM nodes translate fairly directly into the HTML DOM. During updates (re-rendering) the new VDOM is compared to the previous VDOM and the actual DOM is only updated where changes have occurred.

从反应性的角度来看,render 很像一个计算属性.render 函数触及的任何反应数据都将被跟踪.如果该数据随后发生更改,它将触发该组件的重新渲染.

From a reactivity perspective, render is a lot like a computed property. Any reactive data that is touched by the render function will be tracked. If that data subsequently changes it'll trigger a re-render of that component.

不会跟踪任何非反应性数据.更新该数据不会导致重新渲染,不会更新计算属性,也不会触发任何 watch 侦听器.

Any data that is not reactive will not be tracked. Updating that data will not cause a re-render, won't update computed properties and won't trigger any watch listeners.

在您的示例中,您有一个大模板,该模板将被编译为单个 render 函数.如果任何反应性数据发生变化,它将触发重新渲染.这将运行整个 render 函数并创建一个新的 VDOM 树.根据需要访问数据,并将包括反应性和非反应性数据.

In your example you've got one big template that will be compiled down to a single render function. If any of the reactive data changes it will trigger a re-render. That will run the whole render function and create a new VDOM tree. Data is accessed as required and will include both reactive and non-reactive data.

但是,如果您只是更改非反应性数据,则不会触发重新渲染.在这种情况下,不会调用 render 函数,也不会发生 DOM 更改.

However, if you just change non-reactive data then there is nothing to trigger the re-render. In that case the render function won't be called and no DOM changes will occur.

不要让名称 v-bind 混淆你.这只是意味着这是一个 JavaScript 表达式",并不一定与创建依赖项有关.在 render 函数级别跟踪依赖项,并且没有特殊处理将依赖项直接链接到它们的 DOM 节点.如果任何依赖项发生变化,则整个 render 函数将重新运行.这并不像听起来那么昂贵,因为 render 函数只是创建一个 VDOM.更新 DOM 的昂贵过程将使用 VDOM 差异/更新来仅进行更新需要它的 DOM 节点所需的最小更改.一旦模板被编译,数据与模板中看似存在的 DOM 之间的直接链接不会保留.

Don't let the name v-bind confuse you. That just means 'this is a JavaScript expression' and isn't necessarily anything to do with creating a dependency. Dependencies are tracked at the level of the render function and there is no special handling to link dependencies directly to their DOM nodes. If any dependency changes then the whole render function will be re-run. This isn't as expensive as it sounds as the render function is only creating a VDOM. The expensive process of updating the DOM will use VDOM diffing/updating to make only the minimal changes that are required to update the DOM nodes that need it. The direct link between the data and the DOM that appears to exist in the template is not retained once the template is complied.

计算属性的工作方式类似.它们的值会被缓存,并且仅在响应式依赖项更新时才重新计算.如果它们具有非反应性依赖项,则不会使缓存的值无效.但是,如果响应式依赖项使缓存值无效,那么在计算新值时,任何更改的非响应式依赖项仍将被拉入.

Computed properties work in a similar way. Their values are cached and only recalculated when a reactive dependency is updated. If they have a non-reactive dependency then that won't invalidate the cached value. However, if a reactive dependency invalidates the cached value then any changed non-reactive dependencies will still get pulled in when the new value is calculated.

判断对象/数组是否为响应式的最简单方法是将其注销到控制台.当 Vue 使对象具有反应性时,它会用 getter 和 setter 替换其所有属性,这会改变它在控制台中的显示方式.

The easiest way to figure out whether an object/array is reactive is to log it out to the console. When Vue makes an object reactive it replaces all of its properties with getters and setters and that changes how it appears in the console.

一般来说,当一个对象第一次被添加到 data 时,Vue 只会让一个对象响应一次.只有此时存在的属性才会创建 getter 和 setter,从而导致以后添加的任何新属性都不会响应的常见问题.这就是 Vue.setvm.$set 的作用:

Generally Vue will only make an object reactive once, when it's first added to the data. Only properties that exist at that point will have getters and setters created, leading to the common problem that any new properties added later will not be reactive. That is what Vue.set and vm.$set are for:

https://vuejs.org/v2/api/#vm-set

Vue 最近添加了 Vue.observable,它允许在不通过 data 的情况下使对象具有反应性:

Vue recently added Vue.observable, which allows objects to be made reactive without going through data:

https://vuejs.org/v2/api/#Vue-observable

这篇关于对与数据、计算等无关的变量的反应性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆