指令
指令(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
指令绑定的前一个值,仅在update
和componentUpdated
钩子中可用expression
绑定值的字符串形式arg
传给指令的参数modifiers
一个包含修饰符的对象。
vnode
Vue
编译生成的虚拟节点
oldVnode
- 上一个虚拟节点,仅在
update
和componentUpdated
钩子中可用
- 上一个虚拟节点,仅在
自定义组件的实践
<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>
复制代码