Lei Zhang

时光已逝永不回,
往事只能回味。
... ...
春风又吹红了花蕊,
你已经也添了新岁。

▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 96%



gvt salon 02 指令

2018-09-14 » 没填完的坑 / Tutorial , Vuejs , 环境搭建

基础

需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。

Vuejs 内置指令如下:

  • v-if
  • v-else
  • v-else-if
  • v-show
  • v-html
  • v-text
  • v-on
  • v-for
  • v-bind
  • v-model
  • v-pre
  • v-cloak
  • v-once

常用指令, 如下:

  • v-if
  • v-else
  • v-else-if
  • v-show
  • v-for
  • v-model
  • v-bind
  • v-on

注册 directive

  • 全局注册
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})
  • 局部注册
Vue.component("component", {
    directives: {
        focus: {
            inserted: function (el) {
               el.focus()
            }
        }
    }
})

使用 directive

<input v-focus />

实战 click_out_side

在一些下拉框应用的场景中, 例如: 点击用户头像, 出现 ActionSheet.

点击 ActionSheet, ActionSheet 不消失, 点击页面其他位置时, ActionSheet 消失, 即为 click_out_side

实现原理

为父容器添加 v-click-out-side 指令, 当点击区域为该容器之外任意位置时, 执行指令相关事件.

当指令 bind 时, 增加监听函数, 并执行相关操作

当指令 unbind 时, 移除事件监听, 释放内存

每当指令进行事件监听时, 在 unbind 时务必要移除事件监听并释放内存

否则当前组件被频繁创建销毁时, 会造成内存溢出

// 将其属性置位 null, Javascript 垃圾回收机制 将会自动回收内存
el.__vueClickOutside__ = null
// or
// 使用 delete Object.key 也能达到该效果
delete el.__vueClickOutside__
  • HTML 结构
.test {
  padding: 50px;
  border: 1px solid black;
  margin: 50px;
  background-color: white;
  cursor: pointer;
}
<div id="app">

    <!-- 点击 div.test 容器之外位置, 执行 outside(), 使 clickOutside 自增 1-->
    <!-- 点击 div.test 容器之内位置, 执行 inside(), 使 clickInside 自增 1-->
    <div 
        class="test" 
        v-click-out-side="outside" 
        @click="inside">
        Test
    </div>
    <pre>
    {
        clickOutside: {{ clickOutside }},
        clickInside: {{ clickIntside }},
    }
    </pre>
</div>
new Vue({
  el: '#app',

  data: function () {
    return {
        clickOutside: 0,
        clickInside: 0
    }
  },

  methods: {
    outside: function(e) {
    	this.clickOutside += 1
        console.log('clicked outside!')
    },

    inside: function(e) {
        this.clickInside += 1
        console.log('clicked inside!')
    }
  },

  directives: {
    'click-out-side': {
        bind: function(el, binding) {
            // 1. 确保指令所接受的参数为一个 Function
            if (typeof binding.value !== 'function') {
            console.warn("[Vue-click-outside:]绑定的值必须为一个 Function")
            }
            // 2. 定义一个 handler Function
            const handler = e => {
            if (!el.contains(e.target) && el !== e.target) {
                binding.value(e)
            }
            }
            // 3. 将 handler 缓存在 DOM 元素之上
            el.__vueClickOutside__ = handler

            // 4. 监听 document 的 click 事件
            document.addEventListener('click', handler)
	    },
      
        unbind: function(el, binding) {
            // 5. 指令解除绑定时, 释放监听事件内存
            document.removeEventListener('click', el.__vueClickOutside__)
            el.__vueClickOutside__ = null
        }
    }
  }
})
展开选填信息