Vue 3.x 中移除的 7 个功能

发布于 2024-04-05 17:15:04 字数 7813 浏览 33 评论 0

一、移除 $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')
  }
})

事件总线模式可以被替换为使用外部的、实现了事件触发器接口的库,例如 mitttiny-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 的第二个参数。

props-data 语法

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

睫毛溺水了

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

玍銹的英雄夢

文章 0 评论 0

我不会写诗

文章 0 评论 0

十六岁半

文章 0 评论 0

浸婚纱

文章 0 评论 0

qq_kJ6XkX

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文