前言
最近有一个说法,如果你看见某个网站的某个功能,你就大概能猜出背后的业务逻辑是怎么样的,以及你能动手开发一个一毛一样的功能,那么你的前端技能算是进阶中高级水平了.比如咱们今天要聊的这个话题:如何用 vue 开发一个实时性的时间转换指令?
接下来正文从这开始~
如上图所示(我是截取的某技术社区首页的部分页面),大家看到用红色边框勾选中的时间文字了吧.很多网站发布动态的时候,都会有一个相对本机时间转换后的相对时间.那你知道这个功能实现的背后原理是什么吗?如果有兴趣的,请备好瓜子,茶水,继续往下读.
一般在服务器的存储时间格式是 Unix 时间戳,比如 2018-01-17 06:00:00 的时间戳是 1516140000.前端在拿到数据后,将它转换为可持续的时间格式再显示出来.为了显示出实时性,在一些社交类产品中,甚至会实时转换为几秒前,几分钟前,几小时前等不同的格式,因为这样比直接转换为年,月,日,时,分,秒,显得对用户更加友好,体验更人性化.
今天,我们就来实现这样一个 Vue 自定义指令 v-time,将表达式传入的时间戳实时转换为相对时间.为了便于演示效果,我们初始化时定义了两个时间.
首先来看 html 结构:
以及初始化一个 Vue 实例:
<div id="app" v-cloak>
<div v-time="timeNow"></div>
<div v-time="timeBefore"></div>
</div>
timeNow 是目前的时间,timeBefore 是一个写死的时间:1991-09-30.
var app = new Vue({
el: '#app',
data: {
timeNow: (new Date()).getTime(),
timeBefore: 686219755822
}
})
先来分析一下时间转换的逻辑:
1 分钟以前,显示 "刚刚".
1 分钟~ 1 小时之间,显示 "xx 分钟前".
1 小时~ 1 天之间,显示 "xx 小时前".
1 天~ 1 个月(31 天)之间,显示 "xx 天前".
大于 1 个月,显示 "xx 年 xx 月 xx 日".
这样罗列出来,逻辑就一目了然了.为了使判断更简单,我们这里统一使用时间戳进行大小判断.在写指令 v-time 之前,需要先写一系列与时间相关的函数 ,我们声明一个对象 Time,把它们都封装到里面.
当然,如果你对 JavaScript 的 Date 类型不太了解,可以先去 runoob.com 上面了解下.
var Time = {
//获取当前时间戳
getUnix: function() {
var date = new Date();
return date.getTime();
},
//获取今天0点0分0秒的时间戳
getTodayUnix: function() {
var date = new Date();
date.setHours(0);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date.getTime();
},
//获取今年1月1日0点0分0秒的时间戳
getYearUnix: function() {
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: 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(timestamp) {
var now = this.getUnix(); // 当前时间戳
var today = this.getTodayUnix(); // 今天0点的时间戳
var year = this.getYearUnix(); // 今年0点的时间戳
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;
}
}
接着说回来,Time.getFormatTime() 方法就是自定义指令 v-time 所需要的,参数为毫秒级时间戳,返回已经整理好的时间格式的字符串.
最后,来看我们如何用 Vue 自定义一个指令 v-time:
在 bind 钩子里,将指令 v-time 表达式的值 binding.value 作为参数传入 Time.getFormatTime() 方法中得到格式化时间,在通过 el.innerHTML 写入指令所在元素.定时器 el.__timeout__每分钟触发一次,更新时间,并且在 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__;
}
})
你可能会问,这个 binding.value 是什么?
当然,你可以通过 console.log(binding) 方法在控制台打印一下,就一目了然了.
在这里,我先补充下,自定义指令的选项是由几个钩子函数组成的,有 bind,insert,update,componentUpdated,unbind.而其中的 bind 和 unbind 只调用一次.每个钩子函数都有几个参数可用,比如我们上面用到的 el 和 binding.
el 指令所绑定的元素可以用来直接操作 DOM.而 binding 是一个对象,包含很多属性,如上图所示:
name:指令名
rawName:自定义指令
value:指令的绑定值
expression:绑定值的字符串形式
modifiers:一个包含修饰符的对象
总结
在编写自定义指令时,给 DOM 绑定一次性事件等初始动作,建议在 bind 钩子内完成,同时要在 unbind 内解除相关绑定.
后记
前端路漫漫,这是不真的事实.而我想说的是,无论前途多么遥远,我都希望你做一个志在四方的少年.
来源: https://www.cnblogs.com/running-runtu/p/8297075.html