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>