slot插槽
1. 基本插槽
组件:
<template>
<div>
<h2>{{ title }}</h2>
<slot></slot>
</div>
</template>
使用者:
<template>
<div>
<Compo1 title="游戏列表">
<ul>
<li v-for="item in games" :key="item.id">{{ item.name }}</li>
</ul>
</Compo1>
</div>
</template>
2. 具名插槽
组件:
<template>
<div>
<h2>{{ title }}</h2>
<slot name="content"></slot>
</div>
</template>
使用者:
<template>
<div>
<Compo1 title="游戏列表" v-slot:content>
<ul>
<li v-for="item in games" :key="item.id">{{ item.name }}</li>
</ul>
</Compo1>
<Compo1 title="美食中国" #content>
<img :src="imgUrl" alt="">
</Compo1>
</div>
</template>
3. 作用域插槽
组件:
<template>
<div>
<h2>{{ title }}</h2>
<slot name="content" :games="games" :imgUrl="imgUrl"></slot>
</div>
</template>
使用者:
<template>
<div>
<Compo1 title="游戏列表" v-slot:content = 'params'>
<ul>
<li v-for="item in params.games" :key="item.id">{{ item.name }}</li>
</ul>
</Compo1>
<Compo1 title="美食中国" #content = 'params'>
<img :src="params.imgUrl" alt="">
</Compo1>
</div>
</template>
自定义指令
1. 局部注册
<template>
<div>
<input v-focus type="text">
</div>
</template>
<script setup lang="ts">
const vFocus = {
mounted: (el) => {
el.style.height = '25px'
el.focus()
}
}
</script>
2. 全局注册
可以自定义一个文件夹directives,将所有指令的逻辑都放在这里
比如我新建一个vFocus.ts文件
const vFocus = {
mounted: (el) => {
el.style.height = '25px'
el.style.border = '1px dashed black'
el.focus()
}
}
export default vFocus
main.js
// 引入自定义指令
import vFocus from '@/directives/vFocus'
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App);
//注册自定义指令
app.directive('focus', vFocus)
app.mount('#app');
shallowRef与shallowReactive
ref()与reactive()的浅层作用形式,也就是说只对浅层的数据具有响应式
const state = shallowRef({ count: 1 })
// 不会触发更改
state.value.count = 2
// 会触发更改
state.value = { count: 2 }
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
// 更改状态自身的属性是响应式的
state.foo++
// ...但下层嵌套对象不会被转为响应式
isReactive(state.nested) // false
// 不是响应式的
state.nested.bar++
readonly()与shallowReadonly()
readonly()只读代理是深层的:对任何嵌套属性的访问都将是只读的。
const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => {
// 用来做响应性追踪
console.log(copy.count)
})
// 更改源属性会触发其依赖的侦听器
original.count++
// 更改该只读副本将会失败,并会得到一个警告
copy.count++ // warning!
和 readonly()
不同,这里没有深层级的转换:只有根层级的属性变为了只读。
const state = shallowReadonly({
foo: 1,
nested: {
bar: 2
}
})
// 更改状态自身的属性会失败
state.foo++
// ...但可以更改下层嵌套对象
isReadonly(state.nested) // false
// 这是可以通过的
state.nested.bar++
toRaw()
toRaw()
可以返回由 reactive()
、readonly()
、shallowReactive()
或者 shallowReadonly()
创建的代理对应的原始对象。
const foo = {}
const reactiveFoo = reactive(foo)
console.log(toRaw(reactiveFoo) === foo) // true
markRaw()
markRaw 将一个对象标记为不可被转为代理。返回该对象本身。(只对reactive生效)
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// 也适用于嵌套在其他响应性对象
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
customRef()
创建一个自定义的 ref,显式声明对其依赖追踪和更新触发的控制方式。
创建一个hooks:
import { customRef } from 'vue'
export default function (inputInit, delay) {
const input = customRef((track, trigger) => {
let timer
return {
get() {
track() //告诉vue数据inputInit很重要,你要对其进行持续关注,一旦其数据变化就去更新
return inputInit
},
set(value) {
clearTimeout(timer)
timer = setTimeout(() => {
inputInit = value
trigger() // 通知vue数据变化了
}, delay)
}
}
})
return {
input
}
}
使用者:
<template>
<input type="text" v-model="input">
<div>{{ input }}</div>
</template>
<script lang="ts" setup>
import useCustomRef from './hooks/useCustomRef';
let {input} = useCustomRef('666', 2000)
</script>
Teleport
<Teleport>
是一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。
<button @click="open = true">Open Modal</button>
<Teleport to="body">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</Teleport>