Vue 3.x

127 阅读3分钟

基础

多事件处理器

<!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
<button @click="one($event), two($event)">
  Submit
</button>
// ...
methods: {
  one(event) {
    // 第一个事件处理器逻辑...
  },
  two(event) {
   // 第二个事件处理器逻辑...
  }
}

深入组件

组件中使用v-model

v-bind.sync 已 改为 v-model.modelValue

默认情况下,组件上的 v-model 使用 modelValue 作为 prop 和 update:modelValue 作为事件。我们可以通过向 v-model 传递参数来修改这些名称:

在本例中,子组件将需要一个 title prop 并发出 update:title 要同步的事件:

<my-component v-model:title="bookTitle"></my-component>
app.component('my-component', {
  props: {
    title: String
  },
  emits: ['update:title'],
  template: `
    <input
      type="text"
      :value="title"
      @input="$emit('update:title', $event.target.value)">
  `
})

//对于所有不带参数的 v-model,请确保分别将 prop 和 event 命名更改为 modelValue 和 update:modelValue // 以前是 this.$emit('input', title)

<my-component v-model="bookTitle"></my-component>
app.component('my-component', {
  props: {
    modelValue: String
  },
  emits: ['update:modelValue'],
  template: `
    <input
      type="text"
      :value="title"
      @input="this.$emit('update:modelValue', title) ">
  `
})

多个 v-model 绑定

此用法可绑定多个modelValue

动态组件

我们之前曾经在一个多标签的界面中使用 is attribute 来切换不同的组件:

<component :is="currentTabComponent"></component>

currentTabComponent为组件名 点击切换显示不同组件

v-is 用于 DOM 内模板解析解决方案

<table>
  <tr v-is="'blog-post-row'"></tr>
</table>

在 Vue 3.x 中 key 则应该被设置在 <template> 标签上。

v-if 与 v-for 的优先级对比

3.x 版本中 v-if 总是优先于 v-for 生效。

v-bind 合并行为

v-bind="object" 现在排序敏感

<!-- template -->
<div id="div-id" v-bind="{id: 'the-id', class: 'the-class'}">the-box</div>
在2.x 中 总是保留元素本身的attribute 
<!-- result -->
<div id="div-id" class: 'the-class'></div> 
3.x 语法
<!-- result -->
<div id="the-id" class: 'the-class'></div> 

v-cloak

  • 不需要表达式

  • 用法

    这个指令保持在元素上直到关联组件实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到组件实例准备完毕。

  • 示例

    [v-cloak] {
      display: none;
    }
    
    <div v-cloak>
      {{ message }}
    </div>
    

    不会显示,直到编译结束。

异步组件

2.x 语法

const AsyncComponent = () => ({
  // 需要加载的组件 (应该是一个 `Promise` 对象)
  component: import('./MyComponent.vue'),
  // 异步组件加载时使用的组件
  loading: LoadingComponent,
  // 加载失败时使用的组件
  error: ErrorComponent,
  // 展示加载时组件的延时时间。默认值是 200 (毫秒)
  delay: 200,
  // 如果提供了超时时间且组件加载也超时了,
  // 则使用加载失败时使用的组件。默认值是:`Infinity`
  timeout: 3000
})

异步组件现在需要 defineAsyncComponent 方法来创建

3.x 语法

import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'// 不带选项的异步组件
const asyncModal = defineAsyncComponent(() => import('./Modal.vue'))
​
// 带选项的异步组件
const asyncModalWithOptions = defineAsyncComponent({
  `loader: () => import('./Modal.vue')`,
  delay: 200,
  timeout: 3000,
  errorComponent: ErrorComponent,
  loadingComponent: LoadingComponent
})

对 2.x 所做的另一个更改是,component 选项现在被重命名为 loader,以便准确地传达不能直接提供组件定义的信息。

全局API

Vue.prototype 替换为 config.globalProperties
// 之前 - Vue 2
Vue.prototype.$http = () => {}
​
// 之后 - Vue 3
const app = createApp({})
app.config.globalProperties.$http = () => {}

渲染函数 API

点击查看 渲染函数 API 改变

定制内置元素(is)

对特殊的 is prop 的使用只严格限制在被保留的 <component> 标记中

<component :is="currentView"></component>
<tr is="vue:blog-post-row"></tr>

v-is

已在 3.1.0 中被废弃。请换用带有 vue 前缀的 is attribute

getCurrentInstance

getCurrentInstance 支持访问内部组件实例。

WARNING

getCurrentInstance 只暴露给高阶使用场景,典型的比如在库中。强烈反对在应用的代码中使用 getCurrentInstance。请不要把它当作在组合式 API 中获取 this 的替代方案来使用。

import { getCurrentInstance } from 'vue'const MyComponent = {
  setup() {
    const internalInstance = getCurrentInstance()
​
    internalInstance.appContext.config.globalProperties // 访问 globalProperties
  }
}

getCurrentInstance 只能setup生命周期钩子中调用。

如需在 setup生命周期钩子外使用,请先在 setup 中调用 getCurrentInstance() 获取该实例然后再使用。

const MyComponent = {
  setup() {
    const internalInstance = getCurrentInstance() // 有效
​
    const id = useComponentId() // 有效
​
    const handleClick = () => {
      getCurrentInstance() // 无效
      useComponentId() // 无效
​
      internalInstance // 有效
    }
​
    onMounted(() => {
      getCurrentInstance() // 有效
    })
​
    return () =>
      h(
        'button',
        {
          onClick: handleClick
        },
        `uid: ${id}`
      )
  }
}
​
// 在组合式函数中调用也可以正常执行
function useComponentId() {
  return getCurrentInstance().uid
}

expose 3.2+

  • 类型: Array<string>

  • 详细:

    一个将暴露在公共组件实例上的 property 列表。

    默认情况下,通过 $refs$parent$root 访问到的公共实例与模板使用的组件内部实例是一样的。expose 选项将限制公共实例可以访问的 property。

    由 Vue 自身定义的 property,比如 $el$parent,将始终可以被公共实例访问,并不需要列出。

  • 用法:

    export default {
      // increment 将被暴露,
      // 但 count 只能被内部访问
      expose: ['increment'],
    ​
      data() {
        return {
          count: 0
        }
      },
    ​
      methods: {
        increment() {
          this.count++
        }
      }
    }
    

propsData

propsData 选项

2.x 语法

在 2.x,我们可以在创建 Vue 实例的时候传入 prop:

const Comp = Vue.extend({
  props: ['username'],
  template: '<div>{{ username }}</div>'
})
​
new Comp({
  propsData: {
    username: 'Evan'
  }
})

3.x 更新

propsData 选项已经被移除。如果你需要在实例创建时向根组件传入 prop,你应该使用 createApp 的第二个参数:

const app = createApp(
  {
    props: ['username'],
    template: '<div>{{ username }}</div>'
  },
  { username: 'Evan' }
)