| 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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
 | | <template> |  |   <transition name="el-fade-in"> |  |     <div |  |       v-if="visible" |  |       @click.stop="handleClick" |  |       :style="{ |  |         'right': styleRight, |  |         'bottom': styleBottom |  |       }" |  |       class="el-backtop"> |  |       <slot> |  |         <el-icon name="caret-top"></el-icon> |  |       </slot> |  |     </div> |  |   </transition> |  | </template> |  |   |  | <script> |  | import throttle from 'throttle-debounce/throttle'; |  |   |  | const cubic = value => Math.pow(value, 3); |  | const easeInOutCubic = value => value < 0.5 |  |   ? cubic(value * 2) / 2 |  |   : 1 - cubic((1 - value) * 2) / 2; |  |   |  | export default { |  |   name: 'ElBacktop', |  |   |  |   props: { |  |     visibilityHeight: { |  |       type: Number, |  |       default: 200 |  |     }, |  |     target: [String], |  |     right: { |  |       type: Number, |  |       default: 40 |  |     }, |  |     bottom: { |  |       type: Number, |  |       default: 40 |  |     } |  |   }, |  |   |  |   data() { |  |     return { |  |       el: null, |  |       container: null, |  |       visible: false |  |     }; |  |   }, |  |   |  |   computed: { |  |     styleBottom() { |  |       return `${this.bottom}px`; |  |     }, |  |     styleRight() { |  |       return `${this.right}px`; |  |     } |  |   }, |  |   |  |   mounted() { |  |     this.init(); |  |     this.throttledScrollHandler = throttle(300, this.onScroll); |  |     this.container.addEventListener('scroll', this.throttledScrollHandler); |  |   }, |  |   |  |   methods: { |  |     init() { |  |       this.container = document; |  |       this.el = document.documentElement; |  |       if (this.target) { |  |         this.el = document.querySelector(this.target); |  |         if (!this.el) { |  |           throw new Error(`target is not existed: ${this.target}`); |  |         } |  |         this.container = this.el; |  |       } |  |     }, |  |     onScroll() { |  |       const scrollTop = this.el.scrollTop; |  |       this.visible = scrollTop >= this.visibilityHeight; |  |     }, |  |     handleClick(e) { |  |       this.scrollToTop(); |  |       this.$emit('click', e); |  |     }, |  |     scrollToTop() { |  |       const el = this.el; |  |       const beginTime = Date.now(); |  |       const beginValue = el.scrollTop; |  |       const rAF = window.requestAnimationFrame || (func => setTimeout(func, 16)); |  |       const frameFunc = () => { |  |         const progress = (Date.now() - beginTime) / 500; |  |         if (progress < 1) { |  |           el.scrollTop = beginValue * (1 - easeInOutCubic(progress)); |  |           rAF(frameFunc); |  |         } else { |  |           el.scrollTop = 0; |  |         } |  |       }; |  |       rAF(frameFunc); |  |     } |  |   }, |  |   |  |   beforeDestroy() { |  |     this.container.removeEventListener('scroll', this.throttledScrollHandler); |  |   } |  | }; |  | </script> | 
 |