自定义指令介绍与案例实践

自定义指令介绍

什么是自定义指令

Vue.directive( id, [definition] )
自定义指令介绍 directives - 对普通 DOM 元素进行底层操作
官方说法:除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

自定义指令的组成

注册或获取全局指令。

// 注册
Vue.directive('my-directive', {
  bind: function () {},
  inserted: function () {},
  update: function () {},
  componentUpdated: function () {},
  unbind: function () {}
})

// 注册 (指令函数)
Vue.directive('my-directive', function () {
  // 这里将会被 `bind` 和 `update` 调用
})

// getter,返回已注册的指令
var myDirective = Vue.directive('my-directive')

自定义指令钩子

* bind,inserted,update,componentUpdated,unbind

* 参数 el,binding,vnode,oldvnode

指令定义函数提供了几个钩子函数(可选):

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

inserted: 被绑定元素插入父节点时调用(父节点存在即可调用)。

update: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新

**componentUpdated:**指令所在组件的 VNode 及其子 VNode 全部更新后调用。

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

钩子函数的参数:(el, binding, vnode, oldVnode)

​ 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.a.b,modifiers的值为{‘a’:true,‘b’:true}

vnode:Vue编译的生成虚拟节点;

oldVnode:上一次的虚拟节点,仅在update和componentUpdated钩子函数中可用。

自定义指令的参数

v-demo:foo.a.b="message"
binding.name 可以获取指令的名字=demo
binding.value 可以获取指令的内容 =message指代的东西(message是变量)
binding.expression 获取内容的变量名
binding.arg 可以获取v-demo:foo ==> foo
binding.modifiers 可以获取指令的修饰符 v-demo:foo.a.b ==> {a:true,b:true}

 <div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
 Vue.directive('demo', {
     bind: function (el, binding, vnode) {
         var s = JSON.stringify
         el.innerHTML =
            'name: '       + s(binding.name) + '<br>' +
            'value: '      + s(binding.value) + '<br>' +
             'expression: ' + s(binding.expression) + '<br>' +
             'argument: '   + s(binding.arg) + '<br>' +
             'modifiers: '  + s(binding.modifiers) + '<br>' +
             'vnode keys: ' + Object.keys(vnode).join(',')
     }
})

结果
在这里插入图片描述

自定义指令简单案例

自定义指令v-swiper

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!--引入是wiper.css样式-->
    <link rel="stylesheet" href="./base/swiper.min.css">
    <style>
        .swipe{
            height:300px;
        }
    </style>
</head>
<body>
    

    <div id="box">
        <div class="swiper-container swipe">
            <div class="swiper-wrapper">
                <!--内部数据datalist发生变化了,然后生成3个swiper-slide真实dom,插入到swiper-wrapper里面去-->
                <div 
                    class="swiper-slide"
                    v-for="(data,index) in datalist"
                    v-swiper:swipe="{current:index,length:datalist.length,swipe:'swipe'}"  
                >
                    {{data}}
                </div>
            </div>
            <!--分页器-->
            <div class="swiper-pagination"></div>
        </div>
    </div>


    <!--引入swiper or vue插件-->
    <script src="./base/swiper.min.js"></script>
    <script src="./base/vue.js"></script>
    <script>
        //有很多的插件,其实只能实例化一次,
        //swiper实例化了多次之后,其实还是可以进行轮播效果,但是我们发现分页器效果已经失效了。


        //需求:封装一个指令v-swiper,实现内部帮助我们实例化轮播图的功能
        //问题:因为有三个swiper-slide的真实dom生成然后插入,所以new Swiper实例化了3次===>导致了分页器不管用了
        //解决? 等最后一个元素插入完成后再去实例化不就ok了吗?怎么样是代表最后一个元素插入了
        //那么获取到最后一个插入的元素的下标 === 传入的datalist的数组的长度-1
        //自定义指令 v-swiper
        Vue.directive("swiper",{
            inserted(el,binding,vnode){
                // 这个地方是通过vnode.context获取到vue实例,然后就可以通过这个实例.datalist.length获取到数组的长度了
                // console.log(vnode.context.datalist.length)
                //代表最后一个元素插入完毕了,再进进行一次实例化操作就可以了
                if(binding.value.current === binding.value.length-1){
                    //如果外部 {current,length,swipe:'swipe'}
                    //new Swiper("."+binding.value.swipe,{.....})
                    new Swiper("."+binding.arg,{ //默认swiper执行3次,因为插入了3个swiper-slide的真实dom
                        loop:true,
                        pagination:{
                            el:".swiper-pagination"
                        }
                    })
                }
            }
        })
        new Vue({
            el:"#box",
            data:{
                datalist:[]  //定义了初始化的数据
            },
            // updated(){
            //     new Swiper(".swipe",{
            //         loop:true,
            //         pagination:{
            //             el:".swiper-pagination"
            //         }
            //     })
            // },
            created(){
                setTimeout(() => {
                    this.datalist = ["111","222","333"] //更改数据
                    // this.$nextTick(()=>{
                        // new Swiper(".swipe",{
                        //     loop:true,
                        //     pagination:{
                        //         el:".swiper-pagination"
                        //     }
                        // })
                    // })
                }, 3000);
            }
        })
    </script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值