|
| 1 | +--- |
| 2 | +badges: |
| 3 | + - breaking |
| 4 | +--- |
| 5 | + |
| 6 | +# attribute 强制行为 <MigrationBadges :badges="$frontmatter.badges" /> |
| 7 | + |
| 8 | +:::info 信息 |
| 9 | +这是一个底层的内部 API 更改,绝大多数开发人员不会受到影响。 |
| 10 | +::: |
| 11 | + |
| 12 | +## 概览 |
| 13 | + |
| 14 | +以下是对变化的总体概述: |
| 15 | + |
| 16 | +- 移除枚举 attribute 的内部概念,并将这些 attribute 视为普通的非布尔 attribute |
| 17 | +- **非兼容**:如果值为布尔值 `false`,则不再移除 attribute。取而代之的是,它将被设置为 attr="false"。若要移除 attribute,应该使用 `null` 或者 `undefined`。 |
| 18 | + |
| 19 | +如需更深入的解释,请继续阅读! |
| 20 | + |
| 21 | +## 2.x 语法 |
| 22 | + |
| 23 | +在 2.x,我们有以下策略来强制 `v-bind` 的值: |
| 24 | + |
| 25 | +- 对于某些 attribute/元素对,Vue 始终使用相应的 IDL attribute (property):[比如 `<input>`,`<select>`,`<progress>` 中的 `value`,等等](https://github.com/vuejs/vue/blob/bad3c326a3f8b8e0d3bcf07917dc0adf97c32351/src/platforms/web/util/attrs.js#L11-L18)。 |
| 26 | + |
| 27 | +- 对于“[布尔 attribute](https://github.com/vuejs/vue/blob/bad3c326a3f8b8e0d3bcf07917dc0adf97c32351/src/platforms/web/util/attrs.js#L33-L40)”和 [xlinks](https://github.com/vuejs/vue/blob/bad3c326a3f8b8e0d3bcf07917dc0adf97c32351/src/platforms/web/util/attrs.js#L44-L46),如果它们是 `falsy` ([`undefined`,`null` 或 `false`](https://github.com/vuejs/vue/blob/bad3c326a3f8b8e0d3bcf07917dc0adf97c32351/src/platforms/web/util/attrs.js#L52-L54)) 的,Vue 会移除它们,否则会加上。(见[这里](https://github.com/vuejs/vue/blob/bad3c326a3f8b8e0d3bcf07917dc0adf97c32351/src/platforms/web/runtime/modules/attrs.js#L66-L77)和[这里](https://github.com/vuejs/vue/blob/bad3c326a3f8b8e0d3bcf07917dc0adf97c32351/src/platforms/web/runtime/modules/attrs.js#L81-L85))。 |
| 28 | + |
| 29 | +- 对于“[枚举 attribute](https://github.com/vuejs/vue/blob/bad3c326a3f8b8e0d3bcf07917dc0adf97c32351/src/platforms/web/util/attrs.js#L20)” (目前来说包括 `contenteditable`、`draggable` 和 `spellcheck`),Vue 会尝试将它们[强制](https://github.com/vuejs/vue/blob/bad3c326a3f8b8e0d3bcf07917dc0adf97c32351/src/platforms/web/util/attrs.js#L24-L31)转换为字符串 (目前对 `contenteditable` 做了特殊处理,以修复 [vuejs/vue#9397](https://github.com/vuejs/vue/issues/9397))。 |
| 30 | + |
| 31 | +- 对于其他 attribute,我们将移除 `falsy` 的值 (`undefined`,`null`,或 `false`),其他值按原样设置 (见[这里](https://github.com/vuejs/vue/blob/bad3c326a3f8b8e0d3bcf07917dc0adf97c32351/src/platforms/web/runtime/modules/attrs.js#L92-L113))。 |
| 32 | + |
| 33 | +下表描述了 Vue 如何强制转换“枚举 attribute”,以及与普通非布尔 attribute 的不同之处: |
| 34 | + |
| 35 | +| 绑定表达式 | `foo` <sup>正常</sup> | `draggable` <sup>枚举</sup> | |
| 36 | +| ------------------- | ----------------------- | --------------------------------- | |
| 37 | +| `:attr="null"` | - | `draggable="false"` | |
| 38 | +| `:attr="undefined"` | - | - | |
| 39 | +| `:attr="true"` | `foo="true"` | `draggable="true"` | |
| 40 | +| `:attr="false"` | - | `draggable="false"` | |
| 41 | +| `:attr="0"` | `foo="0"` | `draggable="true"` | |
| 42 | +| `attr=""` | `foo=""` | `draggable="true"` | |
| 43 | +| `attr="foo"` | `foo="foo"` | `draggable="true"` | |
| 44 | +| `attr` | `foo=""` | `draggable="true"` | |
| 45 | + |
| 46 | + |
| 47 | +从上表可以看出,当前实现将 `true` 强制转换为了 `'true'`,但如果 attribute 为 `false`,则将其移除。这也导致了不一致性,并要求用户在非常常见的用例中手动将布尔值强制转换为字符串,例如 |
| 48 | + `aria-*` attribute,例如 `aria-selected`、`aria-hidden` 等等。 |
| 49 | + |
| 50 | +## 3.x 语法 |
| 51 | + |
| 52 | +我们打算放弃“枚举型 attribute”的内部概念,并将它们视为普通的非布尔型 HTML attribute。 |
| 53 | + |
| 54 | +- 这就解决了普通非布尔型 attribute 和“枚举型 attribute”之间的不一致性问题 |
| 55 | +- 这个改动还使得对于诸如 `contenteditable` 这样的 attribute,我们可以使用 `'true'` 和 `'false'` 以外的值,甚至是未来新增的关键字。 |
| 56 | + |
| 57 | +对于非布尔型 attribute,如果其值为 `false`,Vue 将不再移除它们,而是将其强制转换为 `'false'`。 |
| 58 | + |
| 59 | +- 这就解决了 `true` 和 `false` 之间的不一致性,并更易于输出 `aria-*` attribute |
| 60 | + |
| 61 | +下表描述了新的行为: |
| 62 | + |
| 63 | +| 绑定表达式 | `foo` <sup>正常</sup> | `draggable` <sup>枚举</sup> | |
| 64 | +| ------------------- | -------------------------- | --------------------------------- | |
| 65 | +| `:attr="null"` | - | - <sup>*</sup> | |
| 66 | +| `:attr="undefined"` | - | - | |
| 67 | +| `:attr="true"` | `foo="true"` | `draggable="true"` | |
| 68 | +| `:attr="false"` | `foo="false"` <sup>*</sup> | `draggable="false"` | |
| 69 | +| `:attr="0"` | `foo="0"` | `draggable="0"` <sup>*</sup> | |
| 70 | +| `attr=""` | `foo=""` | `draggable=""` <sup>*</sup> | |
| 71 | +| `attr="foo"` | `foo="foo"` | `draggable="foo"` <sup>*</sup> | |
| 72 | +| `attr` | `foo=""` | `draggable=""` <sup>*</sup> | |
| 73 | + |
| 74 | +<small>*:已改变</small> |
| 75 | + |
| 76 | +布尔型 attribute 的强制转换保持不变。 |
| 77 | + |
| 78 | +## 迁移策略 |
| 79 | + |
| 80 | +### 枚举 attribute |
| 81 | + |
| 82 | +枚举 attribute 如果不存在,可能会和 `attr="false"` 会产生不同的 IDL attribute 值 (将反映实际状态),描述如下: |
| 83 | + |
| 84 | +| 不存在的枚举 attr | IDL attr & 值 | |
| 85 | +| ---------------------- | ------------------------------------ | |
| 86 | +| `contenteditable` | `contentEditable` → `'inherit'` | |
| 87 | +| `draggable` | `draggable` → `false` | |
| 88 | +| `spellcheck` | `spellcheck` → `true` | |
| 89 | + |
| 90 | +对于“枚举 attribute”,由于我们不再把 `null` 转换为 `'false'`,在 3.x 中,对于 `contenteditable` 和 `spellcheck`,开发者需要将原来解析为 `null` 的 `v-bind` 表达式变更为 `false` 或 `'false'` 才能保持和 2.x 中的行为一致。 |
| 91 | + |
| 92 | +在 2.x 中,枚举 attribute 的无效值将被强制转换为 `'true'`。这通常是不符合预期的,所以该行为不太可能被大规模依赖。在 3.x 中,应显式指定 `true` 或 `'true'`。 |
| 93 | + |
| 94 | +### 将 `false` 强制转换为 `'false'` 而不是移除 attribute |
| 95 | + |
| 96 | +在 3.x 中,应该使用 `null` 或 `undefined` 以显式移除 attribute。 |
| 97 | + |
| 98 | +### 2.x 和 3.x 行为的比较 |
| 99 | + |
| 100 | +<table> |
| 101 | + <thead> |
| 102 | + <tr> |
| 103 | + <th>Attributes</th> |
| 104 | + <th><code>v-bind</code> 的值 <sup>2.x</sup></th> |
| 105 | + <th><code>v-bind</code> 的值 <sup>3.x</sup></th> |
| 106 | + <th>HTML 输出</th> |
| 107 | + </tr> |
| 108 | + </thead> |
| 109 | + <tbody> |
| 110 | + <tr> |
| 111 | + <td rowspan="3">2.x “枚举 attribute”<br><small>即 <code>contenteditable</code>、<code>draggable</code> 与 <code>spellcheck</code>。</small></td> |
| 112 | + <td><code>undefined</code></td> |
| 113 | + <td><code>undefined</code>, <code>null</code></td> |
| 114 | + <td><i>被移除</i></td> |
| 115 | + </tr> |
| 116 | + <tr> |
| 117 | + <td> |
| 118 | + <code>true</code>, <code>'true'</code>, <code>''</code>, <code>1</code>, |
| 119 | + <code>'foo'</code> |
| 120 | + </td> |
| 121 | + <td><code>true</code>, <code>'true'</code></td> |
| 122 | + <td><code>"true"</code></td> |
| 123 | + </tr> |
| 124 | + <tr> |
| 125 | + <td><code>null</code>, <code>false</code>, <code>'false'</code></td> |
| 126 | + <td><code>false</code>, <code>'false'</code></td> |
| 127 | + <td><code>"false"</code></td> |
| 128 | + </tr> |
| 129 | + <tr> |
| 130 | + <td rowspan="2">其他非布尔 attribute<br><small>如 <code>aria-checked</code>、<code>tabindex</code>、<code>alt</code> 等等。</small></td> |
| 131 | + <td><code>undefined</code>, <code>null</code>, <code>false</code></td> |
| 132 | + <td><code>undefined</code>, <code>null</code></td> |
| 133 | + <td><i>被移除</i></td> |
| 134 | + </tr> |
| 135 | + <tr> |
| 136 | + <td><code>'false'</code></td> |
| 137 | + <td><code>false</code>, <code>'false'</code></td> |
| 138 | + <td><code>"false"</code></td> |
| 139 | + </tr> |
| 140 | + </tbody> |
| 141 | +</table> |
| 142 | + |
| 143 | +[迁移构建开关:](migration-build.html#兼容性配置) |
| 144 | + |
| 145 | +- `ATTR_FALSE_VALUE` |
| 146 | +- `ATTR_ENUMERATED_COERCION` |
0 commit comments