【Vue 第二十五章】自定义指令、权限按钮

除了 Vue 内置的一系列指令 (比如 v-modelv-show) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)。

一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。

13.1 自定义局部指令

<script setup> 中,任何以 v 开头的驼峰式命名的变量都可以被用作一个自定义指令。在下面的例子中,vFocus 即可以在模板中以 v-focus 的形式使用。

13.1.1 获取焦点指令案例(v-focus & vFocus)

当一个 input 元素被 Vue 插入到 DOM 中后,它会被自动聚焦

<script setup>
    // 在模板中启用 v-focus
    const vFocus = {
      mounted: (el) => el.focus()
    }
</script>

<template>
  <input v-focus />
</template>

13.1.2 拖拽指令案例(v-drag & vDrag)

<script setup>
import { ref } from 'vue'

const message = ref("自定义指令")

// 自定义 v-color 指令,添加传递参数 myprop,自定义修饰符 .hehe
const vColor = {
    mounted(el, binding, vnode, prevVnode) {
        // 打印组件生命周期钩子参数,参数描述详见笔记文档
        console.log(el, "~~~", binding, "~~~", vnode, "~~~", prevVnode);
    }
}

// 自定义拖拽指令
const vDrag = {
    // 一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。
    // mounted() 在绑定元素的父组件及他自己的所有子节点都挂载完成后调用
    mounted(el) {
        // 获取页面可移动最大范围
        let maxX = document.documentElement.clientWidth - el.clientWidth;
        let maxY = document.documentElement.clientHeight - el.clientHeight;

        // 定义鼠标按下事件对应的事件函数
        const mouseDownFn = (e) => {
            // 获取鼠标按下时的位置
            let x = e.clientX;
            let y = e.clientY;

            // 定义鼠标在页面范围内移动事件对应的事件函数
            const moveFn = (e) => {
                // 获取鼠标的移动距离
                let moveX = e.clientX - x;
                let moveY = e.clientY - y;

                // 更新鼠标最新为欸之
                x = e.clientX;
                y = e.clientY;

                // 获取元素在页面中最新的位置
                let ml = el.offsetLeft + moveX;
                let mt = el.offsetTop + moveY;

                // 判定移动边界
                if (ml <= 0) {
                    ml = 0;
                } else if (ml >= maxX) {
                    ml = maxX;
                }

                if (mt <= 0) {
                    mt = 0;
                } else if (mt >= maxY) {
                    mt = maxY;
                }

                // 将移动后的位置设置给元素
                el.style.left = ml + "px";
                el.style.top = mt + "px";
            }

            // 定义鼠标在页面范围内的移动事件
            document.addEventListener('mousemove', moveFn)

            // 页面文档鼠标松开事件
            document.addEventListener('mouseup', () => {
                // 鼠标在页面范围内的移动事件
                document.removeEventListener('mousemove', moveFn)
            }, false)
        }

        // 拖拽元素添加鼠标按下事件
        el.addEventListener('mousedown', mouseDownFn, false)
    }
}
</script>
<template>
    <!-- 
        自定义指令 v-color 中配置传参和修饰符,<script setup> 中通过 mounted(el, binding, vnode, prevVnode) 中第二个参数对象 binding 获取:
            arg:传递给指令的参数(如果有的话)。例如在 v-my-directive:foo 中,arg 为 "foo"。
            modifiers:包含修饰符(如果有的话) 的对象。例如在 v-my-directive.foo.bar 中,修饰符对象为 {foo: true,bar: true}。 
    -->
    <div v-drag v-color:myprop.hehe="{ color: 'yellow' }" v-bind:class="{ box: true }">{
   
   { message }}</div>
</template>
<style scoped>
.box {
    width: 150px;
    height: 150px;
    color: #fff;
    font-size: 24px;
    text-align: center;
    line-height: 150px;
    background-color: red;

    position: fixed;
    top: 0;
    left: 500px;

    cursor: move;
}
</style>

控制台打印参数:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UT8ggmBv-1685426006811)(Vue3课程笔记导读.assets/Vue指令生命周期.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pGP39WDP-1685426006812)(Vue3课程笔记导读.assets/image-20221230173216123.png)]

注:自定义指令属于破坏性更新。

13.1.3 权限按钮指令案例

<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>
    import { ref, reactive,  } from 'vue'
    
    // permission:登录成功后 localstorage 中存储用户信息
    localStorage.setItem('userId','admin')

    // mock(模拟) 后台返回的权限数据
    const permission = [
    	// 用户ID:当前页描述:操作
        'admin:shop:create',
        //'admin:shop:delete', //注释和隐藏,查看页面按钮变化
        'admin:shop:edit',
    ]
    
    const userId = localStorage.getItem('userId')
    const vHasShow = (el,bingding) => {
       if(!permission.includes(userId+':'+ bingding.value)){
       		//如果后台返回的权限数据不包含这个指令,则隐藏元素
           	el.style.display = 'none'
       }
    }
</script>
 
<style scoped lang='scss'>
    .btns{
        button{
            margin: 10px;
        }
    }
</style>

13.2 自定义全局指令

将一个自定义指令全局注册到应用层级也是一种常见的做法,这样的话在任何一个组件中都可以调用此全局指令。

如下,在 main.js 中定义一个全局指令:

// 导入 createApp 方法:每个 Vue 应用都是通过 createApp 函数创建一个新的应用实例:
import { createApp } from 'vue'
// 导入根组件
import App from './App.vue'

// 通过 createApp() 函数创建一个新的应用实例
// 我们传入 createApp 的对象实际上是一个组件,每个应用都需要一个“根组件”,其他组件将作为其子组件。
const app = createApp(App)

// 注册全局指令
app.directive('focus',{
    mounted: (el) => el.focus()
})

// 挂载应用:应用实例必须在调用了 .mount() 方法后才会渲染出来。该方法接收一个“容器”参数,可以是一个实际的 DOM 元素或是一个 CSS 选择器字符串
// .mount() 方法应该始终在整个应用配置和资源注册完成后被调用。同时请注意,不同于其他资源注册方法,它的返回值是根组件实例而非应用实例。
app.mount('#app')

在任意组件内调用上面注册的全局指令 v-focus

<template>
    <!-- 调用 main.js 中定义的全局指令 v-focus -->
    <input v-focus type="text" placeholder="演示自动获取焦点的全局指令">
</template>

页面效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HAZdaofa-1685426006812)(Vue3课程笔记导读.assets/image-20221230170208984.png)]

13.3 指令钩子

一个指令的定义对象可以提供几种钩子函数 (都是可选的):

const myDirective = {
    // 在绑定元素的 attribute 前
    // 或事件监听器应用前调用
    created(el, binding, vnode, prevVnode) {
    // 下面会介绍各个参数的细节
    },
    
    // 在元素被插入到 DOM 前调用
    beforeMount(el, binding, vnode, prevVnode) {},
    
    // 在绑定元素的父组件
    // 及他自己的所有子节点都挂载完成后调用
    mounted(el, binding, vnode, prevVnode) {},
    
    // 绑定元素的父组件更新前调用
    beforeUpdate(el, binding, vnode, prevVnode) {},
    
    // 在绑定元素的父组件
    // 及他自己的所有子节点都更新后调用
    updated(el, binding, vnode, prevVnode) {},
    
    // 绑定元素的父组件卸载前调用
    beforeUnmount(el, binding, vnode, prevVnode) {},
    
    // 绑定元素的父组件卸载后调用
    unmounted(el, binding, vnode, prevVnode) {}
}

指令的钩子会传递以下几种参数:

  • el:指令绑定到的元素。这可以用于直接操作 DOM。
  • binding:一个对象,包含以下属性。
    • value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2
    • oldValue:之前的值,仅在 beforeUpdateupdated 中可用。无论值是否更改,它都可用。
    • arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"
    • modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }
    • instance:使用该指令的组件实例。
    • dir:指令的定义对象。
  • vnode:代表绑定元素的底层 VNode。
  • prevNode:之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdateupdated 钩子中可用。

猜你喜欢

转载自blog.csdn.net/qq_39335404/article/details/130946863
今日推荐