vue自界说指令先容
Vue 除了内置的一系列指令 (好比 v-model 或 v-show) 之外,Vue 还允许你注册自界说的指令
一个自界说指令由一个包含类似组件生命周期钩子的对象来界说。钩子函数会吸收到指令所绑定元素作为其参数。下面是一个自界说指令的例子,当一个 input 元素被 Vue 插入到 DOM 中后,它会被自动聚焦:
- <script setup>
- // 在模板中启用 v-focus
- const vFocus = {
- mounted: (el) => el.focus()
- }
- </script>
- <template>
- <input v-focus />
- </template>
复制代码 在 <script setup> 中,任何以 v 开头的驼峰式命名的变量都可以被用作一个自界说指令。在上面的例子中,vFocus 即可以在模板中以 v-focus 的情势利用。
在没有利用 <script setup> 的情况下,自界说指令必要通过 directives 选项注册:
- export default {
- setup() {
- /*...*/
- },
- directives: {
- // 在模板中启用 v-focus
- focus: {
- /* ... */
- }
- }
- }
复制代码 将一个自界说指令全局注册到应用层级也是一种常见的做法:
- const app = createApp({})
- // 使 v-focus 在所有组件中都可用
- app.directive('focus', {
- /* ... */
- })
复制代码 指令钩子
一个指令的界说对象可以提供几种钩子函数 (都是可选的):
- const myDirective = {
- // 在绑定元素的 attribute 前
- // 或事件监听器应用前调用
- created(el, binding, vnode) {
- // 下面会介绍各个参数的细节
- },
- // 在元素被插入到 DOM 前调用
- beforeMount(el, binding, vnode) {},
- // 在绑定元素的父组件
- // 及他自己的所有子节点都挂载完成后调用
- mounted(el, binding, vnode) {},
- // 绑定元素的父组件更新前调用
- beforeUpdate(el, binding, vnode, prevVnode) {},
- // 在绑定元素的父组件
- // 及他自己的所有子节点都更新后调用
- updated(el, binding, vnode, prevVnode) {},
- // 绑定元素的父组件卸载前调用
- beforeUnmount(el, binding, vnode) {},
- // 绑定元素的父组件卸载后调用
- unmounted(el, binding, vnode) {}
- }
复制代码 只有当所需功能只能通过直接的 DOM 操纵来实现时,才应该利用自界说指令。其他情况下应该尽大概地利用 v-bind 如许的内置指令来声明式地利用模板,如许更高效,也对服务端渲染更友好。
钩子参数
指令的钩子会通报以下几种参数:
- el:指令绑定到的元素。这可以用于直接操纵 DOM。
- binding:一个对象,包含以下属性。
- value:通报给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2。
- oldValue:之前的值,仅在 beforeUpdate 和 updated 中可用。无论值是否更改,它都可用。
- arg:通报给指令的参数 (假如有的话)。例如在 v-my-directive:foo 中,参数是 "foo"。
- modifiers:一个包含修饰符的对象 (假如有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }。
- instance:利用该指令的组件实例。
- dir:指令的界说对象。
- vnode:代表绑定元素的底层 VNode。
- prevVnode:代表之前的渲染中指令所绑定元素的 VNode。仅在 beforeUpdate 和 updated 钩子中可用。
举例来说,像下面如许利用指令:
- <div v-example:foo.bar="baz">
复制代码 binding 参数会是一个如许的对象:
- {
- arg: 'foo',
- modifiers: { bar: true },
- value: /* `baz` 的值 */,
- oldValue: /* 上一次更新时 `baz` 的值 */
- }
复制代码 和内置指令类似,自界说指令的参数也可以是动态的。举例来说:
- <div v-example:[arg]="value"></div>
复制代码 除了 el 外,其他参数都是只读的,不要更改它们。若你必要在差别的钩子间共享信息,保举通过元素的 dataset attribute 实现。
简化情势
对于自界说指令来说,一个很常见的情况是仅仅必要在 mounted 和 updated 上实现相同的行为,除此之外并不必要其他钩子。这种情况下我们可以直接用一个函数来界说指令,如下所示:
- <div v-color="color"></div>
复制代码- app.directive('color', (el, binding) => {
- // 这会在 `mounted` 和 `updated` 时都调用
- el.style.color = binding.value
- })
复制代码 对象字面量
假如你的指令必要多个值,你可以向它通报一个 JavaScript 对象字面量。别忘了,指令也可以吸收任何合法的 JavaScript 表达式。
- <div v-demo="{ color: 'white', text: 'hello!' }"></div>
复制代码- app.directive('demo', (el, binding) => {
- console.log(binding.value.color) // => "white"
- console.log(binding.value.text) // => "hello!"
- })
复制代码 在组件上利用
当在组件上利用自界说指令时,它会始终应用于组件的根节点,和透传 attributes 类似。
- <MyComponent v-demo="test" />
复制代码- <!-- MyComponent 的模板 -->
- <div> <!-- v-demo 指令会被应用在此处 -->
- <span>My component content</span>
- </div>
复制代码 必要注意的是组件大概含有多个根节点。当应用到一个多根组件时,指令将会被忽略且抛出一个告诫。和 attribute 差别,指令不能通过 v-bind=“$attrs” 来通报给一个差别的元素。
利用自界说指令实现页面按钮权限控制
实现思绪:
- 用户登录成功后, 在 router.beforeEach() 发起请求获取用户所拥有的权限,并将权限存储到 store 中
- 初始化 hasBtnPermi 对象, 并导入到入口文件 mian.js
- 在钩子函数 componentUpdated 判定是否有该按钮权限, 没有就用 removeChild() 方法移除按钮元素
在路由守卫获取按钮权限
- /**
- * permission.js
- */
- import router from './router';
- import store from './store';
- const whiteList = ['/login', '/404'];
- import { getSessStore } from '@/util/store';
- router.beforeEach((to, from, next) => {
- let token = getSessStore('token');
- if (token) {
- /* has token*/
- if (to.path === '/login') {
- next({ path: '/' });
- } else {
- store.dispatch('GenerateRoutes').then(() => { // 获取按钮权限
- next({ ...to, replace: true }); // hack方法 确保addRoutes已完成
- })
- }
- } else {
- if (whiteList.indexOf(to.path) !== -1) {
- next()
- } else {
- next('/login');
- }
- }
- })
复制代码 配置store
- /**
- * store/index.js
- */
- import Vue from 'vue'
- import Vuex from 'vuex'
- import user from './modules/user'
- import common from './modules/common'
- import tags from './modules/tags'
- import leave from './modules/leave'
- import checkin from './modules/checkin'
- import getters from './getters'
- Vue.use(Vuex)
- const store = new Vuex.Store({
- modules: {
- user,
- common,
- tags,
- leave,
- checkin
- },
- getters,
- })
- export default store
复制代码 配置getters.js
- /**
- * store/getters.js
- */
- const getters = {
- buttons: state => state.leave.buttons,
- }
- export default getters
复制代码 leave.js
- /**
- * store/modules/leave.js
- */
- import { getMenuByLogin } from '@/api/menu';
- import Vue from "vue";
- const checkIn = {
- state: {
- buttons: [],
- },
- mutations: {
- SET_BUTTONS: (state, buttons) => {
- state.buttons = buttons
- },
- },
- actions: {
- // 生成路由
- GenerateRoutes({ commit }, type) {
- return new Promise((resolve) => {
- // 向后端请求路由数据
- getMenuByLogin(type).then(({ data }) => {
- let btns = [];
- data.data.forEach((v) => {
- if (v.code) {
- btns.push(v.code);
- }
- })
- console.log('按钮--------', btns);
- commit('SET_BUTTONS', btns);
- resolve(btns);
- })
- // })
- })
- }
- }
- }
复制代码 store 文件结构如下图所示
配置自界说指令
- /**
- * btnPermi.js
- */
- import store from "@/store";
- const hasBtnPermi = {
- // 钩子函数
- bind(el, binding, vnode, oldVnode) {
- // 指令绑定到元素上时调用
- },
- inserted(el, binding, vnode, oldVnode) {
- // 被绑定元素插入父节点时调用
- },
- update(el, binding, vnode, oldVnode) {
- // 被绑定于元素所在的模板更新时调用
- },
- componentUpdated(el, binding, vnode, oldVnode) {
- // 被绑定元素所在模板完成一次更新周期时调用
- const { value } = binding; // 获取页面上自定义指令v-hasBtnPermi传入的值, 如: btn_one
- const permissions = store.getters.buttons; // 从vuex获取所有按钮权限数组
- if (permissions.length > 0) {
- const hasPermissions = permissions.includes(value); // 从权限列表里查找是否有该按钮权限
-
- if (!hasPermissions) { // 如果没有权限, 移除当前的按钮元素
- el.parentNode && el.parentNode.removeChild(el);
- }
- }
- },
- unbind(el, binding, vnode, oldVnode) {
- // 指令与元素解绑时调用
- }
- };
- const install = function(Vue) {
- Vue.directive('hasBtnPermi', hasBtnPermi)
- }
- if (window.Vue) {
- window['hasBtnPermi'] = hasBtnPermi
- Vue.use(install); // eslint-disable-line
- }
- export default install
复制代码 btnPermi.js 文件需引入入口文件 main.js 内里
- /**
- * main.js
- */
- import "./permission"; // 权限
- import btnPermi from "./btnPermi.js";
- Vue.use(btnPermi );
复制代码 页面上利用
- <!-- btn_one 为按钮唯一字段 -->
- <el-button v-hasBtnPermi="'btn_one'" size="small" @click="departure">按钮</el-button>
复制代码 总结
用户登录成功后, 在 router.beforeEach() 发起请求获取用户所拥有的权限,并将权限存储到 store 中, 初始化 hasBtnPermi 对象, 并导入到入口文件 mian.js , 在 componentUpdated 钩子函数内获取页面上自界说指令v-hasBtnPermi传入的值, 去权限数组里查找是否有改按钮权限,假如没有就利用 DOM 原生方法移 removeChild() 除移除当前的按钮元素
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |