分类: vue | 标签: vue

vue3.2新特性笔记

发表于: 2022-12-09 21:20:28 | 字数统计: 2.8k | 阅读时长预计: 13分钟

vue3.2视频教程

script setup基本语法

要使用这个语法,需要将 setup 属性添加到 <script> 代码块上:

里面的代码会被编译成组件setup() 函数的内容。

这也就意味着与普通的 <script> 只在组件被首次引入的时候仅执行一次不同<script setup> 中的代码会在每次组件实例被创建的时候执行。这一点非常的重要,也就是写在<script setup> 中的代码,例如初始化的赋值等在组件每次实例创建时都重新执行一次。

<script setup>
const a = ref(1);
console.log('hello script setup')
</script>

当使用 <script setup> 的时候,任何在<script setup> 声明的顶层的绑定 (包括声明的变量函数声明,以及 import 引入的内容) 都能在模板中直接使用,不再需要使用 return 导出。

script setup新特性

自动组件名推断

在 vue2.x options API 和使用普通的 <script> 的情况下,都可以为组件进行命名

但是在 <script setup> 下,却并没有提供直接的方式来设置的组件的名称,因此,vue 在上述情况下会依据它的文件名来自动推断组件名称。

例如:名为 Foo.vue 的文件可以在模板中用 <Foo/> 引用它自己,在 devtools 中看到的组件名称也是 Foo

使用 <script setup> 的情况下如何修改注册组件名呢??===>使用script

<script lang="ts">
export default { name: 'CustomComponentsName' }
</script>

<script setup lang="ts">
// code
</script>

<template>
    <p>利用 script 自定义组件名称</p>
</template>

普通组件

<script setup> 中引入组件后可直接在模板使用,不再需要注册了。

<script setup lang='ts'>
import SaySomething from "./Components/SaySomething.vue";
</script>

<template>
  <SaySomething />
</template>

动态组件

动态组件仍然是使用 is,相对于 vue2.x 没有变化

<script setup lang='ts'>
import { ref } from "vue";
import Bar from "./Components/Bar.vue";
import Foo from "./Components/Foo.vue";

const condition = ref(false);
setTimeout(() => condition.value = true, 2000);
</script>

<template>
  <component :is="condition ? Bar : Foo"/>
</template>

递归组件

因为自动组件名推断的缘故,一个单文件组件可以通过它的文件名被其自己所引用。例如:名为 Foo.vue 的组件可以在其模板中用 <Foo/> 引用它自己。

请注意这种方式相比于 import 导入的组件和自主注册的组件优先级更低。所有如果有命名的 import 导入和组件的推断名冲突了,可以使用 import 别名导入:

import { Foo as FooChild } from './components'

命名空间组件

可以使用带点的组件标记,例如 <Foo.Bar> 来引用嵌套在对象属性中的组件。这在需要从单个文件中导入多个组件的时候非常有用:

Components/index.ts 用于导出组件

import Foo from './Foo.vue';
import Bar from './Bar.vue';

export { Foo, Bar };

index.vue 基于命名空间使用组件

<script setup lang='ts'>
import * as Form from "../Components";
</script>

<template>
  <Form.Foo />
  <Form.Bar />
</template>

props的使用

接受父组件传递过来的属性

definedProps

为了在<script setup> 中 声明 props ,必须使用 defineProps API,这是一个宏命令,不需要导入,直接可在<script setup> 使用且只能在 <script setup> 中使用,有两种方式可以使用这个宏命令类声明 props,运行时声明类型声明式,不同的方式下使用这个宏命令后 props 将具备不同的类型推断。

  • 使用运行时声明(runtime declaration)

defineProps 运行时声明的基本用法如下,仅支持运行时的校验和vue2类似

<script setup lang='ts'>
const props = defineProps({
    foo: String,
    bar: {
      type: Number,
      required: true
    }
})
</script>
  • 类型声明(type declaration)

defineProps 类型声明的基本用法如下,完美的支持 IDE 的类型推断和检查。推荐这种方式

<script setup lang='ts'>
const props = defineProps<{
  foo?: string  //?表示可选,不带?表示必传
  bar: number
}>()
</script>

运行时声明和类型声明的比较

类型优势劣势
运行时声明不使用 ts 的情况下能够对 props 进行一定的、运行时的类型校验1. 运行时校验2. 只能进行基本类型的校验3. 编码时无任何提示
类型声明完美的支持类型的校验,包括props 的完美类型约束、父组件在传 props 时的提示以及子组件在使用 props 的提示目前 ts 的接口暂时只支持写在本组件的文件内,未来应该会实现可从外部导入的,但目前可通过ts自动扫描types来解决

widthDefaults

defineProps 使用类型声明时的不足之处在于,它没有可以给 props 提供默认值的方式。为了解决这个问题,提供了 withDefaults 宏命令。

<script setup lang="ts">
const props = withDefaults(defineProps<{
  title?: string,
  list?: List.Basic[],
}>(), {
  title: 'Hello withDefaults',
  list: () => [{ id: 3, content: '3', isDone: false }],
});
</script>

注意:widthDefaults 是为了给 defineProps 使用类型声明时提供添加默认值的的方法,因此,需要注意这仅仅适用于 <script setup lang='ts'>defineProps 使用类型声明。

自定义事件-defineEmits

<script setup> 中 声明 emit ,必须使用 defineEmits API,这也是一个宏命令。同样可采用运行时声明和类型声明式两种方式,在类型声明下 emit 将具备完美的类型推断。

  • 运行时声明
<script setup lang="ts">
// 这样是没有任何的类型检查的
const emit = defineEmits(['handleClick', 'handleChange']);

const handleClick = () => emit('handleClick', Date.now()+'');
const handleChange = () => emit('handleChange', Date.now());
</script>
  • 类型声明
<script setup lang="ts">
interface Click {
  id: string,
  val: number,
}
// 完美的类型检查
// List.Basic 是基于 ts 自动扫描 types 文件夹以及 delcare namespace 自动导入的
const emit = defineEmits<{
  (e: 'handleClickWithTypeDeclaration', data: Click): void,
  (e: 'handleChangeWithTypeDeclaration', data: List.Basic): void,
}>();

const handleClickWithTypeDeclaration = () => emit('handleClickWithTypeDeclaration', { id: '1', val: Date.now() });
const handleChangeWithTypeDeclaration = () => emit('handleChangeWithTypeDeclaration', {
  id: 1,
  content: 'change',
  isDone: false,
});
</script>

defineProps 一样,运行时声明和类型声明式同样不可同时使用,且类型声明只能用于在 ts 环境下。

显示的暴露-defineExpose

官方文档指出默认情况下使用 <script setup> 的组件是默认关闭的,也就是说通过模板 ref 或者 $parent 链获取到的子组件的实例,并不会暴露任何在<script setup> 中声明的绑定(变量,函数)。

为了在<script setup> 组件中明确要暴露出去的属性,那么就需要使用 defineExpose 这个宏命令。

<script setup>
import { ref } from 'vue'

const a = 1
const b = ref(2)

defineExpose({
  a,
  b
})
</script>

当父组件通过模板 ref 的方式获取到当前子组件的实例,获取到的实例会像这样 { a: number, b: number } (ref 会和在普通实例中一样被自动解包)

useSlots 和 useAttrs

<script setup> 使用 slotsattrs 获取插槽和兜底属性,可以用 useSlotsuseAttrs 两个函数

<script setup lang="ts">
import { useSlots, useAttrs } from "vue";

const slot = useSlots();
console.log('TestUseSlots', slot.header && slot.header());        // 获取到使用插槽的具体信息
  
const attrs = useAttrs();
console.log('TestUseAttrs', attrs);        // 获取到使用组件时传递的 attributes
</script>

<template>
  <h1> Here is slots test!!</h1>
  <slot name="header"></slot>
</template>

useSlotsuseAttrs 是真实的运行时函数,它会返回与 setupContext.slotssetupContext.attrs 等价的值,同样也能在普通的 composition API 中使用。

与普通的script一起使用

<script setup> 可以和普通的 <script> 一起使用。普通的 <script>在有这些需要的情况下或许会被使用到:

  • 无法在<script setup>声明的选项,例如 inheritAttrs 或通过插件启用的自定义的选项。
  • 显示定义组件的名称。
  • 运行副作用或者创建只需要执行一次的对象。
<script>
// 普通 <script>, 在模块范围下执行(只执行一次)
runSideEffectOnce()

// 声明额外的选项
export default {
  inheritAttrs: false,
  customOptions: {}
}
</script>

<script setup>
// 在 setup() 作用域中执行 (对每个实例皆如此)
</script>

注意:如果同时使用 <script setup><script> ,那么将打破 <script setup> 的默认关闭(即外部无法获取组件内部的属性和方法),此时,子组件内部的属性和方法都将在外部可获取到,如 ref.xxx

顶层await(了解)

await 的使用必须是要在async 语法糖的包裹下,否者将无法执行,为了更简化代码, <script setup> 中可以使用顶层 await

<script setup>
const post = await fetch(`/api/post/1`).then(r => r.json())
</script>

限制使用src 导入(了解)

SFC 的三个模块都可以通过 src 的方式进行导入,如下所示:

<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>

但是在<script setup>下强烈建议不使用 Src 导入。

由于模块执行语义的差异,<script setup> 中的代码依赖单文件组件的上下文。当将其移动到外部的 .js 或者 .ts 文件中的时候,对于开发者和工具来说都会感到混乱。因而<script setup> 不能和src attribute 一起使用。

style v-bind 新特性

style module(了解)

设计和使用上跟 Vue2.x 是一致的,因此也不多赘述。
唯一新的点是使用 <script setup> 时,可以使用 useCssModule API 获取到 css module 对象。

<script setup lang="ts">
import { useCssModule } from "vue";
const css = useCssModule();
console.log(css);        // { blue: "_blue_13cse_5", red: "_red_13cse_2"}
</script>

<style module>
.red {
  color: red;
}
.blue {
  color: blue;
}
</style>

动态css

单文件组件的 <style> 标签可以通过 v-bind 这一 CSS 函数将 CSS 的值关联到动态的组件状态上,有了这一特性,可以将大量的动态样式通过状态来驱动了,而不是写动态的 calss 类名或者获取 dom 来动态设置了

<script setup lang="ts">
import { ref } from "vue";
const color = ref('red');

setTimeout(() => color.value = 'blue' , 2000);
</script>

<template>
  <p>hello</p>
</template>

<style scoped>
p {
  color: v-bind(color);
}
</style>

volar插件

vue3必备vscode的插件,安装后有代码提示、点击css类/组件跳转、自动补全等等功能!

------ 本文结束,感谢您的阅读 ------
本文作者: 贺刘芳
版权声明: 本文采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。