1 | <template>
|
2 | <div id="vscroll-root-element" :style="{height:height+'px', opacity}">
|
3 | <div class="child" id="vscroll-e1">
|
4 | <slot></slot>
|
5 | </div>
|
6 | <div class="child" id="vscroll-e2">
|
7 | <slot></slot>
|
8 | </div>
|
9 | </div>
|
10 | </template>
|
11 | <script>
|
12 | import createEventHub from "ynw/createEventHub";
|
13 | const byId = name => document.getElementById(name);
|
14 | const hub = createEventHub();
|
15 | const IS_BOTTOM = "IS_BOTTOM";
|
16 | /**
|
17 | * ----------------------------------------
|
18 | * @param {Element} el - 运动元素
|
19 | * @param {Element} root - 元素容器
|
20 | * @param {Boolean} start - 开始运行
|
21 | * ----------------------------------------
|
22 | */
|
23 | const move = ({ el, speed = 3, root, start = false, elHeight, rootHeight }) => {
|
24 | const bottom = rootHeight - elHeight;
|
25 | const maxTop = 0 - elHeight;
|
26 | const setpos = v => {
|
27 | el.style.transform = `translateY(${v}px)`;
|
28 | curpos = v;
|
29 | };
|
30 | let curpos = rootHeight;
|
31 | let run = start;
|
32 | let hover = false;
|
33 | setpos(rootHeight);
|
34 |
|
35 | root.addEventListener("mouseenter", () => (hover = true));
|
36 | root.addEventListener("mouseleave", () => (hover = false));
|
37 |
|
38 | hub.on(IS_BOTTOM, notify => {
|
39 | if (notify !== el) {
|
40 | run = true;
|
41 | }
|
42 | });
|
43 |
|
44 | animate();
|
45 | function animate() {
|
46 | requestAnimationFrame(() => {
|
47 | if (run && hover === false) {
|
48 |
|
49 | if (curpos <= maxTop) {
|
50 | run = false;
|
51 | setpos(rootHeight);
|
52 | return animate();
|
53 | }
|
54 |
|
55 | if (curpos <= bottom) {
|
56 | hub.emit(IS_BOTTOM, el);
|
57 | }
|
58 | setpos(curpos - speed);
|
59 | }
|
60 |
|
61 | animate();
|
62 | });
|
63 | }
|
64 | };
|
65 | /**
|
66 | * ----------------------------------------
|
67 | * 垂直方向跑马灯
|
68 | * @param {Number} start - 开始滚动(依赖DOM元素的高度::数据渲染完成后再开始)
|
69 | * @param {Number} [speed=0.5] - 速度(px)
|
70 | * @param {Number} [height=150] - 样式 - 控制ROOT高度
|
71 | * ----------------------------------------
|
72 | */
|
73 | export default {
|
74 | props: {
|
75 | speed: {
|
76 | type: Number,
|
77 | default: 0.5
|
78 | },
|
79 | start: {
|
80 | type: Boolean,
|
81 | default: false
|
82 | },
|
83 | height: {
|
84 | type: Number,
|
85 | default: 150
|
86 | }
|
87 | },
|
88 | data() {
|
89 | return {
|
90 | opacity: 0
|
91 | };
|
92 | },
|
93 | watch: {
|
94 | start(v) {
|
95 | if (!v) return;
|
96 | setTimeout(() => {
|
97 | const root = byId("vscroll-root-element");
|
98 | const e1 = byId("vscroll-e1");
|
99 | const e2 = byId("vscroll-e2");
|
100 | const elHeight = e1.getBoundingClientRect().height;
|
101 | const rootHeight = root.getBoundingClientRect().height;
|
102 | const speed = this.speed;
|
103 |
|
104 |
|
105 | if (elHeight < rootHeight) {
|
106 | this.opacity = 1;
|
107 | return;
|
108 | }
|
109 | move({ el: e1, root, start: true, speed, elHeight, rootHeight });
|
110 | move({ el: e2, root, speed, elHeight, rootHeight });
|
111 | this.opacity = 1;
|
112 | }, 200);
|
113 | }
|
114 | }
|
115 | };
|
116 | </script>
|
117 | <style scoped lang='scss'>
|
118 | #vscroll-root-element {
|
119 | overflow: hidden;
|
120 | position: relative;
|
121 | }
|
122 | .child {
|
123 | width: 100%;
|
124 | position: absolute;
|
125 | left: 0;
|
126 | top: 0;
|
127 | }
|
128 | </style> |
\ | No newline at end of file |