优化性能的指令
//`Vue.js` 提供了一个指令,以便只渲染一次元素和组件,并且跳过以后的更新
<script setup lang="ts">
import { ref } from "vue"
const count = ref(0)
setInterval(() => {
count.value++
console.log(count.value)
}, 1000)
</script>
<template>
<span v-once>使它从不更新: {{ count }}</span>
</template>
切换器
<script setup lang='ts'>
import { ref } from "vue"
/**
* Implement a composable function that toggles the state
* Make the function work correctly
*/
function useToggle(open: boolean) {
const stateRef = ref(open)
const toggle=() => {
stateRef.value = !stateRef.value
}
return [stateRef, toggle]
}
const [state, toggle] = useToggle(false)
</script>
<template>
<p>State: {{ state ? 'ON' : 'OFF' }}</p>
<p @click="toggle">
Toggle state
</p>
</template>
实现until函数
<script setup lang='ts'>
import {ref,watchEffect,type Ref } from "vue"
const count = ref(0)
/**
* 实现`until`函数
*/
function until(initial:Ref<number>) {
function toBe(value:number) {
return new Promise((resolve) => {
const stop=watchEffect(() => {
console.log('我进来看了');
if((initial.value === value)){
stop()
resolve(value);
}
});
});
}
return {
toBe,
}
}
async function increase() {
count.value = 0
setInterval(() => {
count.value++
}, 1000)
await until(count).toBe(3)
console.log(count.value === 3) // 确保输出为true
}
increase()
</script>
实现计数器
<script setup lang='ts'>
import {ref} from 'vue'
interface UseCounterOptions {
min?: number
max?: number
}
/**
* 实现计数器函数,确保功能正常工作
* 1. 加 (+)
* 2. 减 (-)
* 3. 重置
* 4. 最小值 & 最大值 选项支持
*/
function useCounter(initialValue = 0, options: UseCounterOptions = {}) {
const count=ref(initialValue)
const {min,max}=options
const inc=()=>{
if(max!=undefined&&count.value>=max){
count.value=max
}else{
count.value++
}
}
const dec=()=>{
if(min!=undefined&&count.value<=min){
count.value=min
}else{
count.value--
}
}
const reset=()=>{
count.value=initialValue
}
return{
count,
inc,
dec,
reset
}
}
const { count, inc, dec, reset } = useCounter(0, { min: 0, max: 10 })
</script>
<template>
<p>{{count}}</p>
<button @click="inc">加</button>
<button @click="dec">减</button>
<button @click="reset">重置</button>
</template>
一个简易的locastorage读写
<script setup lang='ts'>
import { ref, watchEffect } from "vue"
/**
* 实现`useLocalStorage`函数
*/
function useLocalStorage(key: string, initialValue: any) {
const value = ref(localStorage.getItem(key)??initialValue)
watchEffect(()=>{
localStorage.setItem(key,value.value)
})
return value
}
const counter = useLocalStorage("counter", 0)
// 我们可以通过触发`counter`的`getter`来获取本地存储的值
console.log(counter.value)
setInterval(()=>{
counter.value++
},1000)
// 同样地,我们也可以通过触发`counter`的`setter`来设置本地存储的值
</script>
<template>
<p>{{ counter }}</p>
</template>
自定义指令
<script setup lang='ts'>
import { ref } from "vue"
const state = ref(false)
/**
* 实现一个自定义指令,让元素获取焦点
* 确保当切换`state`时,元素随着状态值获取/失去焦点
*
*/
const VFocus = {
updated:(el:HTMLElement,binding:{value:boolean})=>{
binding.value?el.focus():el.blur()
}
}
console.log(VFocus)
setInterval(() => {
state.value = !state.value
}, 2000)
</script>
<template>
<input v-focus="state" type="text">
</template>
问题 遗留 由于自定义指令未被读取。导致编辑器飘红问题
使用自定义指令实现防抖点击指令
<script setup lang='ts'>
import { ref } from 'vue';
/**
* 实现以下自定义指令
* 确保在一定时间内当快速点击按钮多次时只触发一次点击事件
* 你需要支持防抖延迟时间选项, 用法如 `v-debounce-click:ms`
*
*/
const VDebounceClick = {
mounted:(el:HTMLElement,bingding:{arg:number})=>{
const isClick=ref(true);
el.addEventListener('click',()=>{
if(isClick.value){
isClick.value=false
setTimeout(()=>isClick.value=true,bingding.arg)
console.log('可以执行');
}else{
onClick()
}
})
},
}
function onClick() {
console.log("Only triggered once when clicked many times quicky")
}
console.log(VDebounceClick)
</script>
<template>
<button v-debounce-click:1000="onClick">
Click on it many times quickly
</button>
</template>
函数式组件h函数的使用
<script setup lang='ts'>
import { ref, h } from "vue"
/**
* 实现该函数式组件 :
* 1. 使用`list`数据渲染列表元素 (ul/li)
* 2. 当点击列表子元素时,将其文本颜色更改为红色
* h函数的使用 当第三个参数不是插槽时 可以省略第二个props参数
*/
type props={
list:{name:string}[],
onToggle(index:number):void,
activeIndex:number
}
const ListComponent = (props:props) => {
console.log(props)
return h('ul', props.list.map((element:{name:string},index:number) => {
return h('li', {
style: { color: activeIndex.value==index?'red':null},
onClick:() => props.onToggle(index),
}, element.name)
}))
}
const list = [{
name: "John",
}, {
name: "Doe",
}, {
name: "Smith",
}]
const activeIndex = ref(0)
function toggle(index: number) {
activeIndex.value = index
}
</script>
<template>
<list-component :list="list" :active-index="activeIndex" @toggle="toggle" />
</template>
函数式组件练习
<script setup lang="ts">
import { h} from 'vue';
const onClick = () => {
console.log('onClick')
}
const MyButton=(props,{ slots })=>{
console.log(props)
return h('button',{
onClick:props.onCustomClick,
disabled:props.disabled
},slots.default())
}
</script>
<template>
<MyButton :disabled="false" @custom-click="onClick">
my button
</MyButton>
</template>
按键修饰符和系统修饰符 exact的使用
<template>
<!-- 添加按键修饰符让即使 Alt 或 Shift 被一同按下时也会触发 -->
<button @click.ctrl="onClick1">A</button>
<!-- 添加按键修饰符让有且只有 Shift 被按下的时候才触发 -->
<button @click.shift.exact="onCtrlClick">A</button>
<!-- 添加按键修饰符让没有任何系统修饰符被按下的时候才触发 -->
<button @click.exact="onClick2">A</button>
</template>
<script setup lang="ts">
const onClick1=()=>{
console.log('添加按键修饰符让即使 Alt 或 Shift 被一同按下时也会触发');
}
const onCtrlClick=()=>{
console.log('添加按键修饰符让有且只有 Shift 被按下的时候才触发 ');
}
const onClick2=()=>{
console.log('添加按键修饰符让没有任何系统修饰符被按下的时候才触发');
}
</script>
监听鼠标坐标
<script setup lang="ts">
import {ref} from 'vue'
// Implement ...
function useEventListener(target:Window, event:string,callback) {
target.addEventListener(event,callback)
}
// Implement ...
function useMouse() {
const x=ref(0)
const y=ref(0)
useEventListener(window, "mousemove",(event)=>{
x.value=event.clientX
y.value=event.clientY
})
return {x,y}
}
const { x, y } = useMouse()
</script>
<template>
Mouse position is at: {{ x }}, {{ y }}
</template>
toRaw 和markRaw的使用
//toRaw 返回这个代理对象的原始对象
//markRaw 将一个对象标记为不可转换为代理
<script setup lang="ts">
import { reactive, isReactive,toRaw,markRaw } from "vue"
const state = { count: 1 }
const reactiveState = reactive(state)
/**
* 修改以下代码使输出为true
*/
console.log(toRaw(reactiveState) === state)
/**
* 修改以下代码使输出为false
*/
const info = markRaw({ count: 1 })
const reactiveInfo = reactive(info)
console.log(isReactive(reactiveInfo))
</script>
<template>
<div>
<p>
{{ reactiveState.count }}
</p>
</div>
</template>