赞
踩
除了 Vue 内置的一系列指令 (比如 v-model
或 v-show
) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。
一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。
在 <script setup>
中,任何以 v
开头的驼峰式命名的变量都可以被用作一个自定义指令。
<!-- App.vue --> <template> <div> <button>切换</button> <!-- 钩子函数里面都可以接受这些值 myParam: 自定义参数; myModifier: 自定义修饰符 --> <A v-move:myParam.myModifier="{ background: 'pink' }"></A> </div> </template> <script setup lang="ts"> import { reactive, ref, Directive } from 'vue'; import A from './components/A.vue'; import B from './components/B.vue'; let flag = ref<boolean>(true) const vMove: Directive = { created() { console.log('created') }, beforeMount() { console.log('beforeMount') }, mounted(...args: Array<any>) { console.log('mounted') console.log(args); }, beforeUpdate() { console.log('beforeUpdate') }, updated() { console.log('updated') }, beforeUnmount() { console.log('beforeUnmount') }, unmounted() { console.log('unmounted') } } </script> <style scoped lang="less"></style>
<!-- App.vue --> <template> <div> <button>切换</button> <!-- 钩子函数里面都可以接受这些值 myParam: 自定义参数; myModifier: 自定义修饰符 --> <A v-move:myParam.myModifier="{ background: 'pink' }"></A> </div> </template> <script setup lang="ts"> import { reactive, ref, Directive, DirectiveBinding } from 'vue'; import A from './components/A.vue'; import B from './components/B.vue'; let flag = ref<boolean>(true) type Dir = { background: string; } const vMove: Directive = { created() { console.log('created') }, beforeMount() { console.log('beforeMount') }, mounted(el: HTMLElement, dir: DirectiveBinding<Dir>) { console.log('mounted') console.log(el); console.log(dir); el.style.background = dir.value.background; }, // 传入的数据发生变化(比如此时的background)时触发 beforeUpdate 和 updated beforeUpdate() { console.log('beforeUpdate') }, updated() { console.log('updated') }, beforeUnmount() { console.log('beforeUnmount') }, unmounted() { console.log('unmounted') } } </script> <style scoped lang="less"></style>
<!-- App.vue --> <template> <div class="btns"> <button v-has-show="123">创建</button> <button>编辑</button> <button>删除</button> </div> </template> <script setup lang="ts"> import { reactive, ref, DirectiveBinding } from 'vue'; import type { Directive } from 'vue' const vHasShow: Directive = (el, binding) => { console.log(el, binding) ; } </script> <style scoped lang="less"> .btns { button { margin: 10px; } } </style>
根据能否从 localStorage(或者后台返回) 中获取数据,来判断是否显示某个按钮。
<!-- App.vue --> <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 { reactive, ref, DirectiveBinding } from 'vue'; import type { Directive } from 'vue' localStorage.setItem('userId', 'xiuxiu') // mock 后台返回的数据 const permissions = [ 'xiuxiu:shop:create', // 'xiuxiu:shop:edit', // 后台没有相应数据,则不显示该对应的按钮 'xiuxiu:shop:delete' ] const userId = localStorage.getItem('userId') as string const vHasShow: Directive = (el, binding) => { if(!permissions.includes(userId + ':' + binding.value)) { el.style.display = 'none' } } </script> <style scoped lang="less"> .btns { button { margin: 10px; } } </style>
拖拽粉色框移动大盒子。
<!-- App.vue --> <template> <div v-move class="box"> <div class="header"></div> <div>内容</div> </div> </template> <script setup lang="ts"> import { Directive, DirectiveBinding } from 'vue'; const vMove:Directive<any,void> = (el:HTMLElement, binding:DirectiveBinding)=> { let moveElement:HTMLElement = el.firstElementChild as HTMLElement; console.log(moveElement); const mouseDown = (e:MouseEvent) => { // 记录原始位置 // clientX 鼠标点击位置的X轴坐标 // clientY 鼠标点击位置的Y轴坐标 // offsetLeft 鼠标点击的子元素距离其父元素的左边的距离 // offsetTop 鼠标点击的子元素距离其父元素的顶部的距离 let X = e.clientX - el.offsetLeft; let Y = e.clientY - el.offsetTop; const move = (e:MouseEvent) => { console.log(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 scoped lang="less"> .box { position: fixed; height: 200px; width: 200px; top: 50%; left: 50%; transform: translate(-50%, -50%); border: 1px solid #000; .header { height: 50px; width: 100%; background: pink; border-bottom: #000 1px solid; } } </style>
let imageList = import.meta.glob('./assets/images/*.*', { eager: true })
let imageList = import.meta.glob('./assets/images/*.*')
// 判断图片是否在可视区
const observer = new IntersectionObserver((e)=> {
console.log(e[0]);
})
// 监听元素
observer.observe(el)
<!-- App.vue --> <template> <div> <div> <img v-lazy="item" width="400" height="500" v-for="item in arr" alt=""> </div> </div> </template> <script setup lang="ts"> import { Directive, DirectiveBinding } from 'vue'; let imageList:Record<string,{default:string}> = import.meta.glob('./assets/images/*.*', { eager: true }) let arr = Object.values(imageList).map(item=>item.default) console.log(arr); let vLazy:Directive<HTMLImageElement,string> = async (el,binding)=> { const def = await import('./assets/pinia.svg') el.src = def.default // 判断图片是否在可视区 const observer = new IntersectionObserver((e)=> { console.log(e[0],binding.value); if(e[0].intersectionRatio > 0) { setTimeout(()=> { el.src = binding.value },2000) observer.unobserve(el) } }) // 监听元素 observer.observe(el) } </script> <style scoped lang="less"></style>
进入可视区比例 > 0:
过 2s ,替换图片
全局注册
//在main.js中
Vue.directive('指令名', {
"inserted" (el) {
// 可以对 el 标签,扩展额外功能
el.focus()
}
})
局部注册
//在Vue组件的配置项中
directives: {
"指令名": {
inserted () {
// 可以对 el 标签,扩展额外功能
// el:使用指令的那个DOM元素
el.focus()
}
}
}
使用指令
注意:在使用指令的时候,一定要先注册,再使用,否则会报错
使用指令语法: v-指令名。如:<input type="text" v-focus/>
注册指令时不用加v-前缀,但使用时一定要加v-前缀。
1.在绑定指令时,可以通过“等号”的形式为指令 绑定 具体的参数值
<div v-color="color">我是内容</div>
2.通过 binding.value 可以拿到指令值,指令值修改会 触发 update 函数
directives: {
color: {
inserted (el, binding) {
el.style.color = binding.value
},
update (el, binding) {
el.style.color = binding.value
}
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。