| 
 
 | 
1
 | 
+import type { CSSProperties } from 'vue'
 | 
| 
 
 | 
2
 | 
+import {
 | 
| 
 
 | 
3
 | 
+  computed,
 | 
| 
 
 | 
4
 | 
+  defineComponent,
 | 
| 
 
 | 
5
 | 
+  getCurrentInstance,
 | 
| 
 
 | 
6
 | 
+  nextTick,
 | 
| 
 
 | 
7
 | 
+  onBeforeMount,
 | 
| 
 
 | 
8
 | 
+  onMounted,
 | 
| 
 
 | 
9
 | 
+  ref,
 | 
| 
 
 | 
10
 | 
+  watch,
 | 
| 
 
 | 
11
 | 
+} from 'vue'
 | 
| 
 
 | 
12
 | 
+import { useThrottleFn } from '@vueuse/core'
 | 
| 
 
 | 
13
 | 
+
 | 
| 
 
 | 
14
 | 
+interface PropsType {
 | 
| 
 
 | 
15
 | 
+  modelValue: boolean
 | 
| 
 
 | 
16
 | 
+  list: Array<unknown>
 | 
| 
 
 | 
17
 | 
+  step: number
 | 
| 
 
 | 
18
 | 
+  limitScrollNum: number
 | 
| 
 
 | 
19
 | 
+  hover: boolean
 | 
| 
 
 | 
20
 | 
+  direction: String
 | 
| 
 
 | 
21
 | 
+  singleHeight: number
 | 
| 
 
 | 
22
 | 
+  singleWidth: number
 | 
| 
 
 | 
23
 | 
+  singleWaitTime: number
 | 
| 
 
 | 
24
 | 
+  isRemUnit: boolean
 | 
| 
 
 | 
25
 | 
+  isWatch: boolean
 | 
| 
 
 | 
26
 | 
+  delay: number
 | 
| 
 
 | 
27
 | 
+  ease: any
 | 
| 
 
 | 
28
 | 
+  count: number
 | 
| 
 
 | 
29
 | 
+  copyNum: number
 | 
| 
 
 | 
30
 | 
+  wheel: boolean
 | 
| 
 
 | 
31
 | 
+  singleLine: boolean
 | 
| 
 
 | 
32
 | 
+}
 | 
| 
 
 | 
33
 | 
+
 | 
| 
 
 | 
34
 | 
+function useExpose(apis: Record<string, any>) {
 | 
| 
 
 | 
35
 | 
+  const instance = getCurrentInstance()
 | 
| 
 
 | 
36
 | 
+  if (instance)
 | 
| 
 
 | 
37
 | 
+    Object.assign(instance.proxy as Object, apis)
 | 
| 
 
 | 
38
 | 
+}
 | 
| 
 
 | 
39
 | 
+
 | 
| 
 
 | 
40
 | 
+const Props = {
 | 
| 
 
 | 
41
 | 
+  // 是否开启自动滚动
 | 
| 
 
 | 
42
 | 
+  modelValue: {
 | 
| 
 
 | 
43
 | 
+    type: Boolean,
 | 
| 
 
 | 
44
 | 
+    default: true,
 | 
| 
 
 | 
45
 | 
+  },
 | 
| 
 
 | 
46
 | 
+  // 原始数据列表
 | 
| 
 
 | 
47
 | 
+  list: {
 | 
| 
 
 | 
48
 | 
+    type: Array,
 | 
| 
 
 | 
49
 | 
+    required: true,
 | 
| 
 
 | 
50
 | 
+    default: [],
 | 
| 
 
 | 
51
 | 
+  },
 | 
| 
 
 | 
52
 | 
+  // 步进速度,step 需是单步大小的约数
 | 
| 
 
 | 
53
 | 
+  step: {
 | 
| 
 
 | 
54
 | 
+    type: Number,
 | 
| 
 
 | 
55
 | 
+    default: 1,
 | 
| 
 
 | 
56
 | 
+  },
 | 
| 
 
 | 
57
 | 
+  // 开启滚动的数据量
 | 
| 
 
 | 
58
 | 
+  limitScrollNum: {
 | 
| 
 
 | 
59
 | 
+    type: Number,
 | 
| 
 
 | 
60
 | 
+    default: 3,
 | 
| 
 
 | 
61
 | 
+  },
 | 
| 
 
 | 
62
 | 
+  // 是否开启鼠标悬停
 | 
| 
 
 | 
63
 | 
+  hover: {
 | 
| 
 
 | 
64
 | 
+    type: Boolean,
 | 
| 
 
 | 
65
 | 
+    default: false,
 | 
| 
 
 | 
66
 | 
+  },
 | 
| 
 
 | 
67
 | 
+  // 控制滚动方向
 | 
| 
 
 | 
68
 | 
+  direction: {
 | 
| 
 
 | 
69
 | 
+    type: String,
 | 
| 
 
 | 
70
 | 
+    default: 'up',
 | 
| 
 
 | 
71
 | 
+  },
 | 
| 
 
 | 
72
 | 
+  // 单步运动停止的高度
 | 
| 
 
 | 
73
 | 
+  singleHeight: {
 | 
| 
 
 | 
74
 | 
+    type: Number,
 | 
| 
 
 | 
75
 | 
+    default: 0,
 | 
| 
 
 | 
76
 | 
+  },
 | 
| 
 
 | 
77
 | 
+  // 单步运动停止的宽度
 | 
| 
 
 | 
78
 | 
+  singleWidth: {
 | 
| 
 
 | 
79
 | 
+    type: Number,
 | 
| 
 
 | 
80
 | 
+    default: 0,
 | 
| 
 
 | 
81
 | 
+  },
 | 
| 
 
 | 
82
 | 
+  // 单步停止等待时间 (默认值 1000ms)
 | 
| 
 
 | 
83
 | 
+  singleWaitTime: {
 | 
| 
 
 | 
84
 | 
+    type: Number,
 | 
| 
 
 | 
85
 | 
+    default: 1000,
 | 
| 
 
 | 
86
 | 
+  },
 | 
| 
 
 | 
87
 | 
+  // 是否开启 rem 度量
 | 
| 
 
 | 
88
 | 
+  isRemUnit: {
 | 
| 
 
 | 
89
 | 
+    type: Boolean,
 | 
| 
 
 | 
90
 | 
+    default: false,
 | 
| 
 
 | 
91
 | 
+  },
 | 
| 
 
 | 
92
 | 
+  // 开启数据更新监听
 | 
| 
 
 | 
93
 | 
+  isWatch: {
 | 
| 
 
 | 
94
 | 
+    type: Boolean,
 | 
| 
 
 | 
95
 | 
+    default: true,
 | 
| 
 
 | 
96
 | 
+  },
 | 
| 
 
 | 
97
 | 
+  // 动画时间
 | 
| 
 
 | 
98
 | 
+  delay: {
 | 
| 
 
 | 
99
 | 
+    type: Number,
 | 
| 
 
 | 
100
 | 
+    default: 0,
 | 
| 
 
 | 
101
 | 
+  },
 | 
| 
 
 | 
102
 | 
+  // 动画方式
 | 
| 
 
 | 
103
 | 
+  ease: {
 | 
| 
 
 | 
104
 | 
+    type: [String, Object],
 | 
| 
 
 | 
105
 | 
+    default: 'ease-in',
 | 
| 
 
 | 
106
 | 
+  },
 | 
| 
 
 | 
107
 | 
+  // 动画循环次数,-1 表示一直动画
 | 
| 
 
 | 
108
 | 
+  count: {
 | 
| 
 
 | 
109
 | 
+    type: Number,
 | 
| 
 
 | 
110
 | 
+    default: -1,
 | 
| 
 
 | 
111
 | 
+  },
 | 
| 
 
 | 
112
 | 
+  // 拷贝几份滚动列表
 | 
| 
 
 | 
113
 | 
+  copyNum: {
 | 
| 
 
 | 
114
 | 
+    type: Number,
 | 
| 
 
 | 
115
 | 
+    default: 1,
 | 
| 
 
 | 
116
 | 
+  },
 | 
| 
 
 | 
117
 | 
+  // 开启鼠标悬停时支持滚轮滚动
 | 
| 
 
 | 
118
 | 
+  wheel: {
 | 
| 
 
 | 
119
 | 
+    type: Boolean,
 | 
| 
 
 | 
120
 | 
+    default: false,
 | 
| 
 
 | 
121
 | 
+  },
 | 
| 
 
 | 
122
 | 
+  // 启用单行滚动
 | 
| 
 
 | 
123
 | 
+  singleLine: {
 | 
| 
 
 | 
124
 | 
+    type: Boolean,
 | 
| 
 
 | 
125
 | 
+    default: false,
 | 
| 
 
 | 
126
 | 
+  },
 | 
| 
 
 | 
127
 | 
+}
 | 
| 
 
 | 
128
 | 
+
 | 
| 
 
 | 
129
 | 
+globalThis.window.cancelAnimationFrame = (function () {
 | 
| 
 
 | 
130
 | 
+  return (
 | 
| 
 
 | 
131
 | 
+    globalThis.window.cancelAnimationFrame
 | 
| 
 
 | 
132
 | 
+    || function (id) {
 | 
| 
 
 | 
133
 | 
+      return globalThis.window.clearTimeout(id)
 | 
| 
 
 | 
134
 | 
+    }
 | 
| 
 
 | 
135
 | 
+  )
 | 
| 
 
 | 
136
 | 
+})()
 | 
| 
 
 | 
137
 | 
+globalThis.window.requestAnimationFrame = (function () {
 | 
| 
 
 | 
138
 | 
+  return (
 | 
| 
 
 | 
139
 | 
+    globalThis.window.requestAnimationFrame
 | 
| 
 
 | 
140
 | 
+    || function (callback) {
 | 
| 
 
 | 
141
 | 
+      return globalThis.window.setTimeout(callback, 1000 / 60)
 | 
| 
 
 | 
142
 | 
+    }
 | 
| 
 
 | 
143
 | 
+  )
 | 
| 
 
 | 
144
 | 
+})()
 | 
| 
 
 | 
145
 | 
+
 | 
| 
 
 | 
146
 | 
+function dataWarm(list: any[]) {
 | 
| 
 
 | 
147
 | 
+  if (list && typeof list !== 'boolean' && list.length > 100) {
 | 
| 
 
 | 
148
 | 
+    console.warn(
 | 
| 
 
 | 
149
 | 
+      `数据达到了${list.length}条有点多哦~,可能会造成部分老旧浏览器卡顿。`,
 | 
| 
 
 | 
150
 | 
+    )
 | 
| 
 
 | 
151
 | 
+  }
 | 
| 
 
 | 
152
 | 
+}
 | 
| 
 
 | 
153
 | 
+
 | 
| 
 
 | 
154
 | 
+const ScrollList = defineComponent({
 | 
| 
 
 | 
155
 | 
+  name: 'ScrollList',
 | 
| 
 
 | 
156
 | 
+  inheritAttrs: false,
 | 
| 
 
 | 
157
 | 
+  props: Props,
 | 
| 
 
 | 
158
 | 
+  emits: ['stop', 'count', 'move'],
 | 
| 
 
 | 
159
 | 
+  setup(_props, { slots, emit, attrs }) {
 | 
| 
 
 | 
160
 | 
+    const props = _props as unknown as PropsType
 | 
| 
 
 | 
161
 | 
+    const scrollRef = ref(null)
 | 
| 
 
 | 
162
 | 
+    const slotListRef = ref<HTMLDivElement | null>(null)
 | 
| 
 
 | 
163
 | 
+    const realBoxRef = ref<HTMLDivElement | null>(null)
 | 
| 
 
 | 
164
 | 
+    const reqFrame = ref<number | null>(null)
 | 
| 
 
 | 
165
 | 
+    const singleWaitTimeout = ref<NodeJS.Timeout | null>(null)
 | 
| 
 
 | 
166
 | 
+    const realBoxWidth = ref(0)
 | 
| 
 
 | 
167
 | 
+    const realBoxHeight = ref(0)
 | 
| 
 
 | 
168
 | 
+    const xPos = ref(0)
 | 
| 
 
 | 
169
 | 
+    const yPos = ref(0)
 | 
| 
 
 | 
170
 | 
+    const isHover = ref(false)
 | 
| 
 
 | 
171
 | 
+    const _count = ref(0)
 | 
| 
 
 | 
172
 | 
+
 | 
| 
 
 | 
173
 | 
+    const isScroll = computed(() => props.list ? (props.list.length >= props.limitScrollNum) : false)
 | 
| 
 
 | 
174
 | 
+
 | 
| 
 
 | 
175
 | 
+    const realBoxStyle = computed(() => {
 | 
| 
 
 | 
176
 | 
+      return {
 | 
| 
 
 | 
177
 | 
+        width: realBoxWidth.value ? `${realBoxWidth.value}px` : 'auto',
 | 
| 
 
 | 
178
 | 
+        transform: `translate(${xPos.value}px,${yPos.value}px)`,
 | 
| 
 
 | 
179
 | 
+
 | 
| 
 
 | 
180
 | 
+        transition: `all ${typeof props.ease === 'string'
 | 
| 
 
 | 
181
 | 
+            ? props.ease
 | 
| 
 
 | 
182
 | 
+            : `cubic-bezier(${
 | 
| 
 
 | 
183
 | 
+             props.ease.x1
 | 
| 
 
 | 
184
 | 
+             },${
 | 
| 
 
 | 
185
 | 
+             props.ease.y1
 | 
| 
 
 | 
186
 | 
+             },${
 | 
| 
 
 | 
187
 | 
+             props.ease.x2
 | 
| 
 
 | 
188
 | 
+             },${
 | 
| 
 
 | 
189
 | 
+             props.ease.y2
 | 
| 
 
 | 
190
 | 
+             })`
 | 
| 
 
 | 
191
 | 
+          } ${props.delay}ms`,
 | 
| 
 
 | 
192
 | 
+        overflow: 'hidden',
 | 
| 
 
 | 
193
 | 
+        display: props.singleLine ? 'flex' : 'block',
 | 
| 
 
 | 
194
 | 
+      }
 | 
| 
 
 | 
195
 | 
+    })
 | 
| 
 
 | 
196
 | 
+
 | 
| 
 
 | 
197
 | 
+    const isHorizontal = computed(
 | 
| 
 
 | 
198
 | 
+      () => props.direction === 'left' || props.direction === 'right',
 | 
| 
 
 | 
199
 | 
+    )
 | 
| 
 
 | 
200
 | 
+
 | 
| 
 
 | 
201
 | 
+    const floatStyle = computed<CSSProperties>(() => {
 | 
| 
 
 | 
202
 | 
+      return isHorizontal.value
 | 
| 
 
 | 
203
 | 
+        ? {
 | 
| 
 
 | 
204
 | 
+            float: 'left',
 | 
| 
 
 | 
205
 | 
+            overflow: 'hidden',
 | 
| 
 
 | 
206
 | 
+            display: props.singleLine ? 'flex' : 'block',
 | 
| 
 
 | 
207
 | 
+            flexShrink: props.singleLine ? 0 : 1,
 | 
| 
 
 | 
208
 | 
+          }
 | 
| 
 
 | 
209
 | 
+        : { overflow: 'hidden' }
 | 
| 
 
 | 
210
 | 
+    })
 | 
| 
 
 | 
211
 | 
+
 | 
| 
 
 | 
212
 | 
+    const baseFontSize = computed(() => {
 | 
| 
 
 | 
213
 | 
+      return props.isRemUnit
 | 
| 
 
 | 
214
 | 
+        ? parseInt(
 | 
| 
 
 | 
215
 | 
+          globalThis.window.getComputedStyle(
 | 
| 
 
 | 
216
 | 
+            globalThis.document.documentElement,
 | 
| 
 
 | 
217
 | 
+            null,
 | 
| 
 
 | 
218
 | 
+          ).fontSize,
 | 
| 
 
 | 
219
 | 
+        )
 | 
| 
 
 | 
220
 | 
+        : 1
 | 
| 
 
 | 
221
 | 
+    })
 | 
| 
 
 | 
222
 | 
+
 | 
| 
 
 | 
223
 | 
+    const realSingleStopWidth = computed(
 | 
| 
 
 | 
224
 | 
+      () => props.singleWidth * baseFontSize.value,
 | 
| 
 
 | 
225
 | 
+    )
 | 
| 
 
 | 
226
 | 
+
 | 
| 
 
 | 
227
 | 
+    const realSingleStopHeight = computed(
 | 
| 
 
 | 
228
 | 
+      () => props.singleHeight * baseFontSize.value,
 | 
| 
 
 | 
229
 | 
+    )
 | 
| 
 
 | 
230
 | 
+
 | 
| 
 
 | 
231
 | 
+    const step = computed(() => {
 | 
| 
 
 | 
232
 | 
+      let singleStep: number
 | 
| 
 
 | 
233
 | 
+      const _step = props.step
 | 
| 
 
 | 
234
 | 
+      if (isHorizontal.value)
 | 
| 
 
 | 
235
 | 
+        singleStep = realSingleStopWidth.value
 | 
| 
 
 | 
236
 | 
+
 | 
| 
 
 | 
237
 | 
+      else
 | 
| 
 
 | 
238
 | 
+        singleStep = realSingleStopHeight.value
 | 
| 
 
 | 
239
 | 
+
 | 
| 
 
 | 
240
 | 
+      if (singleStep > 0 && singleStep % _step > 0) {
 | 
| 
 
 | 
241
 | 
+        console.error(
 | 
| 
 
 | 
242
 | 
+          '如果设置了单步滚动, step 需是单步大小的约数,否则无法保证单步滚动结束的位置是否准确。~~~~~',
 | 
| 
 
 | 
243
 | 
+        )
 | 
| 
 
 | 
244
 | 
+      }
 | 
| 
 
 | 
245
 | 
+      return _step
 | 
| 
 
 | 
246
 | 
+    })
 | 
| 
 
 | 
247
 | 
+
 | 
| 
 
 | 
248
 | 
+    const cancel = () => {
 | 
| 
 
 | 
249
 | 
+      cancelAnimationFrame(reqFrame.value as number)
 | 
| 
 
 | 
250
 | 
+      reqFrame.value = null
 | 
| 
 
 | 
251
 | 
+    }
 | 
| 
 
 | 
252
 | 
+
 | 
| 
 
 | 
253
 | 
+    const animation = (
 | 
| 
 
 | 
254
 | 
+      _direction: 'up' | 'down' | 'left' | 'right',
 | 
| 
 
 | 
255
 | 
+      _step: number,
 | 
| 
 
 | 
256
 | 
+      isWheel?: boolean,
 | 
| 
 
 | 
257
 | 
+    ) => {
 | 
| 
 
 | 
258
 | 
+      reqFrame.value = requestAnimationFrame(() => {
 | 
| 
 
 | 
259
 | 
+        const h = realBoxHeight.value / 2
 | 
| 
 
 | 
260
 | 
+        const w = realBoxWidth.value / 2
 | 
| 
 
 | 
261
 | 
+        if (_direction === 'up') {
 | 
| 
 
 | 
262
 | 
+          if (Math.abs(yPos.value) >= h) {
 | 
| 
 
 | 
263
 | 
+            yPos.value = 0
 | 
| 
 
 | 
264
 | 
+            _count.value += 1
 | 
| 
 
 | 
265
 | 
+            emit('count', _count.value)
 | 
| 
 
 | 
266
 | 
+          }
 | 
| 
 
 | 
267
 | 
+          yPos.value -= _step
 | 
| 
 
 | 
268
 | 
+        }
 | 
| 
 
 | 
269
 | 
+        else if (_direction === 'down') {
 | 
| 
 
 | 
270
 | 
+          if (yPos.value >= 0) {
 | 
| 
 
 | 
271
 | 
+            yPos.value = h * -1
 | 
| 
 
 | 
272
 | 
+            _count.value += 1
 | 
| 
 
 | 
273
 | 
+            emit('count', _count.value)
 | 
| 
 
 | 
274
 | 
+          }
 | 
| 
 
 | 
275
 | 
+          yPos.value += _step
 | 
| 
 
 | 
276
 | 
+        }
 | 
| 
 
 | 
277
 | 
+        else if (_direction === 'left') {
 | 
| 
 
 | 
278
 | 
+          if (Math.abs(xPos.value) >= w) {
 | 
| 
 
 | 
279
 | 
+            xPos.value = 0
 | 
| 
 
 | 
280
 | 
+            _count.value += 1
 | 
| 
 
 | 
281
 | 
+            emit('count', _count.value)
 | 
| 
 
 | 
282
 | 
+          }
 | 
| 
 
 | 
283
 | 
+          xPos.value -= _step
 | 
| 
 
 | 
284
 | 
+        }
 | 
| 
 
 | 
285
 | 
+        else if (_direction === 'right') {
 | 
| 
 
 | 
286
 | 
+          if (xPos.value >= 0) {
 | 
| 
 
 | 
287
 | 
+            xPos.value = w * -1
 | 
| 
 
 | 
288
 | 
+            _count.value += 1
 | 
| 
 
 | 
289
 | 
+            emit('count', _count.value)
 | 
| 
 
 | 
290
 | 
+          }
 | 
| 
 
 | 
291
 | 
+          xPos.value += _step
 | 
| 
 
 | 
292
 | 
+        }
 | 
| 
 
 | 
293
 | 
+        if (isWheel)
 | 
| 
 
 | 
294
 | 
+          return
 | 
| 
 
 | 
295
 | 
+
 | 
| 
 
 | 
296
 | 
+        const { singleWaitTime } = props
 | 
| 
 
 | 
297
 | 
+        if (singleWaitTimeout.value)
 | 
| 
 
 | 
298
 | 
+          clearTimeout(singleWaitTimeout.value)
 | 
| 
 
 | 
299
 | 
+
 | 
| 
 
 | 
300
 | 
+        if (realSingleStopHeight.value) {
 | 
| 
 
 | 
301
 | 
+          if (Math.abs(yPos.value) % realSingleStopHeight.value < _step) {
 | 
| 
 
 | 
302
 | 
+            singleWaitTimeout.value = setTimeout(() => {
 | 
| 
 
 | 
303
 | 
+              move()
 | 
| 
 
 | 
304
 | 
+            }, singleWaitTime)
 | 
| 
 
 | 
305
 | 
+          }
 | 
| 
 
 | 
306
 | 
+          else {
 | 
| 
 
 | 
307
 | 
+            move()
 | 
| 
 
 | 
308
 | 
+          }
 | 
| 
 
 | 
309
 | 
+        }
 | 
| 
 
 | 
310
 | 
+        else if (realSingleStopWidth.value) {
 | 
| 
 
 | 
311
 | 
+          if (Math.abs(xPos.value) % realSingleStopWidth.value < _step) {
 | 
| 
 
 | 
312
 | 
+            singleWaitTimeout.value = setTimeout(() => {
 | 
| 
 
 | 
313
 | 
+              move()
 | 
| 
 
 | 
314
 | 
+            }, singleWaitTime)
 | 
| 
 
 | 
315
 | 
+          }
 | 
| 
 
 | 
316
 | 
+          else {
 | 
| 
 
 | 
317
 | 
+            move()
 | 
| 
 
 | 
318
 | 
+          }
 | 
| 
 
 | 
319
 | 
+        }
 | 
| 
 
 | 
320
 | 
+        else {
 | 
| 
 
 | 
321
 | 
+          move()
 | 
| 
 
 | 
322
 | 
+        }
 | 
| 
 
 | 
323
 | 
+      })
 | 
| 
 
 | 
324
 | 
+    }
 | 
| 
 
 | 
325
 | 
+
 | 
| 
 
 | 
326
 | 
+    function move() {
 | 
| 
 
 | 
327
 | 
+      cancel()
 | 
| 
 
 | 
328
 | 
+      if (isHover.value || !isScroll.value || _count.value === props.count) {
 | 
| 
 
 | 
329
 | 
+        emit('stop', _count.value)
 | 
| 
 
 | 
330
 | 
+        _count.value = 0
 | 
| 
 
 | 
331
 | 
+        return
 | 
| 
 
 | 
332
 | 
+      }
 | 
| 
 
 | 
333
 | 
+      animation(
 | 
| 
 
 | 
334
 | 
+        props.direction as 'up' | 'down' | 'left' | 'right',
 | 
| 
 
 | 
335
 | 
+        step.value,
 | 
| 
 
 | 
336
 | 
+        false,
 | 
| 
 
 | 
337
 | 
+      )
 | 
| 
 
 | 
338
 | 
+    }
 | 
| 
 
 | 
339
 | 
+
 | 
| 
 
 | 
340
 | 
+    const initMove = () => {
 | 
| 
 
 | 
341
 | 
+      dataWarm(props.list)
 | 
| 
 
 | 
342
 | 
+      if (isHorizontal.value) {
 | 
| 
 
 | 
343
 | 
+        let slotListWidth = (slotListRef.value as HTMLDivElement).offsetWidth
 | 
| 
 
 | 
344
 | 
+        slotListWidth = slotListWidth * 2 + 1
 | 
| 
 
 | 
345
 | 
+        realBoxWidth.value = slotListWidth
 | 
| 
 
 | 
346
 | 
+      }
 | 
| 
 
 | 
347
 | 
+
 | 
| 
 
 | 
348
 | 
+      if (isScroll.value) {
 | 
| 
 
 | 
349
 | 
+        realBoxHeight.value = (realBoxRef.value as HTMLDivElement).offsetHeight
 | 
| 
 
 | 
350
 | 
+        if (props.modelValue)
 | 
| 
 
 | 
351
 | 
+          move()
 | 
| 
 
 | 
352
 | 
+      }
 | 
| 
 
 | 
353
 | 
+      else {
 | 
| 
 
 | 
354
 | 
+        cancel()
 | 
| 
 
 | 
355
 | 
+        yPos.value = xPos.value = 0
 | 
| 
 
 | 
356
 | 
+      }
 | 
| 
 
 | 
357
 | 
+    }
 | 
| 
 
 | 
358
 | 
+
 | 
| 
 
 | 
359
 | 
+    const startMove = () => {
 | 
| 
 
 | 
360
 | 
+      isHover.value = false
 | 
| 
 
 | 
361
 | 
+      move()
 | 
| 
 
 | 
362
 | 
+    }
 | 
| 
 
 | 
363
 | 
+
 | 
| 
 
 | 
364
 | 
+    const stopMove = () => {
 | 
| 
 
 | 
365
 | 
+      isHover.value = true
 | 
| 
 
 | 
366
 | 
+      if (singleWaitTimeout.value)
 | 
| 
 
 | 
367
 | 
+        clearTimeout(singleWaitTimeout.value)
 | 
| 
 
 | 
368
 | 
+
 | 
| 
 
 | 
369
 | 
+      cancel()
 | 
| 
 
 | 
370
 | 
+    }
 | 
| 
 
 | 
371
 | 
+
 | 
| 
 
 | 
372
 | 
+    const hoverStop = computed(
 | 
| 
 
 | 
373
 | 
+      () => props.hover && props.modelValue && isScroll.value,
 | 
| 
 
 | 
374
 | 
+    )
 | 
| 
 
 | 
375
 | 
+
 | 
| 
 
 | 
376
 | 
+    const throttleFunc = useThrottleFn((e: WheelEvent) => {
 | 
| 
 
 | 
377
 | 
+      cancel()
 | 
| 
 
 | 
378
 | 
+      const singleHeight = realSingleStopHeight.value
 | 
| 
 
 | 
379
 | 
+        ? realSingleStopHeight.value
 | 
| 
 
 | 
380
 | 
+        : 15
 | 
| 
 
 | 
381
 | 
+      if (e.deltaY < 0)
 | 
| 
 
 | 
382
 | 
+        animation('down', singleHeight, true)
 | 
| 
 
 | 
383
 | 
+
 | 
| 
 
 | 
384
 | 
+      if (e.deltaY > 0)
 | 
| 
 
 | 
385
 | 
+        animation('up', singleHeight, true)
 | 
| 
 
 | 
386
 | 
+    }, 30)
 | 
| 
 
 | 
387
 | 
+
 | 
| 
 
 | 
388
 | 
+    const onWheel = (e: WheelEvent) => {
 | 
| 
 
 | 
389
 | 
+      throttleFunc(e)
 | 
| 
 
 | 
390
 | 
+    }
 | 
| 
 
 | 
391
 | 
+
 | 
| 
 
 | 
392
 | 
+    const reset = () => {
 | 
| 
 
 | 
393
 | 
+      cancel()
 | 
| 
 
 | 
394
 | 
+      isHover.value = false
 | 
| 
 
 | 
395
 | 
+      initMove()
 | 
| 
 
 | 
396
 | 
+    }
 | 
| 
 
 | 
397
 | 
+
 | 
| 
 
 | 
398
 | 
+    const Reset = () => {
 | 
| 
 
 | 
399
 | 
+      reset()
 | 
| 
 
 | 
400
 | 
+    }
 | 
| 
 
 | 
401
 | 
+
 | 
| 
 
 | 
402
 | 
+    useExpose({ Reset })
 | 
| 
 
 | 
403
 | 
+
 | 
| 
 
 | 
404
 | 
+    watch(
 | 
| 
 
 | 
405
 | 
+      () => props.list,
 | 
| 
 
 | 
406
 | 
+      () => {
 | 
| 
 
 | 
407
 | 
+        if (props.isWatch) {
 | 
| 
 
 | 
408
 | 
+          nextTick(() => {
 | 
| 
 
 | 
409
 | 
+            reset()
 | 
| 
 
 | 
410
 | 
+          })
 | 
| 
 
 | 
411
 | 
+        }
 | 
| 
 
 | 
412
 | 
+      },
 | 
| 
 
 | 
413
 | 
+      {
 | 
| 
 
 | 
414
 | 
+        deep: true,
 | 
| 
 
 | 
415
 | 
+      },
 | 
| 
 
 | 
416
 | 
+    )
 | 
| 
 
 | 
417
 | 
+
 | 
| 
 
 | 
418
 | 
+    watch(
 | 
| 
 
 | 
419
 | 
+      () => props.modelValue,
 | 
| 
 
 | 
420
 | 
+      (newValue) => {
 | 
| 
 
 | 
421
 | 
+        if (newValue)
 | 
| 
 
 | 
422
 | 
+          startMove()
 | 
| 
 
 | 
423
 | 
+
 | 
| 
 
 | 
424
 | 
+        else
 | 
| 
 
 | 
425
 | 
+          stopMove()
 | 
| 
 
 | 
426
 | 
+      },
 | 
| 
 
 | 
427
 | 
+    )
 | 
| 
 
 | 
428
 | 
+
 | 
| 
 
 | 
429
 | 
+    watch(
 | 
| 
 
 | 
430
 | 
+      () => props.count,
 | 
| 
 
 | 
431
 | 
+      (newValue) => {
 | 
| 
 
 | 
432
 | 
+        if (newValue !== 0)
 | 
| 
 
 | 
433
 | 
+          startMove()
 | 
| 
 
 | 
434
 | 
+      },
 | 
| 
 
 | 
435
 | 
+    )
 | 
| 
 
 | 
436
 | 
+
 | 
| 
 
 | 
437
 | 
+    onBeforeMount(() => {
 | 
| 
 
 | 
438
 | 
+      cancel()
 | 
| 
 
 | 
439
 | 
+      clearTimeout(singleWaitTimeout.value as unknown as number)
 | 
| 
 
 | 
440
 | 
+    })
 | 
| 
 
 | 
441
 | 
+
 | 
| 
 
 | 
442
 | 
+    onMounted(() => {
 | 
| 
 
 | 
443
 | 
+      if (isScroll.value)
 | 
| 
 
 | 
444
 | 
+        initMove()
 | 
| 
 
 | 
445
 | 
+    })
 | 
| 
 
 | 
446
 | 
+
 | 
| 
 
 | 
447
 | 
+    const { default: $default, html } = slots
 | 
| 
 
 | 
448
 | 
+    const copyNum = new Array(props.copyNum).fill(null)
 | 
| 
 
 | 
449
 | 
+
 | 
| 
 
 | 
450
 | 
+    const getHtml = () => {
 | 
| 
 
 | 
451
 | 
+      return (
 | 
| 
 
 | 
452
 | 
+        <>
 | 
| 
 
 | 
453
 | 
+          <div ref={slotListRef} style={floatStyle.value}>
 | 
| 
 
 | 
454
 | 
+            {$default && $default()}
 | 
| 
 
 | 
455
 | 
+          </div>
 | 
| 
 
 | 
456
 | 
+          {isScroll.value
 | 
| 
 
 | 
457
 | 
+            ? copyNum.map(() => {
 | 
| 
 
 | 
458
 | 
+              if (html && typeof html === 'function')
 | 
| 
 
 | 
459
 | 
+                return <div style={floatStyle.value}>{html()}</div>
 | 
| 
 
 | 
460
 | 
+
 | 
| 
 
 | 
461
 | 
+              else
 | 
| 
 
 | 
462
 | 
+                return <div style={floatStyle.value}>{$default && $default()}</div>
 | 
| 
 
 | 
463
 | 
+            })
 | 
| 
 
 | 
464
 | 
+            : null}
 | 
| 
 
 | 
465
 | 
+        </>
 | 
| 
 
 | 
466
 | 
+      )
 | 
| 
 
 | 
467
 | 
+    }
 | 
| 
 
 | 
468
 | 
+
 | 
| 
 
 | 
469
 | 
+    return () => (
 | 
| 
 
 | 
470
 | 
+      <div ref={scrollRef} class={attrs.class}>
 | 
| 
 
 | 
471
 | 
+        {props.wheel && props.hover
 | 
| 
 
 | 
472
 | 
+          ? (
 | 
| 
 
 | 
473
 | 
+          <div
 | 
| 
 
 | 
474
 | 
+            ref={realBoxRef}
 | 
| 
 
 | 
475
 | 
+            style={realBoxStyle.value}
 | 
| 
 
 | 
476
 | 
+            onMouseenter={() => {
 | 
| 
 
 | 
477
 | 
+              if (hoverStop.value)
 | 
| 
 
 | 
478
 | 
+                stopMove()
 | 
| 
 
 | 
479
 | 
+            }}
 | 
| 
 
 | 
480
 | 
+            onMouseleave={() => {
 | 
| 
 
 | 
481
 | 
+              if (hoverStop.value)
 | 
| 
 
 | 
482
 | 
+                startMove()
 | 
| 
 
 | 
483
 | 
+            }}
 | 
| 
 
 | 
484
 | 
+            onWheel={(e) => {
 | 
| 
 
 | 
485
 | 
+              if (hoverStop.value)
 | 
| 
 
 | 
486
 | 
+                onWheel(e)
 | 
| 
 
 | 
487
 | 
+            }}
 | 
| 
 
 | 
488
 | 
+          >
 | 
| 
 
 | 
489
 | 
+            {getHtml()}
 | 
| 
 
 | 
490
 | 
+          </div>
 | 
| 
 
 | 
491
 | 
+            )
 | 
| 
 
 | 
492
 | 
+          : (
 | 
| 
 
 | 
493
 | 
+          <div
 | 
| 
 
 | 
494
 | 
+            ref={realBoxRef}
 | 
| 
 
 | 
495
 | 
+            style={realBoxStyle.value}
 | 
| 
 
 | 
496
 | 
+            onMouseenter={() => {
 | 
| 
 
 | 
497
 | 
+              if (hoverStop.value)
 | 
| 
 
 | 
498
 | 
+                stopMove()
 | 
| 
 
 | 
499
 | 
+            }}
 | 
| 
 
 | 
500
 | 
+            onMouseleave={() => {
 | 
| 
 
 | 
501
 | 
+              if (hoverStop.value)
 | 
| 
 
 | 
502
 | 
+                startMove()
 | 
| 
 
 | 
503
 | 
+            }}
 | 
| 
 
 | 
504
 | 
+          >
 | 
| 
 
 | 
505
 | 
+            {getHtml()}
 | 
| 
 
 | 
506
 | 
+          </div>
 | 
| 
 
 | 
507
 | 
+            )}
 | 
| 
 
 | 
508
 | 
+      </div>
 | 
| 
 
 | 
509
 | 
+    )
 | 
| 
 
 | 
510
 | 
+  },
 | 
| 
 
 | 
511
 | 
+})
 | 
| 
 
 | 
512
 | 
+
 | 
| 
 
 | 
513
 | 
+export default ScrollList
 | 
| 
 
 | 
514
 | 
+
 | 
| 
 
 | 
515
 | 
+export { ScrollList } | 
...
 | 
...
 | 
 |