• 开始时间:2020-03-25
  • 目标主要版本:3.x
  • 引用 issue:N/A
  • 实现的 PR:N/A

摘要

  • 破坏性:自定义元素白名单现在在模版编译过程中执行,应该通过编译器选项而不是运行时 config 来配置。
  • 破坏性:将特殊的 is prop 的使用限制在保留的 标签中。
  • 引入一个新的 v-is 指令,以支持 2.x 的使用情况,即在原生元素上使用 is 来解决原生 HTML 解析的限制。

基本范例

N/A

动机

  • 以更有效的方式提供原生自定义元素支持。
  • 改进对自定义内置元素的支持。

具体设计

自主定制元素

在 Vue 2.x 中,将标签作为自定义元素的白名单是通过 Vue.config.ignoreElements 完成的。缺点是,当使用这个配置选项时,需要在每次调用 vnode 创建时进行检查。

在 Vue3.0 中,这种检查是在模版编译时进行的。例如,给定以下模版:

  1. <plastic-button></plastic-button>

默认生成的渲染函数代码是(伪代码):

  1. function render() {
  2. const component_plastic_button = resolveComponent('plastic-button')
  3. return createVNode(component_plastic_button)
  4. }

如果没有找到名为 plastic-button 的组件,它将发出一个警告。

如果用户希望使用一个名为 plastic-button 的原生自定义元素,所需的生成代码应该是:

  1. function render() {
  2. return createVNode('plastic-button') // render as native element
  3. }

指示编译器将 <plastic-button> 作为一个自定义元素:

  • 如果使用构建步骤:将 isCustomElement 选项传递给 Vue 模版编译器。如果使用 vue-loader,这应该通过 vue-loadercompilerOptions 选项来传递:

    1. // in webpack config
    2. rules: [
    3. {
    4. test: /\.vue$/,
    5. use: 'vue-loader',
    6. options: {
    7. compilerOptions: {
    8. isCustomElement: tag => tag === 'plastic-button'
    9. }
    10. }
    11. }
    12. // ...
    13. ]
  • 如果使用 on-the-fly 模版编译,则通过 app.config 传递: ```javascript const app = Vue.createApp(//)

app.config.isCustomElement = tag => tag === ‘plastic-button’

  1. 注意,运行时配置只影响运行时模版编译 —— 它不会影响预编译的模版。
  2. <a name="YMu7k"></a>
  3. ## 自定义内置元素
  4. 自定义元素规范提供了一种方法,通过向内置元素添加 `is` 属性,将自定义元素作为[自定义内置元素](https://html.spec.whatwg.org/multipage/custom-elements.html#custom-elements-customized-builtin-example)使用:
  5. ```vue
  6. <button is="plastic-button">Click Me!</button>

Vue 对 is 这个特殊的 prop 的使用是在模拟原生属性在浏览器中普遍使用之前的作用。然而,在 2.x 中,它被解释为渲染一个名称为 plastic-button 的 Vue 组件。这就阻碍了上面提到的自定义内置元素的原生用法。

在 3.0 中,我们将 Vue 对 is prop 的特殊处理限制在 <component> 标签上。

  • 当在保留的 <component> 标签上使用时,它的行为与 2.x 中完全相同。
  • 当使用在正常的组件上时,它的行为就像正常的 prop:

    1. <foo is="bar" />
    • 2.x 行为:渲染 bar 组件
    • 3.x 行为:渲染 foo 组件并传递 is prop。
  • 当在普通元素上使用时,它将作为 is 选项传递给 createElement 调用,并作为一个原生特性呈现。这支持自定义的内置元素的使用。

    1. <button is="plastic-button">Click Me!</button>
    • 2.x 行为:渲染 plastic-button 组件
    • 3.x 行为:通过调用渲染一个原生 button。
      1. document.createElement('button', { is: 'plastic-button' })

v-is 用于 In-DOM 模版解析的解决方法

注意:本节只影响 Vue 模版直接写在页面 HTML 中的情况。

当使用 DOM 内模版时,模版要遵守本地 HTML 解析规则。一些 HTML 元素,如 <ul><ol><table><select> 对其内部可以出现的元素有限制,一些元素如 <li><tr><option> 只能出现在某些其他元素的内部。

在 2.x 中,我们建议通过在原生标签上使用 is prop 来解决这些限制:

  1. <table>
  2. <tr is="blog-post-row"></tr>
  3. </table>

随着上面提出的 is 的行为变化,我们需要引入一个新的指令 v-is 来解决这些情况:

  1. <table>
  2. <tr v-is="'blog-post-row'"></tr>
  3. </table>

注意,v-is 的功能就像一个动态的 2.x :is 绑定 —— 所以要通过它的注册名称来渲染一个组件,它的值应该是一个 JavaScript 字符串字面量。

缺点

N/A

备选方案

N/A

采纳策略

  • compat 编译可以检测 config.ignoredElements 的使用,并提供适当的警告和指导。
  • codemod 可以自动将所有使用 is 的 2.x 非 <component> 标签转为 <component is>(用于 SFC 模版)或者 v-is(用于 DOM 内模版)。

没有解决的问题

N/A