Vue全局指令:如何添加全局指令?(附2个常用自定义指令)

前言

前面有专门的文字,讲过Vue指令,以及如何使用指令,今天就来讲讲如何添加全局指令,并且附上2个非常适用的例子。

《Vue如何创建自定义指令?》

Vue全局指令:如何添加全局指令?(附2个常用自定义指令)

如何添加全局指令?

在上面文章中,提到过一种方法,在main.js(入口JS文件)中引入你已经写好的指令文件,可以省略文件后缀:

// main.js import focus from 'xxx/directive'

如果你有多个指令文件了?怎么引入?

Vue.use((Vue) => { ((requireContext) => { const arr = requireContext.keys().map(requireContext); (arr || []).forEach((directive) => { directive = directive.__esModule && directive.default ? directive.default : directive; Object.keys(directive).forEach((key) => { Vue.directive(key, directive[key]); }); }); })(require.context('../directives', false, /^\.\/.*\.js$/)); });

这里用到了require.context函数,require.context是webpack中,用来创建自己的(模块)上下文。
require.context函数接收三个参数:

1、要搜索的文件夹目录
2、是否还应该搜索它的子目录
3、以及一个匹配文件的正则表达式

我们搜索directives目录下的所有js文件,遍历装载指令。

下面我们来看看2个实用的自定义指令。

Vue全局指令:如何添加全局指令?(附2个常用自定义指令)

vue非本元素点击事件指令

这个指令的的作用是什么?

比如:一个按钮点击后弹出一个浮层,然后点击按钮外的所有事件,都关闭浮层。

export default { clickOut: { // 初始化指令 bind(el, binding, vnode) { function clickHandler(e) { // 这里判断点击的元素是否是本身,是本身,则返回 if (el.contains(e.target)) { return false; } // 判断指令中是否绑定了函数 if (binding.expression) { // 如果绑定了函数 则调用那个函数,此处binding.value就是handleClose方法 binding.value(e); } } // 给当前元素绑定个私有变量,方便在unbind中可以解除事件监听 el.__vueClickOutside__ = clickHandler; document.addEventListener('click', clickHandler); }, update() {}, unbind(el, binding) { // 解除事件监听 document.removeEventListener('click', el.__vueClickOutside__); delete el.__vueClickOutside__; } } }

然后,在main.js中这个指令,就可以使用了。

<span @click="showDialog" v-click-out="hideDialog">点击我打开否则关闭</span>

vue倒计时指令

var toZeroStr = (val, num = 2) => { num = num || 2; return (new Array(num) .join('0') + val) .slice(-num); } var milliseconds2HMS = (diff) => { const millisecond = diff % 1000; diff = diff - millisecond; return seconds2HMS(diff / 1000); } var seconds2HMS = (diff) => { const seconds = diff % 60; const minutes = (diff - seconds) % 3600; // const hours = (diff - minutes - seconds) % 86400; const hours = diff - minutes - seconds; return [hours / 3600, minutes / 60, seconds]; } export default { // 倒计时 countdown: { bind(el, binding, vnode) { const { componentOptions, data } = vnode; const listeners = componentOptions ? componentOptions.listeners : null; const on = data ? data.on : null; const events = listeners ? listeners : on ? on : null; if (events && typeof events === 'object' && Object.keys(events).length) { binding.customListeners = events; } }, inserted(el, binding, vnode) { let val = +binding.value; if (!val) { return; } const formatter = vnode.data.attrs.formatter; let timer = null; window.clearInterval(el.timer); const tFunction = () => { val -= 1000; let instance = milliseconds2HMS(val); if (val <= 0) { if (timer) { window.clearInterval(timer); timer = null; if (binding.customListeners) { binding.customListeners.complete && binding.customListeners.complete(); } } el.innerHTML = '0'; return; } el.innerHTML = formatter.replace(/(HH.+)(mm.+)(ss.+)/g, (str, $1, $2, $3) => { return str.replace(new RegExp($1, 'g'), !instance[0] ? '' : $1.replace(/HH/g, toZeroStr(instance[0]))) .replace(new RegExp($2, 'g'), !instance[0] && !instance[1] ? '' : $2.replace(/mm/g, toZeroStr(instance[1]))) .replace(new RegExp($3, 'g'), !instance[1] && !instance[2] ? '' : $3.replace(/ss/g, toZeroStr(instance[2]))); }); }; tFunction(); timer = window.setInterval(tFunction, 1000); el.timer = timer; }, update(el, binding, vnode) { if (binding.oldValue !== binding.value) { window.clearInterval(el.timer); binding.def.inserted(el, binding, vnode); } }, unbind(el, binding, vnode) { window.clearInterval(el.timer); el.timer = null; delete el.timer; const customListeners = binding.customListeners; if (customListeners) { delete binding.customListeners; } } } }

使用方法

<span v-countdown="10000" formatter='HH小时mm分ss秒'></span>

这里的v-countdown参数就是剩余秒数,如果你只有2个时间(起始结束时间),需要先行计算;formatter参数是时间格式。