轻量级 JavaScript 框架 Vue 2.6 发布了,代号 “Macross”。新版带来了大量的改进、内部更改和新功能。
slots:新语法、性能优化、向 3.0 看齐
Slot 是 Vue 实现灵活组合组件的一个重要机制。在 3.0 的原型开发过程中,开发团队发现了一些可以进一步改善现有 slot 机制的方法,其中一些改进可以在不破坏更改的情况下被引入 2.x。另外可能会需要破坏性改动的改进,开发团队会尽量提供渐进的替代方案,使将来的迁移更容易。
新语法
首先是 scoped slot 的新语法。在提出、讨论并试验了多种不同的设计(1, 2, 3)后,采用了这个 RFC 所描述的 v-slot 语法。下面是使用命名 slot 的一个简短示例:
<my-component> <template v-slot:header> <p>Header</p> </template> <template v-slot:item="{ data }"> <h2>{{ data.title }}</h2> <p>{{ data.text }}</p> </template> <template v-slot:footer> <p>Footer</p> </template> </my-component>
新语法统一了单个指令中普通 slot 和 scoped slot 的使用,并强制使用了更明确和可读性的命名 slot。它还与现有语法完全兼容,这使得开发团队可以在 2.6 版本中发布它。
如果您已经熟悉现有的 slot 语法,建议阅读 RFC 以更好地理解新语法背后的基本原理。如果您还不熟悉 slot,建议阅读更新的 slot 文档相反。
性能优化
将在 3.0 版本中看到有关 slot 的另一个改进,是普通 slot 和 scoped slot 的实现的统一,这是因为 scoped slot 在性能方面的优势。普通 slot 将在父组件的渲染周期中渲染。当 slot 的依赖项发生变化时,会导致父组件和子组件进行重新渲染。另一方面,scoped slot 被编译成内联函数,并在子组件的渲染周期中被调用。这意味着子组件将会收集 scoped slot 所依赖的所有数据依赖项,从而做出更精确的更新。
在 2.6 版本中,开发团队引入了一种优化手段,进一步确保父组件的依赖项变化仅影响到父组件,并且如果只使用了 scoped slot,就不会强制子组件做出更新。
此外:
-
所有使用新 v-slot 语法的 slot 都将被编译为 scoped slot,这意味着所有使用新语法的 slot 都会自动获得性能提升;
-
现在所有普通的 slot 也通过 this.$scopedSlots 暴露出来,这意味着使用 render 函数而不是模板的用户现在也可以使用 this.$scopedSlots,而不用担心传入的 slot 是什么类型。
在 3.0 中,将不再区分 scoped 与非 scoped slot——所有 slot 将使用统一的语法,被编译为相同的格式,并具有相同的性能。
异步错误处理
Vue 的内置错误处理机制(组件内 errorCaptured hook 和全局 errorHandler hook)现在也会捕获 v-on 处理程序内部的错误。另外,如果任意一个生命周期 hook 或事件处理程序执行了异步操作,现在可以从函数中返回一个 Promise,Promise 链中任何一个未被捕获的错误都会被发送给错误处理程序。如果使用了 async/await,则会变得更加容易,因为异步函数隐式返回 Promise:
export default { async mounted() { // if an async error is thrown here, it now will get // caught by errorCaptured and Vue.config.errorHandler this.posts = await api.getPosts() } }
动态指令参数
指令参数现在可以接受动态的 JavaScript 表达式:
<div v-bind:[attr]="value"></div> <div :[attr]="value"></div> <button v-on:[event]="handler"></button> <button @[event]="handler"></button> <my-component> <template v-slot:[slotName]> Dynamic slot name </template> </my-component>
更多细节可以在这个 RFC 中找到。
为了方便起见,如果参数值为 null,则绑定和监听器会被移除。(组件库的作者要注意:这个功能要求 Vue 运行时为 2.6.0 及以上版本。如果你发布的是预编译的组件,并希望保持与 2.6 之前版本的兼容性,请避免在源代码中使用该新功能。)
编译器警告位置信息
2.6 版本开始,大多数模板编译警告消息现在都带有源码位置信息。这使得我们就能够为这些警告消息生成更好的代码帧:
显式创建独立的响应式对象
2.6 版本引入了一个新的全局 API,可以显式创建独立的响应式对象:
const reactiveState = Vue.observable({ count: 0 })
生成的对象可以直接用在计算属性或 render 函数中,并在发生变化时触发对应的更新。
服务器端渲染期间的数据预取
新的 serverPrefetch hook 允许任何组件(不仅仅是路由级别的组件)在服务器端渲染期间预取数据,更加灵活并降低了数据获取和路由器之间的耦合。一些项目(如 Nuxt 和 vue-apollo)已经计划通过这个新功能来简化它们的实现。
新 ES 模块构建,可直接导入使用
之前 ES 模块构建主要目标是与捆绑包一起使用。这些构建包含了在编译时需要替换为环境变量的内容。Vue 2.6 现在提供了新的 ES 模块构建,可以直接在浏览器中使用:
<script type="module"> import Vue from 'https://unpkg.com/vue/dist/vue.esm.browser.js' new Vue({ // ... }) </script>
重要的内部改动
让 nextTick 恢复使用 Microtask
在 2.5.0 版本中,开发团队做出了一个内部调整,如果更新是在 v-on 事件处理程序中触发的,则会导致 nextTick 使用 Macrotask(而不是 Microtask)来让更新进入队列。最初这么做是为了修复一些浏览器的边界情况,但反过来又导致了很多其他问题。在 2.6 版本中,开发团队为原始问题找到了一个更简单的修复方案,这样我们就可以在任何情况下恢复 nextTick 使用 Microtask。
如果你对这方面的技术细节感兴趣,请在此处查看。
this.$scopedSlots 函数统一返回数组
这个变更只影响 render 函数用户。在 render 函数中,scoped slot 通过 this.$scopedSlots 暴露为函数。在之前版本,调用 scoped slot 函数会根据父组件传入内容返回单个 VNode 或 VNode 数组。这种设计实际上是一种疏忽,因为它返回值的类型不确定,可能会导致意外的边界情况。
在 2.6 版本,scoped slot 函数确保只返回 VNode 数组或 undefined。如果您的现有代码中如果有些地方返回的是数组但没有被检查出来,可能会出问题,需要进行相应的修正。更多细节请看这里。
下载地址: