少侠请重新来过 - Vue学习笔记(五) - 指令

210 阅读3分钟

指令

指令(Directives)是带有 v- 前缀的特殊属性。指令属性的值预期是单一 JavaScript 表达式。指令的职责就是当其表达式的值改变时相应地将某些行为应用到 DOM 上。

自定义指令

自定义指令是指,我们可以通过自己的业务需求内置的指令

注册
  • 局部注册
    new Vue({
      directives:{
            log:{
                inserted:function(el){
                    console.log(el);
                }
            }
        }
    })
    
  • 全局注册
    Vue.directive('focus',{
      inserted(el){
        el.focus()
      }
    })
    
directive选项

自定义指令通过几个钩子函数组成,每个钩子函数都是可选的。

  • bind
    • 只调用一次,指令第一次绑定到元素时调用,用此钩子函数可以定义一个绑定时执行一次的初始化动作。
  • inserted
    • 被绑定元素插入父节点时调用
  • update
    • 被绑定的元素所在的模板更新时调用,而不论绑定值是否变化,通过比较更新前后的绑定值,可以忽略不必要的模板更新
  • componentUpdated
    • 被绑定的元素再模板完成一次更新周期时调用
  • unbind
    • 只调用一次,指令与元素解绑时调用
钩子函数参数
  • el
    • 指令绑定的元素,可以用来直接操作dom
  • binding
    • name 指令名,不包括前缀
    • value 指令的绑定值
    • oldValue 指令绑定的前一个值,仅在updatecomponentUpdated钩子中可用
    • expression 绑定值的字符串形式
    • arg 传给指令的参数
    • modifiers 一个包含修饰符的对象。
  • vnode
    • Vue 编译生成的虚拟节点
  • oldVnode
    • 上一个虚拟节点,仅在updatecomponentUpdated钩子中可用

自定义组件的实践

<template>
    <div>
        <div class="main" v-clickoutside.esc='handleClose'>
            <button @click='show = !show'>点击我</button>
            <p v-show='show'>我是文字</p>
            <p v-show='show2' v-clickoutside='handleClose2'>我是文字2</p>
        </div>
    </div>
</template>

<script>

var nodeList = []; //存放需要响应的节点
var id = 0;//节点id
function handle(e){
  //遍历所有的节点
  nodeList.forEach(node=>{
    if(node.el.contains(e.target)){
      return false;
    }else{
      //如果当前点击的区域不是在节点上,执行函数
      //键盘响应esc键,当指令配置修饰符esc时,执行函数
      if(e.type != 'click' && !node.binding.modifiers.esc)return
      node.binding.value(e);
    }
  })
}
function keyDownEvent(e){
  //键盘响应函数
  if(e.keyCode == 27)handle(e);
}
document.addEventListener('click',handle);
document.addEventListener('keydown',keyDownEvent);
Vue.directive('clickoutside',{
  inserted(el,binding){
    el._id = id++;
    // 从nodeList中装载此节点。
    nodeList.push({
      id:el._id,
      el:el,
      binding:binding,
    })
  },
  unbind(el){
    // 从nodeList中卸载此节点。
    let len = nodeList.length;
    for (let i = 0; i < len; i++) {
      if(nodeList[i].id === el._id){
        nodeList.splice(i,1);
        break;
      }
    }
    delete el._id
  }
})

export default {
    data(){
        return{
            show:true,
            show2:true
        }
    },
    methods:{
        handleClose(){
            this.show = false
        },
        handleClose2(){
            this.show2 = false
        }
    }
}
</script>
<template>
    <div>
        <span v-time='time'></span>
    </div>
</template>

<script>

var Time = {
  //获取当前的时间戳
  getUnix(){
    return new Date().getTime()
  },
  //获取当天零点时间戳
  getTodayUnix(){
    var date = new Date();
    date.setHours(0);
    date.setMinutes(0);
    date.setSeconds(0);
    date.setMilliseconds(0);
    return date.getTime();
  },
  //获取今年1月1日的时间戳
  getYearUnix(){
    var 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){
    var date = new Date(time);
    var month = date.getMonth() + 1 < 10 ? '0'+ (date.getMonth() + 1) :  date.getMonth() + 1;
    var day = date.setDate() < 10 ? '0'+ (date.setDate()) :  date.setDate();
    return date.getFullYear() + '-' + month + '-' + day;
  },
  //转换时间
  getFormatTime(timestamp){
    var now = this.getUnix();
    var today = this.getTodayUnix();
    var year = this.getYearUnix();
    var time = (now - timestamp) / 1000;
    var tip = '';
    if(time <= 0){
      tip = '刚刚';
    }else if(Math.floor(time / 60) <= 0){
      tip = '刚刚';
    }else if(time < 3600){
      tip = Math.floor(time/60) + '分钟前';
    }else if(time >= 3600 && (timestamp - today) >= 0){
      tip = Math.floor(time/3600) + '小时前';
    }else if(time/86400 <= 31){
      tip = Math.floor(time/86400) + '天前';
    }else{
      tip = this.getLastDate(timestamp);
    }
    return tip;
  }
}
Vue.directive('time',{
  bind(el,binding){
    el.innerHTML = Time.getFormatTime(binding.value);
  }
})
export default {
    data(){
        return{
            time: 1539669588000
        }
    }
}
</script>