Vue实战--自定义时间转化指令

970 阅读2分钟

  不知不觉,又过了一周的时间了,下面是我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 变动,应该使用组件。