zoukankan      html  css  js  c++  java
  • 08.vue-charp-08 自定义指令

    基本用法

    自定义指令的选项是由几个钩子函数组成的,每个都是可选的。

    • bind:

      只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。

    • inserted:

      被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于document中)。

    • update:

      被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。

    • componentUpdated:

      被绑定元素所在模板完成一次更新周期时调用。

    • unbind:

      只调用一次,指令与元素解绑时调用。

    基本使用

    <body>
        <div id="app">
            <input type="text" v-focus>
        </div>
        <script src="../lib/vue.2.6.11.js"></script>
        <script>
            //全局注册指令
            Vue.directive('focus', {
                inserted: function (el, binding, vnode, oldVnode) {
                    console.log("focus->el:", el);
                    console.log("focus->binding:", binding);
                    console.log("focus->vnode:", vnode);
                    console.log("focus->oldVnode:", oldVnode);
    
                    // 聚焦元素
                    el.focus();
                }
            })
            var app = new Vue({
                el: '#app'
            })
        </script>
    </body>
    

    钩子函数参数

    每个钩子函数都有几个参数可用,比如上面我们用到了el。它们的含义如下:el 指令所绑定的元素,可以用来直接操作DOM。

    • binding 一个对象,包含以下属性:
      • 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 钩子中可用。
    <body>
        <div id="app">
            <div v-test:msg.a.b="message"></div>
        </div>
        <script src="../lib/vue.2.6.11.js"></script>
        <script>
            Vue.directive('test', {
                bind: function (el, binding, vnode) {
                    var keys = [];
                    for (var i in vnode) {
                        keys.push(i);
                    }
                    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(', ')
                }
            });
            var app = new Vue({
                el: '#app',
                data: {
                    message: 'some text'
                }
            })
        </script>
    </body>
    

    自定义指令-传入对象

    <body>
        <div id="app">
            <div v-test="{msg: 'hello', name: 'Aresn'}"></div>
        </div>
        <script src="../lib/vue.2.6.11.js"></script>
        <script>
            Vue.directive('test', {
                bind: function (el, binding, vnode) {
                    console.log(binding.value.msg);
                    console.log(binding.value.name);
    
                    el.innerHTML =
                        'binding.value.msg: ' + binding.value.msg + '<br>' +
                        'binding.value.name: ' + binding.value.name + '<br>';
    
                }
            });
            var app = new Vue({
                el: '#app'
    
            })
        </script>
    </body>
    

    开发一个可从外部关闭的下拉菜单

    点击用户头像和名称,会弹出一个下拉菜单,然后点击页面中其他空白区域(除了菜单本身外),菜单就关闭了。

    index.html

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <title>Vue 示例:从外部关闭的下拉菜单</title>
        <link rel="stylesheet" type="text/css" href="style.css">
    </head>
    
    <body>
        <div id="app" v-cloak>
            <div class="main" v-clickoutside="handleClose">
                <button @click="show = !show">点击显示下拉菜单</button>
                <div class="dropdown" v-show="show">
                    <p>下拉框的内容,点击外面区域可以关闭</p>
                </div>
            </div>
        </div>
    
        <script src="../../lib/vue.2.6.11.js"></script>
        <script src="clickoutside.js"></script>
        <script src="index.js"></script>
    </body>
    
    </html>
    

    index.js

    var app = new Vue({
        el: '#app',
        data: {
            show: false
        },
        methods: {
            handleClose: function () {
                this.show = false;
            }
        }
    });
    

    clickoutside.js

    Vue.directive("clickoutside", {
        bind: function (el, binding, vnode) {
            function documentHandler(e) {
                if (el.contains(e.target)) { //第一个是判断点击的区域是否是指令所在的元素内部,
                    return false;
                }
                if (binding.expression) {  //在该自定义指令中,表达式应该是一个函数
                    binding.value(e); //binding.value()就是用来执行当前上下文 methods中指定的函数的
                }
            }
    
            //与Vue 1.x不同的是,在自定义指令中,不能再用this.xxx的形式在上下文中声明一个变量,
            //所以用了el.__vueClickOutside__引用了documentHandler,
            //这样就可以在unbind钩子里移除对document的click事件监听。如果不移除,当组件或元素销毁时,它仍然存在于内存中
            el.__vueClickOutside__ = documentHandler;
            document.addEventListener('click', documentHandler);
        },
        unbind: function (el, binding) {
            document.removeEventListener('click', el.__vueClickOutside__);
            delete el.__vueClickOutside__;
        }
    });
    

    style.css

    [v-cloak] {
        display: none;
    }
    .main{
         125px;
    }
    button{
        display: block;
         100%;
        color: #fff;
        background-color: #39f;
        border: 0;
        padding: 6px;
        text-align: center;
        font-size: 12px;
        border-radius: 4px;
        cursor: pointer;
        outline: none;
        position: relative;
    }
    
    button:active{
        top: 1px;
        left: 1px;
    }
    .dropdown{
         100%;
        height: 150px;
        margin: 5px 0;
        font-size: 12px;
        background-color: #fff;
        border-radius: 4px;
        box-shadow: 0 1px 6px rgba(0,0,0,.2);
    }
    .dropdown p{
        display: inline-block;
        padding: 6px;
    }
    

    开发一个实时时间转换指令v-time

    本示例就来实现这样一个自定义指令v-time,将表达式传入的时间戳实时转换为相对时间,

    示例所用的时间戳都是毫秒级的,时间转换的逻辑:

    • 1分钟以前,显示“刚刚”。
    • 1分钟~1小时之间,显示“xx分钟前”。
    • 1小时~1天之间,显示“xx小时前”。
    • 1天~1个月(31天)之间,显示“xx天前”。
    • 大于1个月,显示“xx年xx月xx日”。

    index.html

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <title>Vue 示例:实时时间转换器</title>
        <link rel="stylesheet" type="text/css" href="style.css">
    </head>
    
    <body>
        <div id="app" v-cloak>
            <div v-time="timeNow"></div>
            <div v-time="timeBefore"></div>
        </div>
    
        <script src="../../lib/vue.2.6.11.js"></script>
        <script src="time.js"></script>
        <script src="index.js"></script>
    </body>
    
    </html>
    

    index.js

    var app = new Vue({
        el: '#app',
        data: {
            timeNow: (new Date()).getTime(),
            timeBefore: 1488930695721
        }
    });
    

    time.js

    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;
        }
    };
    
    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__;
        }
    });
    
  • 相关阅读:
    驾照更换说明
    批处理创建快捷方式
    AC中保存数据与查询数据
    logger日志模块
    如何将python脚本转化为exe
    numpy学习
    request是个什么东西
    django的test文件的使用方式
    高频正则表达式
    dir 的作用
  • 原文地址:https://www.cnblogs.com/easy5weikai/p/13282915.html
Copyright © 2011-2022 走看看