【前端之日常工作】常使用的自定义指令集合

>指令有:只能输入正整数指令、 只能输入数字和两位小数点指令、按钮权限指令、触摸事件指令、全局loading指令


```
/* 
 ** 自定义指令
 */

import Vue from 'vue'
import * as storage from '@/utils/storage'

/*==================|-- * 只能输入正整数指令 * start --|==================*/
// 使用方法: v-enter-number
Vue.directive('enterNumber', {
  inserted: function (el) {
    el.addEventListener("keypress", function (e) {
      e = e || window.event;
      let charcode = typeof e.charCode == 'number' ? e.charCode : e.keyCode;
      let re = /\d/;
      if (!re.test(String.fromCharCode(charcode)) && charcode > 9 && !e.ctrlKey) {
        if (e.preventDefault) {
          e.preventDefault();
        } else {
          e.returnValue = false;
        }
      }
    });

    let legalContent, //开启输入法之前的输入内容
      LOCK = false; //是否开启中文输入法
    el.addEventListener('compositionstart', (e) => {
      legalContent = e.target.value; //保存中文输入法之前的内容
      LOCK = true; //加上锁
    }, false);

    el.addEventListener('compositionend', (e) => {
      e.target.value = legalContent;
      LOCK = false; // 解锁
    }, false);

    el.addEventListener('input', (e) => {
      if (!LOCK) {
        e.target.value = e.target.value.replace(/\D/, '');
      }
    }, false);
  },
  update: function (el) {
    el.addEventListener('paste', (e) => {
      e.preventDefault();
    }, false);
  }
});
/*==================|-- * 只能输入正整数指令 * end --|==================*/


/*==================|-- * 只能输入正数(包含小数)指令 * start --|==================*/
// 使用方法: v-enter-number-point
Vue.directive('enterNumberPoint', {
  inserted: function (el) {
    // 用来处理中文输入法的情况  start
    let input = el.getElementsByTagName("input")[0]  //因为是用的el-input,所以这么拿到input
    input.setAttribute("type", "number"); //设置类型是number,解决输入中文的问题,尝试过很多种方法,但最终发现,只有设置为number可以解决
    input.setAttribute("step", "0.01"); //解决输入不了,如1.1这种的数据
    // 用来处理中文输入法的情况  end


    let isSelect = false
    el.addEventListener("keypress", function (e) {  //在控件有焦点的情况下按下键时发生
      e = e || window.event;
      let charcode = typeof e.charCode == 'number' ? e.charCode : e.keyCode;
      let re = /\d/;
      if (charcode == 46) {
        if (e.target.value && e.target.value.includes('.')) {
          e.preventDefault();
        }
      } else if (!re.test(String.fromCharCode(charcode)) && charcode > 9 && !e.ctrlKey) {
        if (e.preventDefault) {
          e.preventDefault();
        } else {
          e.returnValue = false;
        }
      } else {
        if (!isSelect) {  //处于截断时候的bug
          if (e.target.value && e.target.value.includes('.')) { //如果输入小数的时候
            let len = e.target.value.toString().split(".")[1].length;
            if (len === 2 || e.key === '.') {
              e.preventDefault();
            }
          }
        }
      }
    });

    //失去焦点=>保留指定位小数
    el.addEventListener("keyup", e => {
      isSelect = false
      // console.log('keyup', e, e.target.value)
    }, false)

    //选中
    el.addEventListener("select", e => {
      isSelect = true
      // console.log('select', e, e.target.value)
    }, false)

    //点击
    el.addEventListener("click", e => {
      isSelect = false
      // console.log('click', e, e.target.value)
    }, false)

    //失去焦点
    el.addEventListener("focusout", e => {
      isSelect = true
      // console.log('focusout', e, e.target.value)
    }, false)

    let legalContent, //开启输入法之前的输入内容
      LOCK = false; //是否开启中文输入法
    el.addEventListener('compositionstart', (e) => {
      legalContent = e.target.value; //保存中文输入法之前的内容
      LOCK = true; //加上锁
      isSelect = true
    }, false);

    el.addEventListener('compositionend', (e) => {
      e.target.value = legalContent;
      LOCK = false; // 解锁
      isSelect = true
    }, false);

    el.addEventListener('input', (e) => {
      if (LOCK) return 0;
      if (!LOCK) {
        setInputVal(e)
      } else {
      }
    }, false);

    function setInputVal (e) {
      let dataLen = e.data ? e.data.length : 1
      let len = e.key ? 1 : dataLen
      if (e.target.value && e.target.value.includes('.')) { //如果输入小数的时候
        if (!/^([1-9]+\d*|0{1})\.\d{0,2}$/.test(e.target.value)) {
          e.target.value = e.target.value.slice(0, e.target.value.length - len)
        }
      } else {     //如果输入整数的时候
        if (!/^([1-9]+\d*|0{1})$/.test(e.target.value)) {
          e.target.value = e.target.value.slice(0, e.target.value.length - len)
        }
      }
    }
  },
  update: function (el) {
    el.addEventListener('paste', (e) => {
      console.log('paste')
      e.preventDefault();  //禁止复制,防止不知道复制到是什么东西
    }, false);
  }
});
/*==================|-- * 只能输入正数(包含小数)指令 * end --|==================*/


/*==================|-- * 后台管理按钮权限指令 * start --|==================*/
// 使用方法: v-has="`/table/Table_Update`"
Vue.directive('has', {
  bind: function (el, binding) {
    if (!binding.value) {
      return el.style.display = 'none';
    }
    if (!Vue.prototype.$_has(binding.value)) {
      el.style.display = 'none';
    }
  }
});
//权限检查方法
Vue.prototype.$_has = function (value) {
  let isExist = false;
  let perms = storage.get('perms') || []
  if (perms === undefined || perms === null || !perms) {
    return false;
  }

  for (let item of perms) {
    if (item && item.indexOf(value) > -1) {
      isExist = true;
      break;
    }
  }
  // console.log('权限', perms)
  return isExist;
};
/*==================|-- * 权限指令 * end --|==================*/

```

###监听触摸事件
```
import vue from 'vue'

/************* 事例 start **************
 <div class="box" 
     v-tap="(e)=>vueTouch('点击',e)" 
     v-longtap="(e)=>vueTouch('长按',e)" 
     v-swipeleft="(e)=>vueTouch('左滑',e)"
     v-swiperight="(e)=>vueTouch('右滑',e)"
     v-swipeup="(e)=>vueTouch('上滑',e)"
     v-swipedown="(e)=>vueTouch('下滑',e)"
  >{{ name }}</div>
************* 事例 end **************/

function vueTouch(el, binding, type) {
  var _this = this;
  this.obj = el;
  this.binding = binding;
  this.touchType = type;
  this.vueTouches = {
    x: 0,
    y: 0
  };
  this.vueMoves = true;
  this.vueLeave = true;
  this.longTouch = true;
  this.vueCallBack = typeof (binding.value) == "object" ? binding.value.fn : binding.value;
  this.obj.addEventListener("touchstart", function (e) {
    _this.start(e);
  }, false);
  this.obj.addEventListener("touchend", function (e) {
    _this.end(e);
  }, false);
  this.obj.addEventListener("touchmove", function (e) {
    _this.move(e);
  }, false);
};
vueTouch.prototype = {
  start: function (e) {
    this.vueMoves = true;
    this.vueLeave = true;
    this.longTouch = true;
    this.vueTouches = {
      x: e.changedTouches[0].pageX,
      y: e.changedTouches[0].pageY
    };
    this.time = setTimeout(function () {
      if (this.vueLeave && this.vueMoves) {
        this.touchType == "longtap" && this.vueCallBack(this.binding.value, e);
        this.longTouch = false;
      };
    }.bind(this), 500);
  },
  end: function (e) {
    var disX = e.changedTouches[0].pageX - this.vueTouches.x;
    var disY = e.changedTouches[0].pageY - this.vueTouches.y;
    clearTimeout(this.time);
    if (Math.abs(disX) > 10 || Math.abs(disY) > 100) {
      this.touchType == "swipe" && this.vueCallBack(this.binding.value, e);
      if (Math.abs(disX) > Math.abs(disY)) {
        if (disX > 10) {
          this.touchType == "swiperight" && this.vueCallBack(this.binding.value, e);
        };
        if (disX < -10) {
          this.touchType == "swipeleft" && this.vueCallBack(this.binding.value, e);
        };
      } else {
        if (disY > 10) {
          this.touchType == "swipedown" && this.vueCallBack(this.binding.value, e);
        };
        if (disY < -10) {
          this.touchType == "swipeup" && this.vueCallBack(this.binding.value, e);
        };
      };
    } else {
      if (this.longTouch && this.vueMoves) {
        this.touchType == "tap" && this.vueCallBack(this.binding.value, e);
        this.vueLeave = false
      };
    };
  },
  move: function (e) {
    this.vueMoves = false;
  }
};
vue.directive("tap", {
  bind: function (el, binding) {
    new vueTouch(el, binding, "tap");
  }
});
vue.directive("swipe", {
  bind: function (el, binding) {
    new vueTouch(el, binding, "swipe");
  }
});
vue.directive("swipeleft", {
  bind: function (el, binding) {
    new vueTouch(el, binding, "swipeleft");
  }
});
vue.directive("swiperight", {
  bind: function (el, binding) {
    new vueTouch(el, binding, "swiperight");
  }
});
vue.directive("swipedown", {
  bind: function (el, binding) {
    new vueTouch(el, binding, "swipedown");
  }
});
vue.directive("swipeup", {
  bind: function (el, binding) {
    new vueTouch(el, binding, "swipeup");
  }
});
vue.directive("longtap", {
  bind: function (el, binding) {
    new vueTouch(el, binding, "longtap");
  }
});

// 自动聚焦
vue.directive("focus", {
  inserted: function (el, value) {
    if (value) {
      console.log('自动聚焦')
      el.focus();
    }
  }
});
```

###全局loading
```
///loading.less
@keyframes custom-loading-rotate {
  from {
    transform: rotate(0deg);
  }

  to {
    transform: rotate(360deg);
  }
}

.custom-loading {
  width: 100%;
  height: 100%;
  position: fixed;
  left: 0;
  top: 0;
  z-index: 100;
  background-color: rgba(255, 255, 255, 0.5);
  overflow: hidden;
}

.custom-loading .custom-loading-round {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 4px solid #f9c653;
  border-left-color: transparent;
  animation: custom-loading-rotate 1s linear infinite;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
}
```
```
import vue from 'vue'
import '@/assets/loading.less'

//使用方法: v-loading="isShowLoding"

vue.directive('loading', {
  bind: (el, binding) => {
    const tempDiv = document.createElement('div')
    tempDiv.className = 'custom-loading'
    const round = document.createElement('div')
    round.className = 'custom-loading-round'
    tempDiv.appendChild(round)
    el.loadingElement = tempDiv
    const curStyle = window.getComputedStyle(el)
    const position = curStyle.position
    if (position === 'absolute' || position === 'relative') {
      el.style.position = position
    } else {
      el.style.position = 'relative'
    }
    if (binding.value) {
      el.appendChild(tempDiv)
    }
  },
  update: (el, binding) => {
    if (binding.value) {
      if (el.loadingElement.parentNode === null) {
        el.appendChild(el.loadingElement)
      }
    } else {
      if (el === el.loadingElement.parentNode) {
        el.removeChild(el.loadingElement)
      }
    }
  },
  unbind: (el) => {
    if (el.loadingElement.parentNode === el) {
      el.removeChild(el.loadingElement)
    }
    el.loadingElement = null
  }
})
```
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js的自定义指令可以让我们在模板中直接使用自定义的指令,从而实现一些特殊的功能或交互效果。自定义指令是Vue.js提供的一种扩展机制,它允许我们在编写Vue.js应用程序时自定义DOM元素的行为。 自定义指令主要由两部分组成:指令定义和指令钩子函数。 指令定义是一个包含指令名称、绑定值、修饰符等属性的对象,用来描述指令的属性和行为。指令钩子函数是指在绑定元素插入到DOM中、更新DOM时、解绑元素等特定时刻执行的函数,用来实现指令的具体功能。 下面是一个简单的自定义指令示例,用来实现点击外部区域隐藏弹窗的功能: ```javascript Vue.directive('click-outside', { bind: function(el, binding, vnode) { el.clickOutsideEvent = function(event) { if (!(el == event.target || el.contains(event.target))) { vnode.context[binding.expression](event); } }; document.body.addEventListener('click', el.clickOutsideEvent); }, unbind: function(el) { document.body.removeEventListener('click', el.clickOutsideEvent); } }); ``` 在上面的例子中,我们通过`Vue.directive`方法注册了一个名为`click-outside`的自定义指令,该指令的功能是在点击指定元素外的区域时隐藏元素。 在指令的`bind`钩子函数中,我们绑定了一个事件监听器,用来监听`document.body`的点击事件。在事件处理函数中,我们判断点击的目标是否是指定元素或指定元素的子元素,如果不是,则调用指令绑定的方法,执行隐藏元素的操作。 在指令的`unbind`钩子函数中,我们移除了绑定的事件监听器,以避免内存泄漏。 使用自定义指令时,我们可以在模板中通过`v-指令名`的方式来调用指令,如下所示: ```html <div v-click-outside="hidePopup"></div> ``` 在上面的例子中,我们将`click-outside`指令绑定到一个`<div>`元素上,并指定了一个名为`hidePopup`的方法,用来隐藏弹窗。当用户点击该元素外的区域时,指令会自动触发绑定的方法,从而实现弹窗的隐藏。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值