VUE3组合式API学习笔记
VUE3组合式API学习笔记
unref()
如果参数是 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val 计算的一个语法糖。
toRaw()
toRaw() 可以返回由 reactive()、readonly()、shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象。
可以用于最后需要得到非proxy对象时使用。注意智能时reactive对象,不能是ref对象,还未使用过。
onScopeDispose()
在当前活跃的 effect 作用域上注册一个处理回调函数。当相关的 effect 作用域停止时会调用这个回调函数。
这个方法可以作为可复用的组合式函数中 onUnmounted 的替代品,它并不与组件耦合,因为每一个 Vue 组件的 setup() 函数也是在一个 effect 作用域中调用的。
onRenderTriggered()
注册一个调试钩子,当响应式依赖的变更触发了组件渲染时调用。
function onRenderTriggered(callback: DebuggerHook): void
type DebuggerHook = (e: DebuggerEvent) => void
type DebuggerEvent = {
effect: ReactiveEffect
target: object
type: TriggerOpTypes /* 'set' | 'add' | 'delete' | 'clear' */
key: any
newValue?: any
oldValue?: any
oldTarget?: Map<any, any> | Set<any>
}
expose
可以通过该属性暴露一些属性和方法供父组件使用
v-pre
跳过该元素及其所有子元素的编译。
元素内具有 v-pre,所有 Vue 模板语法都会被保留并按原样渲染。最常见的用例就是显示原始双大括号标签及内容。
<span v-pre>{{ this will not be compiled }}</span>
v-memo
可以绑定一个数组,如果这个数组中的值没有变化,绑定该prop的标签不会被重新渲染
v-cloak
用于隐藏尚未完成编译的 DOM 模板。比如先显示{{}},然后显示数字,用它可以规避这种情况。
setup语法糖中的语法
- 接受父组件传参props可以通过以下语法声明
<script setup>
const props = defineProps({
foo: String
})
</script>
- emits可以通过以下语法使用
<script setup>
const emit = defineEmits(['change', 'delete'])
</script>
-defineExpose(): setup语法糖里的变量都不会保留,需要暴露的内容需要放在这个里面
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
defineExpose({
a,
b
})
// 当父组件通过模板引用的方式获取到当前组件的实例,
// 获取到的实例会像这样 { a: number, b: number }
// (ref 会和在普通实例中一样被自动解包)
</script>
ts类型推断
const props = defineProps<{
foo: string
bar?: number
}>()
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
使用类型声明时的默认 props 值
// 针对类型的 defineProps 声明的不足之处在于,它没有可以给 props 提供默认值的方式。为了解决这个问题,我们还提供了 withDefaults 编译器宏:
export interface Props {
msg?: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
- useSlots() 和 useAttrs()
/*
在 <script setup> 使用 slots 和 attrs 的情况应该是相对来说较为罕见的,因为可以在模板中直接通过 $slots 和 $attrs 来访问它们。在你的确需要使用它们的罕见场景中,可以分别用 useSlots 和 useAttrs 两个辅助函数:
*/
<script setup>
import { useSlots, useAttrs } from 'vue'
const slots = useSlots()
const attrs = useAttrs()
</script>
Suspense
用来在组件树中协调对异步依赖的处理。它让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态。
可以处理组合式api的顶层await异步,一级async setup(){}这样的异步组件,统一控制后面组件的成功与失败状态,不再分别报错
suspense的有两个插槽,分别只能放一个组件。分别是
- #default 异步完成状态,里面放异步组件或含有异步组件的父辈组件
- #fallback 挂起状态 里面放异步组件未加载出来时显示的东西比如loading
注意:组件变成完成后不会在变成挂起状态!!!除非里面的组件变更了。
// 使用示例
<RouterView v-slot="{ Component }">
<template v-if="Component">
<Transition mode="out-in">
<KeepAlive>
<Suspense>
<!-- 主要内容 -->
<component :is="Component"></component>
<!-- 加载中状态 -->
<template #fallback>
正在加载...
</template>
</Suspense>
</KeepAlive>
</Transition>
</template>
</RouterView>
插槽选择器
默认情况下,作用域样式不会影响到 渲染出来的内容,因为它们被认为是父组件所持有并传递进来的。使用 :slotted 伪类以明确地将插槽内容作为选择器的目标:
<style scoped>
:slotted(div) {
color: red;
}
</style>
CSS Modules
一个 style module 标签会被编译为 CSS Modules 并且将生成的 CSS class 作为 $style 对象暴露给组件
<template>
<p :class="$style.red">This should be red</p>
</template>
<style module>
.red {
color: red;
}
</style>
- 自定义注入名称
<template>
<p :class="classes.red">red</p>
</template>
<style module="classes">
.red {
color: red;
}
</style>
- 与组合式API一起使用
import { useCssModule } from 'vue'
// 在 setup() 作用域中...
// 默认情况下, 返回 <style module> 的 class
useCssModule()
// 具名情况下, 返回 <style module="classes"> 的 class
useCssModule('classes')
CSS 中的 v-bind()
单文件组件的 style 标签支持使用 v-bind CSS 函数将 CSS 的值链接到动态的组件状态
<template>
<div class="text">hello</div>
</template>
<script>
export default {
data() {
return {
color: 'red'
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
这个语法同样也适用于 script setup,且支持 JavaScript 表达式 (需要用引号包裹起来):
<script setup>
const theme = {
color: 'red'
}
</script>
<template>
<p>hello</p>
</template>
<style scoped>
p {
color: v-bind('theme.color');
}
</style>
渲染函数
// 完整参数签名
function h(
type: string | Component,
props?: object | null,
children?: Children | Slot | Slots
): VNode
// 省略 props
function h(type: string | Component, children?: Children | Slot): VNode
type Children = string | number | boolean | VNode | null | Children[]
type Slot = () => Children
type Slots = { [name: string]: Slot }
创建原生元素示例
import { h } from 'vue'
// 除了 type 外,其他参数都是可选的
h('div')
h('div', { id: 'foo' })
// attribute 和 property 都可以用于 prop
// Vue 会自动选择正确的方式来分配它
h('div', { class: 'bar', innerHTML: 'hello' })
// class 与 style 可以像在模板中一样
// 用数组或对象的形式书写
h('div', { class: [foo, { bar }], style: { color: 'red' } })
// 事件监听器应以 onXxx 的形式书写
h('div', { onClick: () => {} })
// children 可以是一个字符串
h('div', { id: 'foo' }, 'hello')
// 没有 prop 时可以省略不写
h('div', 'hello')
h('div', [h('span', 'hello')])
// children 数组可以同时包含 vnode 和字符串
h('div', ['hello', h('span', 'hello')])
创建组件示例
import Foo from './Foo.vue'
// 传递 prop
h(Foo, {
// 等价于 some-prop="hello"
someProp: 'hello',
// 等价于 @update="() => {}"
onUpdate: () => {}
})
// 传递单个默认插槽
h(Foo, () => 'default slot')
// 传递具名插槽
// 注意,需要使用 `null` 来避免
// 插槽对象被当作是 prop
h(MyComponent, null, {
default: () => 'default slot',
foo: () => h('div', 'foo'),
bar: () => [h('span', 'one'), h('span', 'two')]
})