如果想要看3.5完整版api,你需要看英文版的vue官网API Reference | Vue.js (vuejs.org)。
以下API测试学习仅在<script setup>
语法中使用。
响应式 Props 解构 3.5
以前结构props会使props失去响应式,而且必须通过withDefaults
进行赋默认值。现在我们直接可以进行解构,并通过js语法即可赋初值。
interface Props {
msg?: any
labels?: string[]
}
const { msg = 'hello', labels = ['one', 'two'] } = defineProps<Props>()
useSlots(),defineSlots()
3.3
在<script setup>
中没啥用,他主要是获取当前组件传入的插槽对象,不管当前组件有没有定义插槽。这个一般在h函数中使用,具体可以看这里。
怎么去理解这个插槽呢?看似子组件是定义者,其实插槽的用处之一就是将子组件中的值向父组件传递。对比函数理解,其实父组件传入的插槽内容才是插槽的定义,子组件才是调用者。所以打印slots
才是一堆函数。
<AttrSlot zh name foo="foo-props">
插槽
<template #footer>
<div>footer</div>
</template>
</AttrSlot>
但是在ts
中,官方更推荐我们使用defineSlots()
,使用defineSlots()
声明插槽的定义有以下好处
增强类型安全:
defineSlots
可以帮助你在 TypeScript 中获得更好的类型检查。通过显式定义插槽的结构和属性,可以确保插槽的正确使用。
提高可读性和可维护性:
- 显式定义插槽可以让其他开发人员更容易理解组件的结构和用途。通过定义插槽,可以清晰地表达哪些插槽是必需的,哪些是可选的。难道可选插槽就是为了提示该插槽是有默认值的吗?没有其他实质性的约束?
增强插槽的灵活性:
- 通过
defineSlots
,你可以更灵活地处理插槽的内容。例如,你可以为插槽传递属性,并在父组件中使用这些属性(不定义也可以有提示)。
<template>
<div>
<slot name="header" msg="header"></slot>
<slot sex="default"></slot>
<slot name="footer" :age="20"></slot>
</div>
</template>
// 定义当前组件插槽类型,并返回使用该组件传入的插槽对象
const slots = defineSlots<{
header(props: { msg: string }): any
default(props: { sex: string }): any
footer(props: { age: number }): any
}>()
useAttrs()
获取当前组件非props的属性集合。这些属性在<script setup>
中获取基本没啥用。一般都是在模板中直接进行绑定。这样我们直接使用$attrs
即可。
<div v-bind="$attrs">useAttrs</div>
useModel(),defineModel()
3.4
二者都是和值的双向绑定有关。以前如果我们实现组件props双向绑定我们在更新props值时向外发送事件进行更新来达到props值的双向绑定。其实这两个参数也就是我们以前方法的语法糖而已。
useModel
是更底层的api,defineModel
是useModel
更具体的封装。
const props = defineProps<{
name: string
}>()
// useModel就比较简单了,参数一组件的props,参数二绑定到v-model的键值,参数三get,set方法对象
const model2 = useModel(props, 'name', {
get(value) {
console.log('value======useModel', value)
return value
},
set(value) {
console.log('value======useModel', value)
return value + '0000' // 如果定义必须有返回值
}
})
defineModel
提供了很多函数重载方法及各个参数类型介绍。
- 参数一:model绑定的变量名。如果不传默认是
modelValue
- 参数二:配置对象
- type 当前绑定值的类型
- default 当前绑定值的默认值
- required 是否必传的
v-model
,如果父组件在使用子组件时不进行定义那么将报错,并且约束了该v-model
绑定的变量不能为undefined
。 - validator 验证函数。这个函数可以拿到当前绑定的变量最新值和
v-model
的修饰符,所以可以在这个函数中做数据校验,至于返回的boolean并没有实际用处? - get,set 如果我们想要通过修饰符来处理变量的值,我们就可以在get,set方法中统一处理。注意:如果设置了
set
方法,我们必须设置返回值,不然外部更新绑定的变量将不会有任何结果响应。
<script setup> const [model, modifiers] = defineModel({ set(value) { if (modifiers.capitalize) { return value.charAt(0).toUpperCase() + value.slice(1) } return value } }) </script> <template> <input type="text" v-model="model" /> </template>
我们定义的修饰符泛型类型并不能在我们使用v-model
指定修饰符时进行提示(只能提示内置的修饰符),而是在获取修饰符时进行提示。
useTemplateRef()
3.5
这个就是以前ref
引用ref
变量获取dom元素的替代品。绑定关系更容易让人理解。
<script setup>
import { useTemplateRef, onMounted } from 'vue'
const inputRef = useTemplateRef('input')
onMounted(() => {
inputRef.value.focus()
})
</script>
<template>
<input ref="input" />
</template>
即使我们不指定绑定的组件类型,他也可以很好的推断出来组件实例暴露了那些数据。
// <InstanceType<typeof RefTemplate>>
const refTemplateRef = useTemplateRef('customComponent')
onMounted(() => {
console.log('====================refTemplateRef', refTemplateRef.value)
})
useId()
3.5
生成当前程序的唯一ID。
<script setup>
import { useId } from 'vue'
const id = useId()
</script>
<template>
<form>
<label :for="id">Name:</label>
<input :id="id" type="text" />
</form>
</template>
hasInjectionContext()
3.3
查看当前组件使用注入数据的地方是否允许被使用,如果可以则返回true
,这样方便我们做出做一些适配。
例如在非setup中使用就会返回false
。并不是我认为的在非provide组件下的子组件中调用hasInjectionContext
就会返回false
。这个是vue组件自动会判断,并且会在控制台抛出警告。
onWatcherCleanup()
3.5
在watch
和watchEffect
函数中可以使用的回调函数,用于在依赖变化导致副作用函数重新执行前执行一些清理操作。注意:不能在await之后调用该钩子,即不能用在具有async
回调的watch, watchEffect
中。
这个钩子的作用同watch, watchEffect
回调中的onCleanup
函数。
watch, watchEffect
中的once
3.4
监听回调函数只会运行一次。侦听器将在回调函数首次运行后自动停止。
watch, watchEffect
监听的回调触发时机
'sync'
:同步执行回调。这意味着当触发依赖变化时,立即执行回调函数,而不是等待下一个事件循环周期。'pre'
:在组件更新之前触发回调。这个阶段会在 Vue 开始计算新的状态和 DOM 变化之前执行。'post'
:在组件更新之后触发回调。这个阶段在 Vue 完成了所有的状态更新和 DOM 渲染之后执行。
尽管监听回调在不同时机执行,但是他们都可以拿到更新前后的值。
如果都设置immediate: true
,那么他们都优先于onMounted
钩子执行。
name 3.2.34
在 3.2.34 或以上的版本中,使用 <script setup>
的单文件组件会自动根据文件名生成对应的 name
选项,即使是在配合 <KeepAlive>
使用时也无需再手动声明。
v-memo 3.2
当前元素或者组件是否可以根据v-memo
中指定的值跳过更新。即类似于v-once
,但是依赖的值发生变化,元素和组件还是会响应式的更新。v-memo
传入空依赖数组 (v-memo="[]"
) 将与 v-once
效果相同。
当搭配 v-for
使用 v-memo
,确保两者都绑定在同一个元素上。v-memo
不能用在 v-for
内部。
这里有一个demo
MemoTest2
组件依赖于非响应式数据age
,当改变age时发现MemoTest2
组件并不会更新数据,并且如果只改变num
由于memo以来于age
也不会更新组件,所以当age
发生变化后在进行num
改变才会更新MemoTest2
组件(这是由于更新响应式数据,vue会更新组件树中的所有组件,而v-memo有依赖了age所以只有当age更新后再更新响应式数据num,memotest2组件才会更新)。由此可见v-memo
依赖的数据只有为响应式数据才会立刻有效果。MemoTest1
中的p
标签依赖于num,name
所以更新任何一个数据都将被更新。
所以说v-memo
依赖项尽量设置为响应式数据。
// memotest1
<template>
<!-- age发生变化,在num响应式数据发生变化后,需要更新子组件状态,所以也会导致 MemoTest2组件更新 -->
<MemoTest2 v-memo="[age]" :age="age" :num="num" />
<h1>memotest1</h1>
<p v-memo="[num, name]">响应式数据name:{{ name }}</p>
<p>响应式数据num:{{ num }}</p>
<button @click="handleData('num')">修改num</button>
<button @click="handleData('name')">修改name</button>
<button @click="handleData('age')">修改age</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import MemoTest2 from './MemoTest2.vue'
const num = ref(1)
const name = ref('zh')
let age = 0
const handleData = (key: string) => {
if (key === 'num') {
num.value = num.value + 1
} else if (key === 'name') {
name.value = name.value === 'zh' ? 'llm' : 'zh'
} else {
age = age + 1
console.log('更新age', age)
}
}
</script>
// memotest2
<template>
<h1>memotest2</h1>
<p>响应式数据num:{{ num }}</p>
<p>非响应式数据:{{ age }}</p>
</template>
<script setup lang="ts">
import { onUpdated } from 'vue'
const { age, num } = defineProps<{
age: number
num?: number
}>()
onUpdated(() => {
console.log('更新数据。。。。')
})
console.log('num', num)
</script>
ComponentPublicInstance
我们通过useTemplateRef, ref
引用元素或者组件实例时,如果不知道具体的类型,我们可以通过ComponentPublicInstance
类型代替。这只会包含所有组件都共享的属性,比如 $el
。
is 3.1
这个主要是用于和component
组件绑定动态组件的。当使用在原生 HTML 元素上时,is
的值必须加上前缀 vue:
才可以被解析为一个 Vue 组件。 这个也是为了解决有些元素强制子元素为某些元素的限制。
<table>
<tr is="vue:blog-post-row"></tr>
</table>
src
导入
如果你更喜欢将 *.vue
组件分散到多个文件中,可以为一个语块使用 src
这个 attribute 来导入一个外部文件:
<template src="./template.html"></template>
<style src="./style.css"></style>
<script src="./script.js"></script>
<script setup>
- 每个
.vue
文件只能有一个<script setup>
和一个<script>
- 由于里面的代码会被编译成组件
setup()
函数的内容,所以<script setup>
中的代码会在每次组件实例被创建的时候执行。普通的<script>
代码(不是setup函数中的)只在组件被首次引入的时候执行一次。 - 局部自定义指令不需要显式注册,但他们必须遵循
vNameOfDirective
这样的命名规范。 - Vue3.3 支持在类型参数的位置引用导入的和有限的复杂类型。然而,由于类型到运行时的转换仍然基于 AST,因此并不支持使用需要实际类型分析的复杂类型,例如条件类型等。你可以在单个 prop 的类型上使用条件类型,但不能对整个 props 对象使用。
自定义元素相关的api下篇文章继续分享,如果还不了解自定义元素可以查看这里 《了解Web Components,在现代框架中使用它》
往期年度总结
往期文章
- 啊,你还在找一款强大的表格组件吗?
- 前端大量数据层级展示及搜索定位预览
- 如何从0开始认识m3u8(提取,解析及下载)
- 展示大量数据节点(tree),引发的一次性能排查
- ts装饰器的那点东西
- 这是你所知道的ts类型断言和类型守卫吗?
- TypeScript官网内容解读
- 经常使用ts的你,知道这些内容?
- 你有了解过原生css的scope?
- 现在比较常用的移动端调试你知道哪些?
- 众多跨标签页通信方式,你知道哪些?(二)
- 众多跨标签页通信方式,你知道哪些?
- 反调试吗?如何监听devtools的打开与关闭
- 因为原生,选择一家公司(前端如何防笔试作弊)
- 结合开发,带你熟悉package.json与tsconfig.json配置
- 如何优雅的在项目中使用echarts
- 如何优雅的做项目国际化
- 近三个月的排错,原来的憧憬消失喽
- 带你从0开始了解vue3核心(运行时)
- 带你从0开始了解vue3核心(computed, watch)
- 带你从0开始了解vue3核心(响应式)
- 3w+字的后台管理通用功能解决方案送给你
- 入职之前,狂补技术,4w字的前端技术解决方案送给你(vue3 + vite )
专栏文章
🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论, 支持一下博主~
公众号:全栈追逐者,不定期的更新内容,关注不错过哦!