6.vue知识点:vue-directive自定义指令


Vue.directive
使用v-*来使用自定义的指令,*代表自定义指令的名称

一、介绍

  • Vue中有很多默认内置的指令,如v-model、v-show、v-if等,还可以 通过directive进行自定义指令,对DOM元素进行自定义的操作。
  • 在组件内部定义的可以在组件内部使用生效,在APP-mian.js中注册定义的所有组件均可用。

二、钩子函数

一个指令定义对象可以提供如下几个钩子函数(都是可选的)

  • bind:只调用一次,可以用于绑定元素的初始化
  • insert:被绑定元素插入父节点时调用,此时可以做一些对元素的操作
  • unbind:只调用一次,指令与元素解绑时调用
  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是可以通过比较更新前后的值来忽略不必要的模板更新。
  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

三、钩子参数

钩子函数中会被传入的参数

  • el:指定绑定的元素,可以直接用这个来对DOM进行操作
  • binding:一个对象,包含着指令里面的一些属性
    {
    name、value、oldValue、expression、arg等
    }
  • vnode:Vue编译生成的虚拟节点
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

四、动态参数

  • 说明
    实现自定义的组件位置修改(就是参数binding里面传入的arg,接收动态参数,可以根据组件实例来进行动态调节)
  • 传入动态参数
    directive1

五、实例

1.需求

  • 需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框
    directive2

  • 父组件区域长宽确定
    directive3

    • 如果子组件区域超过父组件会溢出,但是父组件style属性为’overflow: hidden;'发现还是会被框在父组件内部,受制于父组件
      directive4
      当父组件style属性为overflow: hidden;
      在这里插入图片描述

2.如何设置一个类似于传送门一样的指令

  • 设置自定义指令v-myportal

  • 思路
    directive6

    • 1.把使用指令的组件样式设置为 position:absolute,然后放到app的节点下
    • 2.利用f2在页面中的位置确定f3位置,接着把f3的 z-index 样式修改到顶层
  • 代码

    • vue组件

      <template>
          <div class="f1class" ref="f1">
              父组件所在div(长宽确定)
              <div class="f2class" ref="f2">
                  <div style="height:30px">父组件</div>
                  <button @click="showChildBind" style="height:30px;width:60px">
                      子组件
                  </button>
                  <div style="position:relative;">
                      <div class="f3class" v-mybind:[bindingargs]="message"  v-myportal  ref="f3" v-show="childBindshow" >
                          <div>
                              点击按钮出现的子组件区域
                          </div>
                          {{message}}
                      </div>
                  </div>
              </div>
              <div class="f4class">
                  其他父组件
              </div>
          </div>
      </template>
      
      <script>
      export default {
          data:function(){
              return{
                  message:'Hello Bind',
                  childBindshow:false,
                  bindingargs:{
                      top:100,
                      left:20
                  }
              }
          },
          methods:{
              showChildBind(){//挂载到app以后还需要自己写位置的自适应
                  this.childBindshow=!this.childBindshow
                  var app = document.querySelector('#app');
                  var root=this.$refs.f2
                  var f3comp=this.$refs.f3
                  f3comp.style.top=(root.getBoundingClientRect().top-app.getBoundingClientRect().top+68)+'px'
                  f3comp.style.left=(root.getBoundingClientRect().left+root.getBoundingClientRect().width/2-30)+'px'
              }
          },
          directives: {
              mybindlocal: {//可以在本地注册自定义的指令,用于对DOM元素进行自定义操作
                  bind: function (el, binding, vnode) {
                      var s = JSON.stringify;
                      let temstr = el.innerHTML;
                      el.innerHTML =temstr + '<br>' +
                          'name: '       + s(binding.name) + '<br>' +
                          'value: '      + s(binding.value) + '<br>' +
                          'bindarg-top: '+ s(binding.arg.top)+ '<br>'+
                          'bindarg-left: '+ s(binding.arg.left)+ '<br>' ;
                          
                      el.style['padding-top']='20px'
                      console.log(el)
                  }
              }
          },
      }
      </script>
      
      <style>
      .f1class{
          width:600px;
          height:400px;
          background:rgb(255,99,71);
          margin-top:30px;
          margin-left:30px;
          position:relative;
      }
      .f2class{
          width:400px;
          height:200px;
          background:rgb(240,230,140);
          margin-left:30px;
          margin-top:30px;
          position:relative;
          overflow: hidden;
      }
      .f3class{
          width:500px;
          height:250px;
          background:rgb(135,206,235);
          position:absolute;
          z-index: 99;
      }
      .f4class{
          width:200px;
          height:100px;
          background:rgb(144,238,144);
          margin-left:30px;
          position:relative;
      }
      </style>
      
    • main.js中设置全局的自定义组件

      Vue.directive('mybind', {//单纯的自定义指令
          bind: function (el, binding, vnode) {
              var s = JSON.stringify;
              let temstr = el.innerHTML;
              el.innerHTML =temstr + '<br>' +
                  'name: '       + s(binding.name) + '<br>' +
                  'value: '      + s(binding.value) + '<br>' +
                  'bindarg-top: '+ s(binding.arg.top)+ '<br>'+
                  'bindarg-left: '+ s(binding.arg.left)+ '<br>' ;
                  
              el.style['padding-top']='20px'
              console.log(el)
      
          }
      })
      
      Vue.directive('myportal', {//设置传送门(其实就是简单地挂载到app)
          inserted: function (el, binding, vnode) {//这是将DOM元素挂载到指定的组件上,注意使用inserted/使用bind刷新会出错
              var app = document.querySelector('#app');
              var value = binding.value;
              if(value){
                  var fathernode=document.querySelector(value)
                  fathernode.appendChild(el)
              }else{//默认情况下挂载到app下
                  app.appendChild(el) 
              }
          }
      })
      

3.效果

  • 点击子组件按钮,子组件附加区域完整的出现且位置正确
    directive7

参考

自定义指令

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值