Vue 3.x 中移除的 7 个功能
一、移除 $children
Vue 2.x
在 2.x 中,开发者可以使用 this.$children
访问当前实例的直接子组件
<template>
<div>
<my-button></my-button>
</div>
</template>
<script>
import MyButton from './MyButton'
export default {
components: {
MyButton
},
mounted() {
console.log(this.$children) // [VueComponent]
}
}
</script>
Vue 3.x
在 3.x 中,使用 $refs 访问子组件
二、移除 $listeners
Vue 2.x
通过 this.$attrs
访问传递给组件的 attribute,以及通过 this.$listeners
访问传递给组件的事件监听器。结合 inheritAttrs: false
,开发者可以将这些 attribute 和监听器应用到根元素之外的其它元素:
<template>
<label>
<input type="text" v-bind="$attrs" v-on="$listeners" />
</label>
</template>
<script>
export default {
inheritAttrs: false
}
</script>
Vue 3.x
在 Vue 3 的虚拟 DOM 中,事件监听器现在只是以 on
为前缀的 attribute,这样它就成为了 $attrs
对象的一部分,因此 $listeners
被移除了。
<template>
<label>
<input type="text" v-bind="$attrs" />
</label>
</template>
<script>
export default {
inheritAttrs: false
}
</script>
三、移除 v-on.native
修饰符
Vue 2.x
默认情况下,传递给带有 v-on
的组件的事件监听器只能通过 this.$emit
触发。要将原生 DOM 监听器添加到子组件的根元素中,可以使用 .native
修饰符:
<my-component
v-on:close="handleComponentEvent"
v-on:click.native="handleNativeClickEvent"
/>
Vue 3.x
v-on
的 .native
修饰符已被移除。同时, 新增的 emits
选项 允许子组件定义真正会被触发的事件。
因此,对于子组件中未被定义为组件触发的所有事件监听器,Vue 现在将把它们作为原生事件监听器添加到子组件的根元素中 (除非在子组件的选项中设置了 inheritAttrs: false
)。
<my-component
v-on:close="handleComponentEvent"
v-on:click="handleNativeClickEvent"
/>
MyComponent.vue
<script>
export default {
emits: ['close']
}
</script>
四、移除$on,$off 和 $once
$on
, $off
和 $once
实例方法已被移除,组件实例不再实现事件触发接口,包括事件总线(组件实例,其用到的设计模式是发布订阅模式)。
- 静态的事件监听器可以通过 prop 的形式传递给
createApp
以添加到根组件中。
createApp(App, {
// 监听 'expand' 事件
onExpand() {
console.log('expand')
}
})
事件总线模式可以被替换为使用外部的、实现了事件触发器接口的库,例如 mitt 或 tiny-emitter 。
示例:
// eventBus.js
import emitter from 'tiny-emitter/instance'
export default {
$on: (...args) => emitter.on(...args),
$once: (...args) => emitter.once(...args),
$off: (...args) => emitter.off(...args),
$emit: (...args) => emitter.emit(...args),
}
它提供了与 Vue 2 相同的事件触发器 API。
在绝大多数情况下,不鼓励使用全局的事件总线在组件之间进行通信。虽然在短期内往往是最简单的解决方案,但从长期来看,它维护起来总是令人头疼。根据具体情况来看,有多种事件总线的替代方案:
- Prop 和 事件 应该是父子组件之间沟通的首选。兄弟节点可以通过它们的父节点通信。
- Provide 和 inject 允许一个组件与它的插槽内容进行通信。这对于总是一起使用的紧密耦合的组件非常有用。
provide
/inject
也能够用于组件之间的远距离通信。它可以帮助避免“prop 逐级透传”,即 prop 需要通过许多层级的组件传递下去,但这些组件本身可能并不需要那些 prop。- Prop 逐级透传也可以通过重构以使用插槽来避免。如果一个中间组件不需要某些 prop,那么表明它可能存在关注点分离的问题。在该类组件中使用 slot 可以允许父节点直接为它创建内容,因此 prop 可以被直接传递而不需要中间组件的参与。
- 全局状态管理 ,比如 Vuex 。
自定义发布订阅模式
type BusClass<T> = {
emit: (name: T) => void
on: (name: T, callback: Function) => void
}
type BusParams = string | number | symbol
type List = {
[key: BusParams]: Array<Function>
}
class Bus<T extends BusParams> implements BusClass<T> {
list: List
constructor() {
this.list = {}
}
emit(name: T, ...args: Array<any>) {
let eventName: Array<Function> = this.list[name]
eventName.forEach(ev => {
ev.apply(this, args)
})
}
on(name: T, callback: Function) {
let fn: Array<Function> = this.list[name] || [];
fn.push(callback)
this.list[name] = fn
}
}
export default new Bus<number>()
使用第三方库 mitt
在 main.ts
中申明
import { createApp } from 'vue'
import App from './App.vue'
import mitt from 'mitt'
const Mitt = mitt();
// TypeScript 注册
// 必须要扩展 ComponentCustomProperties 类型才能获得类型提示
declare module "vue" {
export interface ComponentCustomProperties {
$Bus: typeof mitt // 拿到所有 mitt 中的类型
}
}
const app = createApp(App);
// vue3 挂载全局 API
app.config.globalProperties.$Bus = Mitt;
app.mount('#app')
五、移除 过滤器 filters
在 3.x 中,过滤器已移除,建议用方法调用或计算属性来替换它们。
如果在应用中全局注册了过滤器,那么在每个组件中用计算属性或方法调用来替换它可能就没那么方便了。
取而代之的是,你可以通过 全局属性 以让它能够被所有组件使用到:
// main.js
const app = createApp(App)
app.config.globalProperties.$filters = {
currencyUSD(value) {
return '$' + value
}
}
然后,可以通过这个 $filters
对象修正所有的模板,就像这样:
<template>
<h1>Bank Account Balance</h1>
<p>{{ $filters.currencyUSD(accountBalance) }}</p>
</template>
注意,这种方式只适用于方法,而不适用于计算属性,因为后者只有在单个组件的上下文中定义时才有意义。
六、移除 inline-template
内联模板 Attribute
Vue 2.x
在 2.x 中,Vue 为子组件提供了 inline-template
attribute,以便将其内部内容作为模板使用,而不是作为分发内容。
<my-component inline-template>
<div>
<p>它们将被编译为组件自己的模板,</p>
<p>而不是父级所包含的内容。</p>
</div>
</my-component>
Vue 3.x
将不再支持此功能。
七、移除 propsData
propsData
选项用于在创建 Vue 实例的过程中传入 prop,现在它被移除了。如果想为 Vue 3 应用的根组件传入 prop,请使用 createApp 的第二个参数。
Vue 2.x
在创建 Vue 实例的时候传入 prop:
const Comp = Vue.extend({
props: ['username'],
template: '<div>{{ username }}</div>'
})
new Comp({
propsData: {
username: 'Evan'
}
})
Vue 3.x
propsData
选项已经被移除。如果你需要在实例创建时向根组件传入 prop,你应该使用 createApp
的第二个参数:
const app = createApp(
{
props: ['username'],
template: '<div>{{ username }}</div>'
},
{ username: 'Evan' }
)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论