blob: bc2346607e026e792004ddc3eb6c2a2735ef0d7e [file] [log] [blame]
huibing.xie1f1606f2018-08-20 15:46:55 +08001const vueSticky = {}
2let listenAction
3vueSticky.install = Vue => {
4 Vue.directive('sticky', {
5 inserted(el, binding) {
6 const params = binding.value || {}
7 const stickyTop = params.stickyTop || 0
8 const zIndex = params.zIndex || 1000
9 const elStyle = el.style
10
11 elStyle.position = '-webkit-sticky'
12 elStyle.position = 'sticky'
13 // if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
14 // if (~elStyle.position.indexOf('sticky')) {
15 // elStyle.top = `${stickyTop}px`;
16 // elStyle.zIndex = zIndex;
17 // return
18 // }
19 const elHeight = el.getBoundingClientRect().height
20 const elWidth = el.getBoundingClientRect().width
21 elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`
22
23 const parentElm = el.parentNode || document.documentElement
24 const placeholder = document.createElement('div')
25 placeholder.style.display = 'none'
26 placeholder.style.width = `${elWidth}px`
27 placeholder.style.height = `${elHeight}px`
28 parentElm.insertBefore(placeholder, el)
29
30 let active = false
31
32 const getScroll = (target, top) => {
33 const prop = top ? 'pageYOffset' : 'pageXOffset'
34 const method = top ? 'scrollTop' : 'scrollLeft'
35 let ret = target[prop]
36 if (typeof ret !== 'number') {
37 ret = window.document.documentElement[method]
38 }
39 return ret
40 }
41
42 const sticky = () => {
43 if (active) {
44 return
45 }
46 if (!elStyle.height) {
47 elStyle.height = `${el.offsetHeight}px`
48 }
49
50 elStyle.position = 'fixed'
51 elStyle.width = `${elWidth}px`
52 placeholder.style.display = 'inline-block'
53 active = true
54 }
55
56 const reset = () => {
57 if (!active) {
58 return
59 }
60
61 elStyle.position = ''
62 placeholder.style.display = 'none'
63 active = false
64 }
65
66 const check = () => {
67 const scrollTop = getScroll(window, true)
68 const offsetTop = el.getBoundingClientRect().top
69 if (offsetTop < stickyTop) {
70 sticky()
71 } else {
72 if (scrollTop < elHeight + stickyTop) {
73 reset()
74 }
75 }
76 }
77 listenAction = () => {
78 check()
79 }
80
81 window.addEventListener('scroll', listenAction)
82 },
83
84 unbind() {
85 window.removeEventListener('scroll', listenAction)
86 }
87 })
88}
89
90export default vueSticky
91