不知不觉,又过了一周的时间了,下面是我Vue实战第二篇,开发一个实时时间转换指令 v-time
,能将时间戳转化为更形象的几秒钟前、几分钟前、几小时前等不同的格式,在一些社交类的产品都会有这种需求。以下是我改进的一个todoList,结合了实时时间转化指令。
先上效果图
只实现逻辑,没有添加CSS样式
目录结构
代码
不多解释,直接上代码
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>时间转换指令</title>
</head>
<body>
<div id="app" v-clock>
<form>
<label for="new-todo">Add a todo</label>
<input
v-model="newTodoText"
id="new-todo"
placeholder=""
>
<button @click.prevent="addNewTodo">Add</button>
</form>
<ul>
<li
is="todo-item"
v-for="(item, index) in todos"
:key="item.id"
:title="item.title"
:time="item.time"
@remove="todos.splice(index, 1)"
></li>
</ul>
</div>
<script src="https://unpkg.com/vue@2.6.10/dist/vue.min.js"></script>
<script src="./time.js"></script>
<script src="./index.js"></script>
</body>
</html>
time.js
var Time = {
getUnix: function () {
var date = new Date();
return date.getTime();
},
getTodayUnix: function () {
var date = new Date();
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date.getTime();
},
getYearUnix: function () {
var date = new Date();
date.setMonth(0);
date.setDate(1);
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.getMilliseconds(0);
return date.getTime();
},
getLastDate: function (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: function (time) {
var now = this.getUnix();
var today = this.getTodayUnix();
var year = this.getYearUnix();
var timer = (now - time)/1000;
var tip = '';
if (timer <=0 || Math.floor(timer/60) <=0) {
tip = '刚刚';
} else if (timer < 3600) {
tip = Math.floor(timer/60) + '分钟前';
} else if (timer >= 3600 && (time-today) >= 0) {
tip = Math.floor(timer/3600) + '小时前';
} else if (timer/86400 <= 31) {
tip = Math.ceil(timer/86300) + '天前';
} else {
tip = this.getLastDate(time);
}
return tip;
}
};
/*
* bind: 只调用一次,指令第一次绑定到元素时调用
* inserted: 被绑定元素插入父节点时调用
* update
* componentUpdated
* unbind
*/
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__;
}
})
index.js
Vue.component('todo-item', {
template: '\
<li>\
{{title}}\
<span style="color:#666;" v-time="time"></span>\
<button @click="$emit(\'remove\')">remove</button>\
</li>\
',
props: {
title: String,
time: String
}
})
var app = new Vue({
el: '#app',
data: {
newTodoText: '',
todos: [
{
id: 1,
title: 'This is a example',
time: '1563015337821'
}
],
nextTodoId: '2'
},
methods: {
addNewTodo () {
let date = new Date().getTime();
this.todos.unshift({
id: this.nextTodoId++,
title: this.newTodoText,
time: date
})
this.newTodoText = ''
}
}
})
总结
在编写自定义指令时,给DOM
绑定一次性事件等初始动作,建议在 bind
钩子内完成, 同时要在unbind
内解除相关绑定。在自定义指令里,可以任意操作 DOM
, 但这又违背 Vue.js 的初衷,所以需要大幅度的 DOM 变动,应该使用组件。