vue-cli自定义指令

431 阅读2分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

请移步 vue-cli自定义指令-从实例入门,掌握最基础的语法概念在来阅读此篇。

参数熟悉

也是直接从一个demo开始进一步了解这些指令,这里采用局部注册。

我们使用自定义指令v-learn将钩子函数的参数打印出来,这里打印的是inserted钩子函数的参数,其他钩子函数(也叫生命周期)也同理,只是调用时间、次数不同(inserted里可以写各种js语句)。

<template>
  <div class="container">
    <div v-learn:hello.a.b="message">12321</div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      message: "菜鸟教程!",
    };
  },
  directives: {
    learn: {
      inserted(el, binding, vnode) {
        console.log("el --------", el);
        console.log("name --------", binding.name);
        console.log("value --------", binding.value);
        console.log("expression --------", binding.expression);
        console.log("arg --------", binding.arg);
        console.log("modifiers --------", binding.modifiers);
        console.log("vnode --------", vnode);
      },
    },
  },
};
</script>

打印结果如下: image.png

实际应用

v-drag

使用自定义指令v-drag,实现拖拽功能,可在页面可视区域任意拖拽元素,这里我采用的是局部注册,关键代码如下:

  directives: {
    drag: {
      inserted: function (el) {
        el.style.cursor = "move";
        el.onmousedown = function (e) {
          let disx = e.pageX - el.offsetLeft;
          let disy = e.pageY - el.offsetTop;
          document.onmousemove = function (e) {
            console.log(e);
            let x = e.pageX - disx;
            let y = e.pageY - disy;
            let maxX =
              document.body.clientWidth -
              parseInt(window.getComputedStyle(el).width);
            let maxY =
              document.body.clientHeight -
              parseInt(window.getComputedStyle(el).height);
            if (x < 0) {
              x = 0;
            } else if (x > maxX) {
              x = maxX;
            }

            if (y < 0) {
              y = 0;
            } else if (y > maxY) {
              y = maxY;
            }
            el.style.left = x + "px";
            el.style.top = y + "px";
          };
          document.onmouseup = function () {
            document.onmousemove = document.onmouseup = null;
          };
        };
      },
    },
  },

使用时只需给元素加上 v-drag指令

 <div class="drag" v-drag></div>

注:拖动元素必须设置position属性

.drag {
  margin-top: 50px;
  width: 200px;
  height: 200px;
  line-height: 200px;
  text-align: center;
  background: rgb(252, 220, 220);
  position: relative;  
}

v-relativeTime

使用自定义指令v-relativeTime,实现将时间戳转换为相对时间的功能 即我们常常在各种网站或者APP上看到的,当有一条新内容发布后,不直接显示发布时间,而是显示为几分钟前,刚刚等这样的相对时间。

实现思路也很简单,获取指令上赋值的时间戳,与当前时间作比较,通过差值判断相对时间显示的文字,将文字插入至元素中

关键代码如下: 在main.js中全局注册

Vue.directive('relativeTime', {
  bind(el, binding) {
    const Time = {
    
      // 获取当前时间戳
      getUnix() {
        
        const date = new Date();
        return date.getTime();
      },
      // 获取今天0点0分0秒的时间戳
      getTodayUnix() {
        
        const date = new Date();
        date.setHours(0);
        date.setMinutes(0);
        date.setSeconds(0);
        date.setMilliseconds(0);
        return date.getTime();
      },
      // 获取今年1月1日0点0分0秒的时间戳
      getYearUnix() {
        
        const date = new Date();
        date.setMonth(0);
        date.setDate(1);
        date.setHours(0);
        date.setMinutes(0);
        date.setSeconds(0);
        date.setMilliseconds(0);
        return date.getTime();
      },
      // 获取标准年月日
      getLastDate(time) {
        
        const date = new Date(time);
        const year = date.getFullYear();
        const month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
        const day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
        return year + '-' + month + '-' + day;
      },
      // 转换时间
      getFormatTime(timestamp) {
        
        const now = this.getUnix(); // 当前时间戳
        const today = this.getTodayUnix(); // 今天0点0分0秒时间戳
        const year = this.getYearUnix(); // 今年1月1日0点0分0秒的时间戳
        const timer = (now - timestamp) / 1000; // 获取传递进来的时间和当前时间的差值,并转换为秒级时间戳
        let tip;
        if(timer < 60 || Math.floor(timer / 60) <= 0) {
        
          tip = '刚刚'
        } else if(timer < 3600) {
        
          tip = Math.floor(timer / 60) + '分钟前';
        } else if(timer >= 3600 && (timestamp - today) >= 0) {
        
          tip = Math.floor(timer / 3600) + '小时前';
        } else if((timer / 86400) <= 31){
        
          tip = Math.floor(timer / 86400) + '天前';
        } else {
        
          tip = this.getLastDate(timestamp);
        }
        return tip;
      }
    }
    el.innerHTML = Time.getFormatTime(binding.value)
    el.__timeout__ = setInterval(() => {
      el.innerHTML = Time.getFormatTime(binding.value)
    }, 6000)
  },
  unbind(el) {
    clearInterval(el.innerHTML)
    delete el.__timeout__
  }
})

使用时只需给元素加上 v-relativeTime指令,将时间戳传给该指令,便会自动计算出相对于当前时间的时间

 <div  v-relativeTime="1636083312221"></div>

显示为:

image.png

在实际的开发中,根据项目需求创建更高级灵活的自定义指令,使你的代码更加简洁。 当我们在项目中需要全局注册多个自定义指令时,则会造成main.js中代码臃肿,可以考虑批量注册,详见下文。