Table of contents
1. Noteworthy new features of vue3
1.2, Vue 3 now officially supports components with multiple root nodes
1.4.2, Multiple v-model bindings
1.4.3. Dealing with v-model modifiers
2.1, Vue 2 does not have the concept of "app",
2.2, attribute mandatory behavior
2.3, attributes, contains, class and style
2.5. Custom element interaction
2.7, Mixin merge behavior change
2.8, Vue.prototype changed to config.globalProperties
2.10. Inline Template Attribute
2.13. Access this in the default function of prop
2.14.1 Render function parameters
2.14.2. Rendering function signature changes
2.16. Transitional class name change
2.17. Priority comparison between v-if and v-for
3.5. The .native modifier of v-on has been deleted.
4. Vue3 + view-ui-plus + js project upgrade
1. Noteworthy new features of vue3
1.1、Teleport
Teleport provides a way to allow us to control under which parent node in the DOM renders HTML without having to resort to global state or split it into two components.
For example, there is a modal box in a subcomponent. Its default parent set is its parent component dom, but the modal box we need is body. This is Teleport, which is a subset component that defines its parent set dom
After joining Teleport
app.component('modal-button', {
template: `
<button @click="modalOpen = true">
Open full screen modal! (With teleport!)
</button>
<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal!
(My parent is "body")
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
</teleport>
`,
data() {
return {
modalOpen: false
}
}
})
1.2, Vue 3 now officially supports components with multiple root nodes
In 2.x, since multi-root node components are not supported, a warning will be issued when the developer accidentally creates one. To fix this, many components are wrapped in one <div>
.
<template>
<div>
<header>...</header>
<main>...</main>
<footer>...</footer>
</div>
</template>
In 3.x, components can contain multiple root nodes! However, this requires the developer to explicitly define where the attribute should be distributed.
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
1.3. Custom events emits
emits
The emitted events can be defined on the component via options.
When emits
a native event (like click
) is defined in the options, the event from the component will be used instead of the native event listener.
app.component('custom-form', {
emits: {
// 没有验证
click: null,
// 验证submit 事件
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
},
methods: {
submitForm() {
this.$emit('submit', { email, password })
}
}
})
1.4、v-model
1.4.1, v-model parameter
As far as changes go, this section is high-level:
- Incompatible
v-model
: prop and event default names changed when used in custom components :- prop:
value
->modelValue
; - event:
input
->update:modelValue
;
- prop:
- Incompatible :
v-bind
The.sync
modifiers andmodel
options of components have been removed and can bev-model
used instead; - New
v-model
: Now you can use multiple two-way bindings on the same component ; - New : Modifiers can now be customized
v-model
.
v-model
By default, used on components modelValue
as props and update:modelValue
as events. We can v-model
modify these names by passing parameters to:
<my-component v-model:title="bookTitle"></my-component>
In this example, the child component will take a title
prop and emit update:title
an event to be synchronized:
app.component('my-component', {
props: {
foo: String
},
emits: ['update:title'],
template: `
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)">
`
})
1.4.2, multiple v-model
bindings
By leveraging the ability to target specific props and events, we can now create multiple v-model bindings on a single component instance.
Each v-model will sync to a different prop without adding extra options to the component:
<user-name
v-model:first-name="firstName"
v-model:last-name="lastName"
></user-name>
app.component('user-name', {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName'],
template: `
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)">
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)">
`
})
1.4.3, processing v-model
modifiers
In 2.x we had hardcoded support for the etc modifier v-model
on components. .trim
However, it would be more useful if the component could support custom modifiers. In 3.x, v-model
modifiers added to a component will modelModifiers
be made available to the component via props:
When we learned about form input bindings, we saw that v-model
there are built-in modifiers - .trim
, , .number
and .lazy
. However, in some cases you may also need to add your own custom modifiers.
For example a custom modifier capitalize
that v-model
capitalizes the first letter of the string provided by the binding.
<my-component v-model.capitalize="myText"></my-component>
1.5 Ref array in v-for
In Vue 2, the attribute v-for
used in ref
will fill the corresponding $refs
property with the ref array. v-for
This behavior becomes ambiguous and inefficient when there are nested .
In Vue 3, such usage will no longer $ref
automatically create an array in . To get multiple refs from a single binding, attach ref
the binding to a more flexible function (this is a new feature):
<div v-for="item in list" :ref="setItemRef"></div>
export default {
data() {
return {
itemRefs: []
}
},
methods: {
setItemRef(el) {
this.itemRefs.push(el)
}
},
beforeUpdate() {
this.itemRefs = []
},
updated() {
console.log(this.itemRefs)
}
}
1.6 Asynchronous components
Previously, asynchronous components were created by defining the component as a function returning a Promise, for example:
const asyncPage = () => import('./NextPage.vue')
Or, for higher order component syntax with options:
const asyncPage = {
component: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
error: ErrorComponent,
loading: LoadingComponent
}
Vue3. Grammar:
defineAsyncComponent
Now, in Vue 3, since functional components are defined as pure functions, the definition of an async component needs to be defined explicitly by wrapping it in a new helper method:
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'
// 不带选项的异步组件
const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))
// 带选项的异步组件
const asyncPageWithOptions = defineAsyncComponent({
loader: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
Another change from 2.x is that component
options are now renamed to loader
in order to accurately convey information that cannot be directly provided by a component definition.
Also, unlike 2.x, the loader function no longer takes resolve
and reject
parameters and must always return a Promise
// 2.x 版本
const oldAsyncComponent = (resolve, reject) => {
/* ... */
}
// 3.x 版本
const asyncComponent = defineAsyncComponent(
() =>
new Promise((resolve, reject) => {
/* ... */
})
)
2. Incompatible changes
2.1, Vue 2 does not have the concept of "app",
The application we define is just new Vue()
created by the root Vue instance. Every root instance created from the same Vue constructor shares the same global configuration
new Vue() 改成 createApp()
The application instance exposes a subset of the current global API. The rule of thumb is that any API that globally changes the behavior of Vue will now be moved to the application instance. Here is a table of the current global API and its corresponding instance API:
2.x Global API | 3.x instance API ( app ) |
---|---|
View.config | app.config |
Vue.config.productionTip | removed ( see below ) |
Vue.config.ignoredElements | app.config.isCustomElement ( see below ) |
Vue.component | app.component |
Directive.view | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use ( see below ) |
Vue.prototype | app.config.globalProperties ( see below ) |
All other global APIs that do not change behavior globally are now named exports
In 3.0, the check of whether an element is a component has been moved to the template compilation stage, so this configuration option is only considered when using the runtime compiler. If you are using the runtime-only version isCustomElement
it must @vue/compiler-dom
be replaced in the build step - for example, via the compilerOptions option in vue-loader (opens new window) .
- If
config.isCustomElement
when using a runtime-only build, a warning will be issued instructing the user to pass this option in the build settings; - This will be a new top-level option in the Vue CLI configuration.
2.2, attribute mandatory behavior
This is a low-level internal API change that won't affect most developers.
- Remove the internal concept of enumeration attributes and treat these attributes as ordinary non-boolean attributes
- Breaking change : attribute is no longer removed if the value is boolean
false
. Instead, it is set to attr="false". To remove attribute, usenull
orundefined
.
The following table describes how Vue 2.0 enforces "enum attributes" with normal non-boolean attributes:
binding expression | foo normal |
draggable enumerate |
---|---|---|
:attr="null" |
/ | draggable="false" |
:attr="undefined" |
/ | / |
:attr="true" |
foo="true" |
draggable="true" |
:attr="false" |
/ | draggable="false" |
:attr="0" |
foo="0" |
draggable="true" |
attr="" |
foo="" |
draggable="true" |
attr="foo" |
foo="foo" |
draggable="true" |
attr |
foo="" |
draggable="true" |
As can be seen from the above table, the current implementation true
is mandatory 'true'
, but if the attribute is false
, the attribute is removed. This also leads to inconsistencies and requires users to manually coerce boolean values to strings in very common use cases, such as aria-*
attributes like aria-selected
, aria-hidden
, etc.
The following table describes how Vue3.0 uses ordinary non-boolean
binding expression | foo normal |
draggable enumerate |
---|---|---|
:attr="null" |
/ | / † |
:attr="undefined" |
/ | / |
:attr="true" |
foo="true" |
draggable="true" |
:attr="false" |
foo="false" † |
draggable="false" |
:attr="0" |
foo="0" |
draggable="0" † |
attr="" |
foo="" |
draggable="" † |
attr="foo" |
foo="foo" |
draggable="foo" † |
attr |
foo="" |
draggable="" † |
†: Change
The coercion of Boolean attributes remains unchanged.
Comparison of 2.x and 3.x behavior
Attributes | v-bind value 2.x |
v-bind value 3.x |
HTML output |
---|---|---|---|
2.x "enum attribute" ie contenteditable , draggable and spellcheck . |
undefined , false |
undefined , null |
removed |
true , 'true' , '' , 1 , 'foo' |
true , 'true' |
"true" |
|
null , 'false' |
false , 'false' |
"false" |
|
Other non-boolean attributes eg. aria-checked , tabindex , alt , etc. |
undefined , null , false |
undefined , null |
removed |
'false' |
false , 'false' |
"false" |
2.3, attributes, contains, class and style
vue2
<my-component id="my-id" class="my-class"></my-component>
<label class="my-class">
<input type="text" id="my-id" />
</label>
vue3
<label>
<input type="text" id="my-id" class="my-class" />
</label>
So the migration may be in the wrong style
2.4. Custom commands
In Vue 2, custom directives are created by using the hooks listed below, all of which are optional
- bind - Occurs after the directive is bound to the element. Happens only once.
- inserted - Occurs after the element has been inserted into the parent DOM.
- update - 当元素更新,但子元素尚未更新时,将调用此钩子。
- componentUpdated - 一旦组件和子级被更新,就会调用这个钩子。
- unbind - 一旦指令被移除,就会调用这个钩子。也只调用一次。
下面是一个例子:
<p v-highlight="'yellow'">高亮显示此文本亮黄色</p>
Vue.directive('highlight', {
bind(el, binding, vnode) {
el.style.background = binding.value
}
})
在这里,在这个元素的初始设置中,指令通过传递一个值来绑定样式,该值可以通过应用程序更新为不同的值。
在 Vue 3 中,我们为自定义指令创建了一个更具凝聚力的 API。正如你所看到的,它们与我们的组件生命周期方法有很大的不同,即使我们正与类似的事件钩子,我们现在把它们统一起来了:
- bind → beforeMount
- inserted → mounted
- beforeUpdate:新的!这是在元素本身更新之前调用的,很像组件生命周期钩子。
- update → 移除!有太多的相似之处要更新,所以这是多余的,请改用
updated
。 - componentUpdated → updated
- beforeUnmount:新的!与组件生命周期钩子类似,它将在卸载元素之前调用。
- unbind -> unmounted
最终 API 如下:
const MyDirective = {
beforeMount(el, binding, vnode, prevVnode) {},
mounted() {},
beforeUpdate() {}, // 新
updated() {},
beforeUnmount() {}, // 新
unmounted() {}
}
生成的 API 可以这样使用,与前面的示例相同:
<p v-highlight="'yellow'">高亮显示此文本亮黄色</p>
const app = Vue.createApp({})
app.directive('highlight', {
beforeMount(el, binding, vnode) {
el.style.background = binding.value
}
})
2.5、自定义元素交互
- 非兼容:自定义元素白名单现在在模板编译期间执行,应该通过编译器选项而不是运行时配置来配置。
- 非兼容:特定
is
prop 用法仅限于保留的<component>
标记。 - 新增:有了新的
v-is
指令来支持 2.x 用例,其中在原生元素上使用了v-is
来处理原生 HTML 解析限制。
v-is
函数像一个动态的 2.x :is
绑定——因此,要按注册名称渲染组件,其值应为 JavaScript 字符串文本:
<!-- 不正确,不会渲染任何内容 -->
<tr v-is="blog-post-row"></tr>
<!-- 正确 -->
<tr v-is="'blog-post-row'"></tr>
2.6、Data 选项
- 非兼容:
data
组件选项声明不再接收纯 JavaScriptobject
,而需要function
声明。
当合并来自 mixin 或 extend 的多个 data
返回值时,现在是浅层次合并的而不是深层次合并的(只合并根级属性)
在 2.x 中,开发者可以定义 data
选项是 object
或者是 function
。
例如:
<!-- Object 声明 -->
<script>
const app = new Vue({
data: {
apiKey: 'a1b2c3'
}
})
</script>
<!-- Function 声明 -->
<script>
const app = new Vue({
data() {
return {
apiKey: 'a1b2c3'
}
}
})
</script>
虽然这对于具有共享状态的根实例提供了一些便利,但是由于只有在根实例上才有可能,这导致了混乱。
在 3.x,data
选项已标准化为只接受返回 object
的 function
。
使用上面的示例,代码只有一个可能的实现:
<script>
import { createApp } from 'vue'
createApp({
data() {
return {
apiKey: 'a1b2c3'
}
}
}).mount('#app')
</script>
2.7、Mixin 合并行为变更
此外,当来自组件的 data()
及其 mixin 或 extends 基类被合并时,现在将浅层次执行合并:
const Mixin = {
data() {
return {
user: {
name: 'Jack',
id: 1
}
}
}
}
const CompA = {
mixins: [Mixin],
data() {
return {
user: {
id: 2
}
}
}
}
在 Vue 2.x中,生成的 $data
是:
{
user: {
id: 2,
name: 'Jack'
}
}
在 3.0 中,其结果将会是:
{
user: {
id: 2
}
}
2.8、Vue.prototype
改成 config.globalProperties
在Vue 2中,Vue。prototype通常用于添加在所有组件中都可以访问的属性。
Vue 3中的等效项是config.globalproperty。这些属性将作为实例化应用程序内组件的一部分进行复制:
// before - Vue 2
Vue.prototype.$http = () => {}
// after - Vue 3
const app = Vue.createApp({})
app.config.globalProperties.$http = () => {}
2.9 、全局 API Treeshaking
如果你曾经在 Vue 中手动操作过 DOM,你可能会遇到以下模式:
import Vue from 'vue'
Vue.nextTick(() => {
// 一些和DOM有关的东西
})
在 Vue 3 中,全局和内部 API 都经过了重构,并考虑到了 tree-shaking 的支持。因此,全局 API 现在只能作为 ES 模块构建的命名导出进行访问。例如,我们之前的片段现在应该如下所示:
import { nextTick } from 'vue'
nextTick(() => {
// 一些和DOM有关的东西
})
直接调用 Vue.nextTick()
将导致臭名昭著的 undefined is not a function
错误。
通过这一更改,如果模块绑定器支持 tree-shaking,则 Vue 应用程序中未使用的全局 api 将从最终捆绑包中消除,从而获得最佳的文件大小
Vue 2.x 中的这些全局 API 受此更改的影响:
Vue.nextTick
Vue.observable
(用Vue.reactive
替换)Vue.version
Vue.compile
(仅全构建)Vue.set
(仅兼容构建)Vue.delete
(仅兼容构建)
插件中的用法
如果你的插件依赖受影响的 Vue 2.x 全局 API,例如:
const plugin = {
install: Vue => {
Vue.nextTick(() => {
// ...
})
}
}
在 Vue 3 中,必须显式导入:
import { nextTick } from 'vue'
const plugin = {
install: app => {
nextTick(() => {
// ...
})
}
}
如果使用 webpack 这样的模块捆绑包,这可能会导致 Vue 的源代码绑定到插件中,而且通常情况下,这并不是你所期望的。防止这种情况发生的一种常见做法是配置模块绑定器以将 Vue 从最终捆绑中排除。对于 webpack,你可以使用 externals (opens new window)配置选项:
// webpack.config.js
module.exports = {
/*...*/
externals: {
vue: 'Vue'
}
}
这将告诉 webpack 将 Vue 模块视为一个外部库,而不是捆绑它。
如果你选择的模块绑定器恰好是 Rollup (opens new window),你基本上可以免费获得相同的效果,因为默认情况下,Rollup 会将绝对模块 id (在我们的例子中为 'vue'
) 作为外部依赖项,而不会将它们包含在最终的 bundle 中。但是在绑定期间,它可能会发出一个“将 vue 作为外部依赖” (opens new window)警告,可使用 external
选项抑制该警告:
// rollup.config.js
export default {
/*...*/
external: ['vue']
}
2.10、内联模板 Attribute
在 2.x 中,Vue 为子组件提供了 inline-template
attribute,以便将其内部内容用作模板,而不是将其作为分发内容。 3.x将不再支持此功能。
<my-component inline-template>
<div>
<p>它们被编译为组件自己的模板</p>
<p>不是父级所包含的内容。</p>
</div>
</my-component>
2.11、key
attribute
- 新增:对于
v-if
/v-else
/v-else-if
的各分支项key
将不再是必须的,因为现在 Vue 会自动生成唯一的key
。- 非兼容:如果你手动提供
key
,那么每个分支必须使用唯一的key
。你不能通过故意使用相同的key
来强制重用分支。
- 非兼容:如果你手动提供
- 非兼容:
<template v-for>
的key
应该设置在<template>
标签上 (而不是设置在它的子节点上)。
Vue 2.x 建议在 v-if
/v-else
/v-else-if
的分支中使用 key
。
<!-- Vue 2.x -->
<div v-if="condition" key="yes">Yes</div>
<div v-else key="no">No</div>
这个示例在 Vue 3.x 中仍能正常工作。但是我们不再建议在 v-if
/v-else
/v-else-if
的分支中继续使用 key
attribute,因为没有为条件分支提供 key
时,也会自动生成唯一的 key
。
<!-- Vue 3.x -->
<div v-if="condition">Yes</div>
<div v-else>No</div>
2.12、按键修饰符
- 非兼容:不再支持使用数字 (即键码) 作为
v-on
修饰符 - 非兼容:不再支持
config.keyCodes
在 Vue 2 中,支持 keyCodes
作为修改 v-on
方法的方法。
<!-- 键码版本 -->
<input v-on:keyup.13="submit" />
<!-- 别名版本 -->
<input v-on:keyup.enter="submit" />
此外,你可以通过全局 config.keyCodes
选项。
Vue.config.keyCodes = {
f1: 112
}
<!-- 键码版本 -->
<input v-on:keyup.112="showHelpText" />
<!-- 自定别名版本 -->
<input v-on:keyup.f1="showHelpText" />
从KeyboardEvent.keyCode has been deprecated (opens new window)开始,Vue 3 继续支持这一点就不再有意义了。因此,现在建议对任何要用作修饰符的键使用 kebab-cased (短横线) 大小写名称。
<!-- Vue 3 在 v-on 上使用 按键修饰符 -->
<input v-on:keyup.delete="confirmDelete" />
因此,这意味着 config.keyCodes
现在也已弃用,不再受支持。
2.13、在 prop 的默认函数中访问this
替代方案:
-
把组件接收到的原始 prop 作为参数传递给默认函数;
-
注入 API 可以在默认函数中使用。
import { inject } from 'vue'
export default {
props: {
theme: {
default (props) {
// `props` 是传递给组件的原始值。
// 在任何类型/默认强制转换之前
// 也可以使用 `inject` 来访问注入的 property
return inject('theme', 'default-theme')
}
}
}
}
2.14、渲染函数 API
2.14.1 Render 函数参数
在 2.x 中,e render
函数将自动接收 h
函数 (它是 createElement
的常规别名) 作为参数:
// Vue 2 渲染函数示例
export default {
render(h) {
return h('div')
}
}
在 3.x 中,h
现在是全局导入的,而不是作为参数自动传递。
// Vue 3 渲染函数示例
import { h } from 'vue'
export default {
render() {
return h('div')
}
}
2.14.2、渲染函数签名更改
在 2.x 中,render
函数自动接收诸如 h
之类的参数。
// Vue 2 渲染函数示例
export default {
render(h) {
return h('div')
}
}
在 3.x 中,由于 render
函数不再接收任何参数,它将主要用于 setup()
函数内部。这还有一个好处:可以访问作用域中声明的响应式状态和函数,以及传递给 setup()
的参数。
import { h, reactive } from 'vue'
export default {
setup(props, { slots, attrs, emit }) {
const state = reactive({
count: 0
})
function increment() {
state.count++
}
// 返回render函数
return () =>
h(
'div',
{
onClick: increment
},
state.count
)
}
}
2.14.3 VNode Props 格式化
在 2.x 中,domProps
包含 VNode props 中的嵌套列表:
// 2.x
{
class: ['button', 'is-outlined'],
style: { color: '#34495E' },
attrs: { id: 'submit' },
domProps: { innerHTML: '' },
on: { click: submitForm },
key: 'submit-button'
}
在 3.x 中,整个 VNode props 结构是扁平的,使用上面的例子,下面是它现在的样子
// 3.x 语法
{
class: ['button', 'is-outlined'],
style: { color: '#34495E' },
id: 'submit',
innerHTML: '',
onClick: submitForm,
key: 'submit-button'
}
2.15、Slot 统一
this.$slots
现在将 slots 作为函数公开- 非兼容:移除
this.$scopedSlots
2.x 当使用渲染函数时,即 h
,2.x 用于在内容节点上定义 slot
data property。
// 2.x 语法
h(LayoutComponent, [
h('div', { slot: 'header' }, this.header),
h('div', { slot: 'content' }, this.content)
])
此外,在引用作用域 slot 时,可以使用以下方法引用它们:
// 2.x 语法
this.$scopedSlots.header
在 3.x 中,插槽被定义为当前节点的子对象:
// 3.x Syntax
h(LayoutComponent, {}, {
header: () => h('div', this.header),
content: () => h('div', this.content)
})
当你需要以编程方式引用作用域 slot 时,它们现在被统一到 $slots
选项中。
// 2.x 语法
this.$scopedSlots.header
// 3.x 语法
this.$slots.header
2.16、过渡的 class 名更改
过渡类名 v-enter
修改为 v-enter-from
、过渡类名 v-leave
修改为 v-leave-from
在v2.1.8版本之前, 为过渡指令提供了两个过渡类名对应初始和激活状态。
在 v2.1.8 版本中, 引入 v-enter-to
来定义 enter 或 leave 变换之间的过渡动画插帧, 为了向下兼容, 并没有变动 v-enter
类名:
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-leave,
.v-enter-to {
opacity: 1;
}
这样做会带来很多困惑, 类似 enter 和 leave 含义过于宽泛并且没有遵循类名钩子的命名约定。
为了更加明确易读,我们现在将这些初始状态重命名为:
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.v-leave-from,
.v-enter-to {
opacity: 1;
}
现在,这些状态之间的区别就清晰多了。
<transition>
组件相关属性名也发生了变化:
leave-class
已经被重命名为leave-from-class
(在渲染函数或 JSX 中可以写为:leaveFromClass
)enter-class
已经被重命名为enter-from-class
(在渲染函数或 JSX 中可以写为:enterFromClass
)
2.17、v-if 与 v-for 的优先级对比
- 非兼容:两者作用于同一个元素上时,
v-if
会拥有比v-for
更高的优先级。
2.x 版本中在一个元素上同时使用 v-if
和 v-for
时,v-for
会优先作用。
3.x 版本中 v-if
总是优先于 v-for
生效
2.18、v-bind 合并行为
- 不兼容:v-bind 的绑定顺序会影响渲染结果。
在 2.x,如果一个元素同时定义了 v-bind="object"
和一个相同的单独的 property,那么这个单独的 property 总是会覆盖 object
中的绑定。
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="red"></div>
在 3.x,如果一个元素同时定义了 v-bind="object"
和一个相同的单独的 property,那么声明绑定的顺序决定了它们如何合并。换句话说,相对于假设开发者总是希望单独的 property 覆盖 object
中定义的内容,现在开发者对自己所希望的合并行为有了更好的控制。
<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>
<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>
三、移除的属性
3.1、$children
$children实例属性已从Vue 3.0中删除,不再受支持。
#2.x语法
In 2.x, developers could use this command to access the immediate child components of the current instance. $children:
in 3. x, the $children property has been removed and is no longer supported. Instead, it is recommended to use $refs if you need to access child component instances.
<template>
<div>
<img alt="Vue logo" src="/vue3js/logo.png">
<my-button>Change logo</my-button>
</div>
</template>
<script>
import MyButton from './MyButton'
export default {
components: {
MyButton
},
mounted() {
console.log(this.$children) // [VueComponent]
}
}
</script>
3.2 , $on
, $off
and $once
instance methods have been removed, and the application instance no longer implements the event trigger interface.
3.3, filters filter delete
filters: {
currencyUSD(value) {
return '$' + value
}
}
In 3.x, the filter was removed and is no longer supported. Instead, we recommend replacing them with method calls or computed properties.
Using the example above, here's an example of how to do it.
<template>
<h1>Bank Account Balance</h1>
<p>{
{ accountInUSD }}</p>
</template>
<script>
export default {
props: {
accountBalance: {
type: Number,
required: true
}
},
computed: {
accountInUSD() {
return '$' + this.accountBalance
}
}
}
</script>
3.4、$listeners 删除
The $listeners object has been removed in Vue 3. Event listeners are now part of $attrs:
view2.x
<template>
<label>
<input type="text" v-bind="$attrs" v-on="$listeners" />
</label>
</template>
<script>
export default {
inheritAttrs: false
}
</script>
vue.3.x
<template>
<label>
<input type="text" v-bind="$attrs" />
</label>
</template>
<script>
export default {
inheritAttrs: false
}
</script>
3.5. The .native modifier of v-on has been deleted.
By default, event listeners passed to components with v-on are only triggered by emitting events with this. $emit. To add a native DOM listener to the root element of a child component, you can use the .native modifier:
<my-component
v-on:close="handleComponentEvent"
v-on:click.native="handleNativeClickEvent"
/>
The .native modifier for v-on has been removed. Also, the new emits option allows the child to define which events it does emit.
As a result, Vue now adds all event listeners that were not defined as components emitting events in the child as native event listeners to the child's root element (unless inheritAttrs:false is set in the child's options).
<my-component
v-on:close="handleComponentEvent"
v-on:click="handleNativeClickEvent"
/>
MyComponent.vue
<script>
export default {
emits: ['close']
}
</script>