Vue2自定义指令使用—按钮级别权限控制 + vue3中按钮级别权限控制的扩展

目录

 vue.directive讲解

例子1:设置表格数据自动滚动 

例子2:根据权限控制着按钮的展示

前提

方案

1.新建 permissions.js 文件

2.havePermission 插件(import { havePermission } from '@/utils')

3.在 main.js 文件中引入

4.使用-登录成功后、将权限数组缓存


此文为vue2的按钮控制使用

vue3版本如下链接:

vue3.0项目实战系列文章 - 自定义指令_BMG-Princess的博客-CSDN博客

 vue.directive讲解

1、vue.directive的作用

vue.directive是我们除了内置的指令(如v-model和v-show)之外的自定义指令。自定义指令是对普通DOM元素进行的底层操作,它是一种有效的的补充和扩展,不仅可以用于定义任何的dom操作,并且是可以复用的,

2、vue.directive的使用场景

  • 例如在图片加载完成前,用随机的背景色占位,图片加载完成后直接渲染出来
  • 还有高亮类的操作
  • 控制按钮的展示
  • 自定义操作dom
  • 使用自定义指令的方式

//会实例化一个指令,但这个指令没有参数 
`v-xxx`
 
// -- 将值传到指令中
`v-xxx="value"`  
 
// -- 将字符串传入到指令中,如`v-html="'<p>内容</p>'"`
`v-xxx="'string'"` 
 
// -- 传参数(`arg`),如`v-bind:class="className"`
`v-xxx:arg="value"` 
 
// -- 使用修饰符(`modifier`)
`v-xxx:arg.modifier="value"`  

3、使用vue.directive的4个demo

import Vue from "vue"; 
 
// 1、输入框聚焦
Vue.directive("focus", {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus();
  },
});
 
// 2、绑定背景颜色
Vue.directive('pin', function(el, binding) { //背景颜色
    el.style.background = binding.value
})
 
// 3、文字显示
Vue.directive('demo', {
  bind: function (el, binding, vnode) {
    var s = JSON.stringify
    el.innerHTML =
      'name: '       + s(binding.name) + '<br>' +
      'value: '      + s(binding.value) + '<br>' +
      'expression: ' + s(binding.expression) + '<br>' +
      'argument: '   + s(binding.arg) + '<br>' +
      'modifiers: '  + s(binding.modifiers) + '<br>' +
      'vnode keys: ' + Object.keys(vnode).join(', ')
  }
})

//4、该指令的元素被插入到dom时自动获得焦点
Vue.directive('focus',{
        /*inserted函数表示当绑定了该指令的元素被插入到dom时候会自动触发*/
        inserted(el){
            console.log(el);
            /*获得焦点*/
            el.focus();
        }
    })

 4.使用vue.directive的图片加载(此例子为子组件形式)

<template>
  <div>
    <div v-img="url" style="width: 500px; height: 500px;"></div>
  </div>
</template>
<script>
import Vue from "vue"; //需要引入
Vue.directive("img", {
    bind:function(el){    
    var color = Math.floor(Math.random() * 1000000);
    el.style.backgroundColor = "#" + color;
    },
  inserted: function (el, binding) {
    var img = new Image();
    img.src = binding.value;
    img.onload = function () {
      el.style.backgroundImage = "url(" + binding.value + ")";
    };
  },
});
 
export default {
  name: "directive",
  data() {
    return {
      url: "../../../1.jpg",//据具体图片存储文件夹而定
 
    };
  },
};
</script>

5.钩子函数
自定义指令也像组件那样存在钩子函数:

bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)
update:所在组件的 VNode 更新时调用,但是可能发生在其子
VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
unbind:只调用一次,指令与元素解绑时调用

所有的钩子函数的参数都有以下: 

el:指令所绑定的元素,可以用来直接操作 DOM
binding:一个对象,包含以下 property:

 `name`:指令名,不包括 v- 前缀。

`value`:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。

`oldValue`:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。

`expression`:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。

`arg`:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。

`modifiers`:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }

`vnode`:Vue 编译生成的虚拟节点

`oldVnode`:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用

例子1:设置表格数据自动滚动 

  • scroll.js文件如下
  • main.js引入scroll.js文件       import './assets/js/scroll'
  • 组件中使用      <el-table stripe border :data="数据" height="400'" v-auto-scroll>
import Vue from 'vue';
let timer = null;
let scrollBlockX = 0; // 滚动条位置;
let moveDir = 1 // 移动发现 1 正向  -1  方向
let scrollTop = 0; // 移动的距离


// 设置表格数据自动滚动
function dataScroll(el) {
  clearTimeout(timer);
  timer = setTimeout(() => {
    dataScroll(el);
  }, 50);
  let oTable = el.querySelectorAll(".el-table__body-wrapper")[0];
  scrollBlockX += moveDir; // 滚动条位置+1;

  oTable.scrollTo(0, scrollBlockX); //0到滚动条位置发生滚动
  // 判断是否触底
  if (scrollTop == oTable.scrollTop) { // 移动的距离达到滚动条长度:开始逆序
    console.log(1);
    moveDir *= -1;
    scrollTop = scrollTop + 100;
  } else { // 移动的距离 < 滚动条长度:正常移动
    scrollTop = oTable.scrollTop;
  }
}
//清除轮询,初始化
function init(el) {
  clearTimeout(timer);
  scrollBlockX = 0;
  moveDir = 1;
  scrollTop = 0;
  //返回文档中匹配指定 CSS 选择器的所有元素,返回NodeList对象。
  //scrollTo() 方法将文档滚动到指定的坐标:接受两个参数,分别是目标位置的水平和垂直坐标
  el && el.querySelectorAll(".el-table__body-wrapper")[0].scrollTo(0, 0)
}
//自定义指令:不仅可以用于定义任何的dom操作,并且是可以复用的
Vue.directive('auto-scroll', {
  bind(el) {
    // console.log('bind函数只会调用一次,指令第一次被绑定到元素被触发');
    init(el);
  },
  /*inserted函数表示当绑定了该指令的元素被插入到dom时候会自动触发*/
  inserted() {
    // console.log('inserted函数在组件被渲染时候调用');
  },
  update() {
    // console.log('update函数在所有组件的VNode对象更新时调用');
  },
  /*
   * el表示当顶了该指令的dom对象
   * binding是一个包含了指令各种信息的对象:指令名,指令值,指令表达式和一个包含了修饰符的对象
   * */
  async componentUpdated(el, binding, vNode, oldVNode) {
    // console.log('componentUpdated指令所在组件的VNode对象和其子类VNode对象全部更新后调用');
    // 首次/点击查询
    if (oldVNode.child.data.length == 0 || !oldVNode.isRootInsert) {
      init(el);
    }
    await new Promise(resolve => setTimeout(() => resolve(), 200));
    // 当滚动条出现时开始滚动
    if (!Array.from(el.classList).includes("el-table--scrollable-y")) return false;
    dataScroll(el);
    // 穿过(进入)被选元素时
    let oTable = el.querySelectorAll(".el-table__body-wrapper")[0];
    oTable.addEventListener('mouseenter', () => {
      clearTimeout(timer);
    })
    // 离开被选元素时
    oTable.addEventListener('mouseleave', () => {
      clearTimeout(timer);
      let oTable = el.querySelectorAll(".el-table__body-wrapper")[0];
      scrollBlockX = oTable.scrollTop - moveDir // 滚动条位置
      scrollTop = scrollBlockX
      dataScroll(el);
    })
  },
  unbind() {
    // console.log('unbind指令解绑时候被调用');
  }
})

例子2:根据权限控制着按钮的展示

前提

  • 项目中控制着按钮的展示
  • 权限系统中添加需要控制的按钮
  •  配置好后由接口返回按钮列表信息
["alarmReports:export",
"stationInfo:data",
 "stationSet:set5",
 "stationSet:set4",
 "stationSet:set3",
 "stationSet:set1",
 "stationList:use"
]

方案

1.新建 permissions.js 文件

import Vue from 'vue';
import { havePermission } from '@/utils'

// 检测是否有权限
// 使用Vue.directive声明自定义指令permission
Vue.directive('permission', {
  inserted(el, binding, vnode) {
    // console.log(el.localName, binding, vnode)
    const permission = binding.value
    const result = havePermission(permission)
    const tagName = el.localName
    if (!result) {
      // switch (tagName) { 
      //   case 'button': // 按钮权限控制-删除tag
      //     el.remove()
      //     break
      //   case 'div':
      //     el.remove()
      //     break
      //   case 'span':
      //     el.remove()
      //     break
      //     case 'img':
      //       el.remove()
      //       break
      // }
      el.remove()
    }
  }
})
/**
 * @description: 表单防止重复提交指令
 * @param {*}
 * @return {*}
 * @author: gumingchen
 */
Vue.directive('repeat', {
  mounted(el, binding) {
    el.addEventListener('click', () => {
      if (!el.disabled) {
        el.disabled = true
        setTimeout(() => {
          el.disabled = false
        }, binding.value || 2000)
      }
    })
  }
})

2.havePermission 插件(import { havePermission } from '@/utils')

/**
 * @description: 判断是否有按钮级权限1
 * @param {String} permission 多个使用 & 或 | 分隔开
 * @param {String} separator 分隔符:&-并且 |-或者
 * @return {*}
 * @author: gumingchen
 */
 export function havePermission(permission, separator = '&') {
  let result = false
  const permissions = permission.split(separator)
  let fn = ''
  switch (separator) {
    case '&':
      fn = 'every'
      break
    case '|':
      fn = 'some'
      break
  }
  const list = JSON.parse(localStorage.getItem('buttonList')) || [];
  result = fn && permissions[fn](item => {
    return list.indexOf(item) !== -1
  })
  return result
}

3.在 main.js 文件中引入

//自定义指令

import './assets/js/permissions';

4.使用-登录成功后、将权限数组缓存

1.数据例子如上

// 接口返回 - 缓存权限数据

const buttonList = 返回数组
localStorage.setItem('buttonList',JSON.stringify(buttonList));

2.组件中:

<el-table-column label="操作" width="300" v-if="havePermission('sourceOfP:use|sourceOfP:change|sourceOfP:delete', '|')">
            <template slot-scope="scope">
              <dr-button v-permission="'sourceOfP:use'" v-if="!scope.row.disable" message="停用"
                icon="static/img/tingyong.png" csstyl="btn-tingyong" @click="handleStop(scope.row)"></dr-button>
              <dr-button v-permission="'sourceOfP:use'" v-else message="启用" icon="static/img/qiyong.png"
                csstyl="btn-qiyong" @click="handleStop(scope.row)"></dr-button>
              <dr-button v-permission="'sourceOfP:change'" message="编辑" icon="static/img/edits.png" csstyl="btn-bianji"
                @click="changeSourceOfPPage(scope.row)"></dr-button>
              <dr-button v-permission="'sourceOfP:delete'" message="删除" icon="static/img/delete1.png"
                csstyl="btn-shanchu" @deleteCommon="deleteCommon" :value="scope.row" name="此单位"></dr-button>
            </template>
          </el-table-column>

3.说明:havePermission调用全局方法

//判断是否有按钮级权限2
    Vue.prototype.havePermission = function(permission, separator = '&') {
      let result = false
      const permissions = permission.split(separator)
      let fn = ''
      switch (separator) {
        case '&':
          fn = 'every'
          break
        case '|':
          fn = 'some'
          break
      }
      const list = JSON.parse(localStorage.getItem('buttonList')) || [];
      result = fn && permissions[fn](item => {
        return list.indexOf(item) !== -1
      })
      return result
    };
  };

4.v-permission 控制按钮及标签的展示

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BMG-Princess

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值