自定义指令
自定义focus
const focus = {
inserted: function(el){
el.focus();
}
}
export default focus;
<input type="text" v-focus />
自定义test
import Vue from 'vue'
import App from './App.vue'
import focus from './directive/focus/index.js'
Vue.config.productionTip = false
Vue.directive('focus',focus);
Vue.directive('test',{
// bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作.
// inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中) .
// update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。
// 通过比较更新前后update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。
// 通过比较更新前后的绑定值,可以忽略不必要的模板更新。
// componentUpdated: 被绑定元素所在模板完成一次更新周期时调用.
// unbind: 只调用一次,指令与元素解绑时调用 。
bind:function(el, binding, vnode){
debugger
// el 指令所绑定的元素,可以用来直接操作 DOM.
el
var keys = []
for(var i in vnode){
keys.push(i)
}
// name: 指令名,不包括 v-前缀。
// value: 指令的绑定值,例如 v-my-directive=1+ 1”, value的值是2.
// oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用.无论
// 值是否改变都可用 。
// expression 绑定值的字符串形式。例如v-my-directive="1+ 1”,expression的值是”1+1”.
// arg 传给指令的参数。例如 v-my-directive:foo, arg 的值是 foo.
// modifiers 一个包含修饰符的对象 。 例如 v-my-directive.foo.bar,修饰符对象 modifiers的值是{ foo: true, bar: true }。
// vnode Vue 编译生成的虚拟节点
// oldVnode 上一个虚拟节点仅在 update 和 componentUpdated 钩子中可用
el.innerHTML =
'name:' + binding.name + '<br>' +
'value:' + binding.value + '<br>' +
'expression:' + binding.expression + '<br>' +
'argument:' + binding.arg + '<br>' +
'modifiers:' + JSON.stringify(binding.modifiers) + '<br>' +
'vnode keys:' + keys.join(', ')
}
});
new Vue({
render: h => h(App),
}).$mount('#app')
v-test 使用
<template>
<div id="parent">
<div v-test:msg.a.b="message"></div>
</div>
</template>
<script>
export default{
name: 'directive',
data(){
return{
message: 'some text'
}
}
}
</script>
点击外部关闭的下拉菜单
<template>
<div>
<div class="main" v-clickoutside="handleClose">
<button @click="show =! show">下拉</button>
<div class="dropdown" v-show="show">
<p>点击外部关闭的下拉菜单</p>
</div>
</div>
</div>
</template>
<script>
export default{
data(){
return{
show:false
}
},
methods:{
handleClose(){
this.show = false
}
}
}
</script>
<style>
.main{
width: 120px;
}
button{
display: block;
width: 100%;
color: #fff;
background-color: #39f;
border: 0;
padding: 6px;
text-align: center;
border-radius: 4px;
cursor: pointer;
outline: none;
position: relative;
}
button:active{
top: 1px;
left: 1px;
}
.dropdown{
width: 100%;
height: 150px;
margin: 5px 0;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 6px rgba(0,0,0,.2);
}
</style>
Vue.directive('clickoutside',{
bind:function(el, binding, vnode){
function documentHandler(e){
if(el.contains(e.target)){
return false;
}
if(binding.expression){
// 执行表达式
binding.value(e)
}
}
//在自定义指令中,不能再用 this.xxx 的形式在上下文中声明一个变量,
//所以用了 el.__vueClickOutside__ 引用了 docurnentHandler
el.__vueClickOutside__ = documentHandler;
document.addEventListener('click',documentHandler)
},
unbind:function(el,binding){
document.removeEventListener('click',el.__vueClickOutside__)
//如果不移除, 当组件或元素销毁时,它仍然存在于内存中
delete el.__vueClickOutside__;
}
})
实时时间转换指令
var Time = {
//获取当前时间戳
getUnix() {
var date = new Date();
return date.getTime();
},
//获取今天 0 点 0分 0秒的时间戳
getTodayUnix() {
var date = new Date();
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0)
return date.getTime();
},
//获取今年 1月 1 日 0点 0分 0秒的时间戳
getUYearUnix() {
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.getDate() < 10 ? '0' + date.getDate() : date.getDate();
return date.getFullYear() + '-' + month + '-' + day;
},
//转换时间
getFormatTime(timestamp) {
var now = this.getUnix()
var today = this.getTodayUnix()
var year = this.getUYearUnix();
var timer = (now - timestamp) / 1000;
var tip = '';
if (timer <= 0) {
tip = '刚刚'
} else if (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.ceil(timer / 86400) + '天前';
} else {
tip = this.getLastDate(timestamp);
}
return tip;
}
}
export default Time
Vue.directive('time',{
bind: function(el, binding){
el.innerHTML = Time.getFormatTime(binding.value)
el.__timeout__ = setInterval(function(){
el.innerHTML = Time.getFormatTime(binding.value)
}, 60000);
},
unbind: function(el){
clearInterval(el.__timeout__);
delete el.__timeout__;
}
})
<div v-time="timeNow"></div>
<div v-time="timeBefore"></div>
<div v-time="timeBefore2"></div>
data(){
return{
timeNow:(new Date()).getTime(),
timeBefore: 1606800579180,
timeBefore2: 1488930695721
}
}