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

前言

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

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

Vue全局指令:如何添加全局指令?(附2个常用自定义指令)_第1张图片

如何添加全局指令?

在上面文章中,提到过一种方法,在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个常用自定义指令)_第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参数是时间格式。

你可能感兴趣的:(vue)