自定义指令
使用场景: 鉴权 像v-if v-model这些都是内置的指令 自己也可以定义
命名规则:第一个字母为v
自定义指令内部也有生命周期钩子
使用方法:
<A v-move:aaa.xiaoman="{background: 'red'}"></A>
const vMove: Directive = {
created() {
console.log('======>created')
},
beforeMount() {
console.log('=====>beforeMount')
},
mounted(...args: any[]) {
console.log('=====>mounted', args)
},
unmounted() {
}
}
括号里接收的第一个值为绑定的元素本身,第二个值为冒号后面的值dir,也能通过value获取background red
鉴权场景
如果当前用户没有添加编辑删除命令,对应按钮就隐藏
<template>
<div class="btns">
<button v-has-show="'shop:create'">创建</button>
<button v-has-show="'shop:edit'">编辑</button>
<button v-has-show="'shop:delete'">删除</button>
</div>
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
import type { Directive } from 'vue'
localStorage.setItem('userId', 'xm')
const permission = ['xm:shop:edit', 'xm:shop:create', 'xm:shop:delete']
const userId = localStorage.getItem('userId') as string
const vHasShow: Directive = (el, binding) => {
console.log(el, binding)
if (!permission.includes(userId + ':' + binding.value)) {
el.style.display = 'none'
}
}
</script>
盒子拖拽
<template>
<div v-move class="box">
<div class="header"></div>
<div>内容</div>
</div>
</template>
<script setup lang='ts'>
import { ref, Directive, DirectiveBinding } from 'vue'
const vMove = (el, binding) => {
let moveElement = el.firstElementChild
const mouseDown = e => {
let X = e.clientX - el.offsetLeft
let Y = e.clientY - el.offsetTop
const move = e => {
el.style.left = e.clientX - X + 'px'
el.style.top = e.clientY - Y + 'px'
}
document.addEventListener('mousemove', move)
document.addEventListener('mouseup', () => {
document.removeEventListener('mousemove', move)
})
}
moveElement.addEventListener('mousedown', mouseDown)
}
</script>
<style lang='scss' scoped>
.box {
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
border: 2px solid black;
.header {
height: 20px;
background-color: black;
}
}
</style>
图片懒加载
<template>
<div>
<div>
<img v-lazy="item" v-for="item in arr" alt="img" width="300" height="300">
</div>
</div>
</template>
<script setup lang='ts'>
import { ref, reactive } from 'vue'
import type { Directive } from 'vue'
let imageList: Reacord<string> = import.meta.glob('../public/*.*', { eager: true })
let arr = Object.values(imageList).map(v => v.default)
console.log(arr)
let VLazy: Directive<HTMLImageElement, string> = async (el, bingding) => {
const def = await import('../public/vite.svg')
el.src = def.default
console.log('el', el)
// 判断元素是否在可视区
const observer = new IntersectionObserver(enr => {
console.log('===>', enr[0])
console.log('bingding', bingding.value)
if (enr[0].intersectionRatio > 0) {
setTimeout(() => {
el.src = bingding.value
// 取消监听
observer.unobserve(el)
}, 1000)
}
})
传入要监听的元素
observer.observe(el)
}
</script>
一个将图片生成base64的hook
hook ts
import { onMounted } from 'vue'
type Options = {
el: string
}
export default function (options: Options):Promise<{BaseUrl:string}> {
return new Promise(res => {
onMounted(() => {
let img: HTMLImageElement = document.querySelector(options.el) as HTMLImageElement
img.onload = () => {
res({
baseUrl: base64(img)
})
}
})
const base64 = (el:HTMLImageElement) => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = el.width
canvas.height = el.height
ctx?.drawImage(el, 0, 0, canvas.width, canvas.height)
return canvas.toDataURL('image/png')
}
})
}
组件
<template>
<div>
<img src="../public/1.png" alt="1">
</div>
</template>
<script setup lang='ts'>
import useBase64 from './hooks/index'
useBase64({
el: 'img'
}).then(res => {
console.log(res.baseUrl)
})
</script>