liuxiaolong
2019-05-06 acc45d2ece02563964d7b8a22ff0c40bd8358889
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import Vue from 'vue'
 
const TIMEOUT = 150
 
Vue.directive('hover-dropdown', {
  bind (el, binding, vnode) {
    const dropdown = vnode.componentInstance
    const toggle = el.querySelector('.dropdown-toggle')
    const menu = el.querySelector('.dropdown-menu')
    let timeout = null
    let hovered = false
 
    // Patch hideMenu method
    const _hideMenu = dropdown.hideMenu
    dropdown.hideMenu = function () {
      // Prevent dropdown close
      if (!hovered) _hideMenu.call(this)
      else dropdown.visible = true
    }
 
    function isStatic () {
      return window.getComputedStyle(menu, null).getPropertyValue('position') === 'static'
    }
 
    function clearCloseTimeout () {
      if (!timeout) return
      clearTimeout(timeout)
      timeout = null
    }
 
    function show () {
      clearCloseTimeout()
      if (isStatic() || dropdown.visible) return
      dropdown.$nextTick(() => dropdown.show())
    }
 
    function hide () {
      clearCloseTimeout()
      if (isStatic()) return
 
      timeout = setTimeout(() => {
        clearCloseTimeout()
        dropdown.hide()
      }, TIMEOUT)
    }
 
    const listeners = {
      toggleMouseenter: () => {
        if (!isStatic()) hovered = true
        show()
      },
      toggleMouseleave:  () => {
        hovered = false
        hide()
      },
      menuMouseenter: show,
      menuMouseleave:  hide
    }
 
    toggle.addEventListener('mouseenter', listeners.toggleMouseenter)
    toggle.addEventListener('mouseleave', listeners.toggleMouseleave)
    menu.addEventListener('mouseenter', listeners.menuMouseenter)
    menu.addEventListener('mouseleave', listeners.menuMouseleave)
 
    // Save data
    el.hoverDropdownDirectiveData = {
      toggle,
      menu,
      clearCloseTimeout,
      listeners
    }
  },
  unbind (el) {
    const i = el.hoverDropdownDirectiveData
 
    if (!i) return
 
    i.clearCloseTimeout()
 
    i.toggle.removeEventListener('mouseenter', i.listeners.toggleMouseenter)
    i.toggle.removeEventListener('mouseleave', i.listeners.toggleMouseleave)
    i.menu.removeEventListener('mouseenter', i.listeners.menuMouseenter)
    i.menu.removeEventListener('mouseleave', i.listeners.menuMouseleave)
 
    el.hoverDropdownDirectiveData = null
  }
})