添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

使用时总是需要携带上变量名 props

vue3.3 中,可以对 props 进行解构并且不失去其响应性

const { name = '默认名称' } = defineProps({
  name: {
    type: string

我个人还是很喜欢这个新特性的

2、defineEmit的改进

vue3.2版本中,defineEmit需要这么定义:

const emits = defineEmits<{
  (e: 'search', query: string): void
  (e: 'handleUser', id: string): void

看着就很丑陋,在vue3.3中,简化了emit事件的写法:

const emits = defineEmits<{
  search: [query: string]
  handleUser: [id: string]

注意:原本这种调用签名的语法写法仍然支持

3、新增宏 defineOptions

以前在禁止组件继承没被自身接受的props时,需要新增一个单独的<script>标签

<script lang="ts">
export default {
  inheritAttrs: false
<script>
<script setup lang="ts">
<script>

现在可以使用defineOptions,无需新增一个<script>

<script setup lang="ts">
defineOptions<{
  // 指定不继承哪些属性
  name: "name1",
	age: 'age1'
  inheritAttrs: false
<script>

4、新增宏 defineModel

在以前,如果使用v-model支持双向绑定组件时,通常时需要propsemit配合,在监听数据变化 emit一个事件

子组件ChildrenInput

const props = defineProps(['modelValue'])  // 接收props
const value = computed({
  get() {
    return props.modelValue
  set(val) {
    emits('update:modelValue', val)  // 监听到数据变化emit变化的数据
<template>
  <input v-model="value" />
</template>
const modelValue = ref('')
<template>
  <ChildrenInput v-model="modelValue" />
</template>

其中,子组件在实现双向绑定上,略微繁琐,vue3.3中就新增了一个宏:defineModel

  • 代替子组件接收并监听props最后emit这一步操作
  • 子组件ChildrenInput

    const value = defineModel('')  // defineModel宏
    <template>
      <input v-model="value" />
    </template>

    编译时,defineModel将声明一个具有相同名称的 prop和一个相应的 update:propName 事件

    const modelValue = ref('')
    <template>
      <ChildrenInput v-model="modelValue" />
      <h1>{{ modelValue  }}</h1>
    </template>

    注意:defineModel目前还是一个实用性的功能,需要手动开启

  • vue3.3+
  • @vitejs/plugin-vue@^4.2.0vite@^4.3.5
  • vue-loader@^17.1.0(如果使用 webpack 或 vue-cli)
  • vite中的配置:

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    export default defineConfig({
      plugins: [vue({
        script: {  
            defineModel: true  // 开启defineModel
    

    vue-cli

    // vue.config.js
    module.exports = {
      chainWebpack: (config) => {
        config.module
          .rule('vue')
          .use('vue-loader')
          .tap((options) => {
            return {
              ...options,
              defineModel: true
    

    5、toReftoValue

    5.1 toRef

    toRef的作用是用于提取响应式对象的属性,将其变成ref

    import { reactive, toRef } from 'vue'
    const obj = reactive({
    const aRef = toRef(obj, 'a')

    无论通过obj.a更改值还是aRef.value取更改值,objaRef都可以进行响应式变化,这就是toRef的用法

    现在,toRef支持只接受一个参数,并且会转换成一个getter,与computed的区别就是它没有setter

    toRef(1)
    toRef(() => props.foo)
    toRef(ref(1))

    它最终得到的是一个响应式的只读ref

    const obj = reactive({
    const aRef = toRef(() => obj.a)

    obj.a变化时,aRef也会变化

  • 减少不必要的性能开销,相比于computed,因为它无需设置setter,因为它是只读的
  • 适用于需要实时获取响应式数据,又无需更改该数据的场景(代替computed):

        1.实时获取prop

    const name = toRef(() => props.name)

        2. 获取路由paramsquery

    const id = toRef(() => route.params.id)

    总之,将对象属性转化成ref,推荐使用最新语法toRef(() => object.key)

    5.2 toValue

    新增的toValue是将valuegetterref转化成值:

    toValue(1)  //  1 
    toValue(ref(1))  //  1
    toValue(() => 1)  //  1

    toValuetoRef基本是一个相反的结果,返回是一个非响应性的普通数据

    源码的实现:

    function unref(ref2) {
      return isRef(ref2) ? ref2.value : ref2;
    function toValue(source) {
      return isFunction(source) ? source() : unref(source);
    

    6、props支持外部导入

    <script setup lang="ts">
    import type { Props } from './foo'
    // imported + intersection type
    defineProps<Props & { extraProp?: string }>()
    </script>

    7、通用组件

    <script setup lang="ts" generic="T">
      defineProps<{
        items: T[]
        selected: T
    </script>
    <Conponment1 :items="[1, 2, 3]" :selected="1">
    <Conponment1 :items="[true, false]" :selected="true">

    还可以使用多个类型、约束等

    参考文献:

  • https://blog.vuejs.org/posts/vue-3-3
  • https://github.com/vuejs/core/pull/7997
  • https://advanced-inertia.com/blog/vue-3-3
  •