Vue.js 响应式原理

 Vue 不支持 IE8 以及更低版本浏览器

是因为当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setterObject.defineProperty 是 ES5 中一个无法 shim 的特性。

建议安装 vue-devtools 

来获取对检查数据更加友好的用户界面

是因为不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同。

在属性被访问和修改时通知变更 getter/setter。

watcher

使它关联的组件重新渲染

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

属性必须在 data 对象上存在

才能让 Vue 将它转换为响应式的

受现代 JavaScript 的限制 (而且 Object.observe 也已经被废弃),Vue 无法检测到对象属性的添加或删除。你必须在初始化实例前声明所有根级响应式属性,哪怕只是一个空值。

Vue.set(object, propertyName, value) 

向嵌套对象添加响应式属性
Vue.set(vm.someObject, 'b', 2)
//vm.$set 实例方法
this.$set(this.someObject,'b',2)
//Object.assign 创建一个新的对象
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

//数组修改
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
vm.items.splice(newLength)

Vue 在更新 DOM 时是异步执行的

在缓冲时去除重复数据避免不必要的计算和 DOM 操作

要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。

Vue 在内部对异步队列尝试使用原生的 Promise.thenMutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。

Vue.nextTick(callback)

回调函数将在 DOM 更新完成后被调用
updateMessage: function () {
      this.message = '已更新'
      console.log(this.$el.textContent) // => '未更新'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => '已更新'
      })
 }

$nextTick() 返回一个 Promise 对象,可以使用 ES2017 async/await 语法

 updateMessage: async function () {
    this.message = '已更新'
    console.log(this.$el.textContent) // => '未更新'
    await this.$nextTick()
    console.log(this.$el.textContent) // => '已更新'
  }

key

预期number | string

key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。

而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。

有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。

它也可以用于强制替换元素/组件而不是重复使用它。如下场景时很有用:

  • 完整地触发组件的生命周期钩子
  • 触发过渡

例如:

<transition>
  <span :key="text">{{ text }}</span>
</transition>

当 text 发生改变时,<span> 总是会被替换而不是被修改,因此会触发过渡。

虚拟 DOM 

Vue 通过建立一个虚拟 DOM 来追踪自己要如何改变真实 DOM。请仔细看这行代码:

return createElement('h1', this.blogTitle)

createElement 到底会返回什么呢?其实不是一个实际的 DOM 元素。它更准确的名字可能是 createNodeDescription,因为它所包含的信息会告诉 Vue 页面上需要渲染什么样的节点,包括及其子节点的描述信息。我们把这样的节点描述为“虚拟节点 (virtual node)”,也常简写它为“VNode”。

“虚拟 DOM”是我们对由 Vue 组件树建立起来的整个 VNode 树的称呼。

组件树中的所有 VNode 必须是唯一的。

渲染函数

Vue 的模板实际上被编译成了渲染函数。

Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。

Vue.component('anchored-heading', {
  render: function (createElement) {
    return createElement(
      'h' + this.level,   // 标签名称
      this.$slots.default // 子节点数组
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})

向组件中传递不带 v-slot 指令的子节点时,比如 anchored-heading 中的 Hello world!,这些子节点被存储在组件实例中的 $slots.default 中。