基本上,当我有一个组件时,我们称它为"TransportComponenet.vue",在该组件中,我有一个data(),我的属性是carId,transportId.vue所做的是为这些属性生成getter和setter.假设在这个组件的视图中,我输入{{carId + transportId}},也输入{{carId * transportId}}.

只要我有{{carId * transportId}}个,我就可以看到{{carId+ transportId}}个.所以vue来将它们注册到组件的watcher中.当我在某处使用setter时,比如this.carId = 5.Vue为此属性执行setter函数,并重新判断之前保存在watcher中的函数(getter).这是正确的假设吗?

我不明白的是,Dep类和Watcher类之间存在什么关系?我知道他们都扮演着重要的角色.我真的很荣幸能解释"什么东西go 了哪里,什么时候go ,为什么go ".

推荐答案

react 性是状态和DOM之间的自动同步.这就是Vue和React等视图库在其核心中所做的.他们用自己的方式做这件事.

我认为Vue的react 系统是双重的.问题的一面是DOM更新机制.让我们先看看.

假设您有一个模板如下的组件:

<template>
    <div>{{ foo }}</div>
</template>

<script>
export default {
    data() {
        return {foo: 'bar'};
    }
}
</script>

此模板将转换为渲染函数.这在使用vue-loader的构建时发生.上面模板的渲染函数如下所示:

function anonymous(
) {
    with(this){return _c('div',[_v(_s(foo))])}
}

Render函数在浏览器上运行,执行时返回一个Vnode(虚拟 node ).虚拟 node 只是一个简单的JavaScript对象,它代表实际的DOM node ,是DOM node 的蓝图.执行上述渲染函数时,会返回如下内容:

{
    tag: 'div',
    children: ['bar']
}

Vue然后根据这个Vnode蓝图创建实际的DOM node ,并将其放入DOM中.

稍后,假设foo的值发生变化,somehow渲染函数再次运行.它将给出一个不同的Vnode.Vue然后将新的Vnode与旧的Vnode区分开来,只将所需的更改修补到DOM中.

这为我们提供了一种机制,可以根据组件的最新状态高效地更新DOM.如果组件的任何状态(数据、props 等)发生变化时,每次调用组件的渲染函数时,我们都有完整的react 系统.

这就是Vuereact 性硬币的另一面.这就是react 型的接受者和接受者.

如果你还没有意识到这一点,这将是理解Object.defineProperty API的好时机.因为Vue的react 系统依赖于这个API.

太长,读不下go 了它允许我们用自己的getter和setter函数覆盖对象的属性访问和赋值.

当Vue实例化组件时,它会遍历dataprops的所有属性,并使用Object.defineProperty重新定义它们.

它实际做的是,每个数据和props 属性都有defines getters and setters个.通过这样做,它会覆盖该属性的点访问(this.data.foo)和赋值(this.data.foo=someNewValue).因此,每当这两个操作在该属性上发生时,就会调用我们的重写.所以我们有一个钩子来对付他们.我们稍后会回到这个话题.

此外, for each 属性创建一个new Dep()类实例.之所以称之为Dep,是因 for each 数据或props 属性都可以是组件渲染函数的dep属性.

但首先,重要的是要知道每个组件的渲染函数都会被调用within a watcher次.因此,观察者有一个相关组件的渲染功能.Watcher也可用于其他用途,但当它查看组件的渲染函数时,它是render watcher.观察者将自己指定为current running watcher,在某个地方可以全局访问(在Dep.target静态属性中),然后运行组件的render function.

现在我们回到被动的接球手和接球手.运行渲染函数时,将访问状态属性.例如this.data.foo.这将调用我们的getter覆盖.调用getter时,会调用dep.depend().dep判断当前的watcher,如果这个watcher正在运行,那么这个watcher将被分配给当前的watcher.它被称为dep.depend(),因为我们让watcher依赖于dep.

_______________                       _______________
|             |                       |             |
|             |     subscribes to     |             |
|   Watcher   |    -------------->    |     Dep     |
|             |                       |             |
|_____________|                       |_____________|

这和

_______________                       _______________
|             |                       |             |
|  Component  |     subscribes to     |   it's      |
|  render     |    -------------->    |   state     |
|  function   |                       |   property  |
|_____________|                       |_____________|

稍后,当state属性更新时,会调用setter,关联的dep对象会将新值通知其订阅者.订阅者是观察者,可以感知呈现函数,这就是组件呈现函数在状态改变时自动被调用的方式.

这使得react 系统完整.我们有一种方法可以在组件的状态发生变化时调用其渲染函数.我们有一种方法可以在这种情况下高效地更新DOM.

通过这种方式,Vue在状态属性和渲染函数之间创建了一种关系.Vue确切地知道在状态属性更改时要执行哪个渲染函数.这可以很好地扩展,从根本上消除了开发人员手中的一类性能优化责任.无论组件树有多大,开发人员都不需要担心组件渲染过度.为了防止这种情况,请做出react ,例如提供PureComponent或shouldComponentUpdate.在Vue中,这是不必要的,因为Vue确切地知道在任何状态更改时要重新渲染哪个组件.

但现在我们知道了Vue是如何让事情变得被动的,我们可以想出一种方法来稍微优化事情.假设你有一个博客帖子组件.您可以从后端获取一些数据,并使用Vue组件在浏览器上显示它们.但是博客数据没有必要是被动的,因为它很可能不会改变.在这种情况下,我们可以告诉Vue,不要通过冻结对象使这些数据成为被动的.

export default {
  data: () => ({
    list: {}
  }),
  async created() {
    const list = await this.someHttpClient.get('/some-list');

    this.list = Object.freeze(list);
  }
};

除此之外,Oject.freeze会禁用对象的可配置性.不能使用Object.defineProperty重新定义该对象的属性.所以Vue skips整个react 性设置都适用于这样的物体.

此外,您自己也可以浏览Vue源代码,在这个主题上有两个非常好的资源:

  1. Vue Mastery的Advanced component门课程
  2. 由Evan You创作的FrontendMaster's Advanced Vue.js Features from the Ground Up

如果您对一个简单的虚拟DOM实现的内部 struct 感到好奇,请查看Jason Yu的博客文章.

Building a Simple Virtual DOM from Scratch

Vue.js相关问答推荐

Vue 3 需要 main.js 中的文件

在 Vue 中更改 json 数据后,如何在屏幕上重新呈现表格组件?

拖入 vue2-google-map 后如何获取标记位置?

如何在Typescript语言Vuejs中使用watch功能?

[Vue 警告]:渲染函数中的错误:TypeError:无法读取属性 'first_name' of null

Bootstrap-vue b-table,标题中带有过滤器

Vuetify v-select 组件宽度变化

在 vue-router 中带有路由的 Vuejs2 模态

当前端和后端位于虚拟 docker 网络中时,如何使用 axios 寻址后端主机

Vuetify / Offline离线图标

如何使用 vuejs 从 SPA 访问 /storage -laravel- 中的图像

如果我观看解构的props,Vue 3 手表将无法正常工作

Vue-test-utils:在单个测试中多次使用 $nextTick

NUXT如何将数据从页面传递到布局

安装后运行computed计算函数

如何在 JEST 测试中模拟全局 Vue.js 变量

如何在 Vue.js 中延迟 @keyup 处理程序

Vuejs 不会在 HTML 表格元素中呈现组件

如何使用vue js判断组件本身的数据何时发生变化?

理解 Vue 中的this关键字