关注前端 | 前端博客
当前位置: JavaScript > 【造轮子】左右伸缩兼左右滑动的区间滑块

【造轮子】左右伸缩兼左右滑动的区间滑块

2021-08-08 分类:JavaScript 作者:管理员 阅读(119)

基于JavaScript编写的一个原生区间滑块

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>slider-range</title>
    </head>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        .timelineScroll {
            width: 468px;
            height: 90px;
            overflow-x: scroll;
            overscroll-behavior: contain;
            margin: 50px auto;
        }
        .timelineScroll::-webkit-scrollbar {
            -webkit-appearance: none;
        }
        .timelineScroll::-webkit-scrollbar:vertical {
            width: 6px;
        }
        .timelineScroll::-webkit-scrollbar:horizontal {
            height: 6px;
        }
        .timelineScroll::-webkit-scrollbar-thumb {
            border-radius: 6px;
            border: 0 solid #dfdfdf;
           background-color: rgba(0, 0, 0, 0.2);
        }
        .timelineScroll::-webkit-scrollbar-thumb:hover {
            background-color: rgba(0, 0, 0, 0.3);
        }
        .timelineScroll::-webkit-scrollbar-track {
            background-color: #dfdfdf;
           border-radius: 2px;
            box-shadow: 0 0 1px #fff;
       }
        .timelineScrollinner {
            min-width: 444px;
            box-sizing: content-box;
            height: 100%;
            padding: 0 12px;
            overflow: hidden;
        }
        .rule-ruleContainer {
            position: relative;
            white-space: nowrap;
            height: 28px;
            cursor: default;
            border-bottom: 1px solid rgba(0, 0, 0, 0.1);
            margin-right: -20px;
        }
        .timelineBack::before,
        .timelineBack::after {
            content: '';
            position: absolute;
            top: 0;
            height: 100%;
            width: 12px;
            background: #d1d1d1;
       }
        .timelineBack::before {
            left: -12px;
            border-radius: 2px 0 0 2px;
        }
        .timelineBack::after {
            right: -12px;
            border-radius: 0 2px 2px 0;
        }
        .timelineBack {
            box-sizing: content-box;
            position: relative;
            background: #d1d1d1;
           height: 30px;
            line-height: 30px;
            margin-top: 12px;
            /* margin-bottom: 25px; */
        }
        .timeline {
            position: relative;
            height: 100%;
            background: #d1d1d1;
           user-select: none;
            z-index: 1;
        }
        .highlights {
            height: 100%;
        }
        .highlightsCon {
            position: relative;
            overflow: hidden;
            width: 100%;
            height: 100%;
        }
        /* selecton */
        .selection {
            position: absolute;
            top: 0;
            height: 100%;
            background: rgba(66, 133, 244, 0.25);
            text-align: center;
            color: #fff;
           font-size: 12px;
            border-radius: 2px;
            z-index: 1;
            cursor: pointer;
        }
        .selection:before {
            content: '';
            position: absolute;
            left: -1px;
            top: 0;
            right: -1px;
            bottom: 0;
            border: 1px solid #4285f4;
       }
        .selectionText {
            white-space: nowrap;
            overflow: hidden;
        }
        .dragLeft {
            position: absolute;
            top: 0;
            height: 100%;
            width: 12px;
            background: #4285f4;
           border: 0;
            padding: 0;
            cursor: ew-resize;
            left: -12px;
            border-radius: 2px 0 0 2px;
        }
        .dragLeft::before,
        .dragLeft::after,
        .dragRight::before,
        .dragRight::after {
            content: '';
            position: absolute;
            width: 1px;
            height: 8px;
            background: #fff;
           margin: 1px;
            top: 10px;
        }
        .dragLeft::before,
        .dragRight::before {
            left: 3px;
        }
        .dragLeft::after,
        .dragRight::before {
            right: 3px;
        }
        .dragLeft > span,
        .dragRight > span {
            position: absolute;
            bottom: 33px;
            transform: translate(-50%);
            left: 50%;
            visibility: visible;
        }
        /* dragRight */
        .dragRight {
            position: absolute;
            top: 0;
            height: 100%;
            width: 12px;
            background: #4285f4;
           border: 0;
            padding: 0;
            cursor: ew-resize;
            outline: none;
            right: -12px;
            border-radius: 0 2px 2px 0;
        }
        .dragRight:not(:hover):not(:active) > span,
        .dragLeft:not(:hover):not(:active) > span {
            visibility: hidden;
            color: #000;
       }
        .dragRight > span > span,
        .dragLeft > span > span {
            display: block;
            background: #4285f4;
           height: 20px;
            padding: 0 4px;
            border-radius: 2px;
            line-height: 20px;
        }
        .rule-item {
            position: absolute;
            bottom: 0;
            display: inline-block;
        }
        .rule-item > span {
            position: absolute;
            left: -2px;
            text-align: center;
            bottom: 10px;
            color: rgba(0, 0, 0, 0.85);
            font-size: 12px;
            pointer-events: none;
        }
        .rule-ruleSubList {
            display: flex;
            justify-content: space-between;
            align-items: flex-end;
            position: absolute;
            width: 100%;
            bottom: 0;
        }
        .rule-ruleSubList i {
            border-left: 1px solid rgba(0, 0, 0, 0.1);
            width: 0;
            height: 4px;
        }
        .rule-ruleSubList i:first-child {
            border-left: 1px solid rgba(0, 0, 0, 0.65);
            height: 4px;
        }
    </style>
    <body>
        <div class="timelineScroll">
            <div class="timelineScrollinner">
                <!--  -->
                <div class="rule-ruleContainer">
                    <div class="rule-item" style="width: 110px; left: 0px">
                        <span>00:00:00</span>
                        <div class="rule-ruleSubList"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div>
                    </div>
                    <div class="rule-item" style="width: 110px; left: 110px">
                        <span>00:00:00</span>
                        <div class="rule-ruleSubList"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div>
                    </div>
                </div>
                <!--  -->
                <div class="timelineBack">
                    <div class="timeline">
                        <div class="highlights">
                            <div class="highlightsCon"></div>
                        </div>
                        <!-- selection -->
                        <div class="selection" style="left: 0px">
                            <div class="selectionText">0</div>
                            <!-- dragLeft -->
                            <div class="dragLeft">
                                <span>
                                    <span style="margin-left: 30px" class="leftText">00:00</span>
                                </span>
                            </div>
                            <!-- dragRight -->
                            <div class="dragRight">
                                <span>
                                    <span style="margin-left: 0px" class="rightText">00:00</span>
                                </span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </body>
    <script>
        // 滑块类
        class RangeSlider {
            constructor(userOptions) {
                this._init(userOptions)
            }
            _init(userOptions) {
                // 合并参数
                this.options = userOptions
                // 滑块轨道容器
                this.container = this._get(this.options.sliderContainer)
                // 滑块内容容器
                this.content = this._get(this.options.sliderContent)
                // 滑块左边按钮
                this.left = this._get(this.options.sliderLeft)
                // 滑块右边按钮
                this.right = this._get(this.options.sliderRight)
                // 滑块左边按钮顶部提示
                this.leftText = this._get(this.options.leftText)
                // 滑块右边按钮顶部提示
                this.rightText = this._get(this.options.rightText)
                // 滑块内容按钮提示
                this.contentText = this._get(this.options.contentText)
                // 设置初始值
                this._setAttr()
                this._textRefresh()
                // 添加事件
                this.content.onmousedown = ({ target: { className }, clientX }) => {
                    // 滑块宽度 动态值
                    let sliderWidth = this.content.offsetWidth
                    // 滑块宽度 距离左边 动态值
                    let sliderLeft = this.content.offsetLeft
                    switch (className) {
                        case 'selection':
                            // 滑块 X 坐标计算
                            this.disX = clientX - this.content.offsetLeft
                            // 滑块最大left 值
                            let sliderMaxLeft = this.container.offsetWidth - sliderWidth
                            document.onmousemove = ({ clientX }) => {
                                this.content.style.left = clientX - this.disX < 0 ? 0 : clientX - this.disX > sliderMaxLeft ? sliderMaxLeft + 'px' : clientX - this.disX + 'px'
                                this._textRefresh()
                            }
                            break
                        case 'dragLeft':
                            // width 增 ↑  left ↓
                            // 滑块 X 坐标计算
                            this.disX = clientX
                            // 滑块右边按钮 至 轨道 最左边变距离
                            let rightWidth = this.content.getBoundingClientRect().right - this.container.getBoundingClientRect().left // 固定值
                            // 移动
                            document.onmousemove = ({ clientX }) => {
                                // 两点间的 x 差值
                                let diff = this.disX - clientX
                                let n1 = sliderWidth + diff
                                let n2 = sliderLeft - diff
                                if (this.options.rangeMin && n1 <= this.options.rangeMin) {
                                    n1 = this.options.rangeMin
                                    n2 = rightWidth - this.options.rangeMin
                                } else if (this.options.rangeMax && n1 >= this.options.rangeMax) {
                                    n1 = this.options.rangeMax >= rightWidth ? rightWidth : this.options.rangeMax
                                    n2 = rightWidth - (this.options.rangeMax >= rightWidth ? rightWidth : this.options.rangeMax)
                                } else if (n1 >= rightWidth) {
                                    n1 = rightWidth
                                    n2 = 0
                                } else if (n2 >= rightWidth) {
                                    n1 = 0
                                    n2 = rightWidth
                                }
                                this.content.style.left = n2 + 'px'
                                this.content.style.width = n1 + 'px'
                                this.right.style.left = n1 + 'px'
                                this._textRefresh()
                            }
                            break
                        case 'dragRight':
                            // 滑块 X 坐标计算
                            this.disX = clientX - this.right.offsetLeft
                            document.onmousemove = ({ clientX }) => {
                                // 容器宽度
                                let c_w = this.container.offsetWidth
                                // 滑块左边可滑动距离
                                let c_l = this.content.offsetLeft
                                // 左边最大可以滑动 距离
                                let sliderMaxLeft = this.options.rangeMax ? (this.options.rangeMax >= c_w - c_l ? c_w - c_l : this.options.rangeMax) : c_w - c_l
                                // 如果两点x坐标差值 小于等于 最小值?
                                let diff = clientX - this.disX

                                let num = diff <= (this.options.rangeMin || 0) ? this.options.rangeMin || 0 : diff >= sliderMaxLeft ? sliderMaxLeft : diff

                                this.right.style.left = num + 'px'
                                this.content.style.width = this.right.offsetLeft + 'px'
                                this._textRefresh()
                            }
                    }
                    document.onmouseup = () => {
                        document.onmousemove = null
                        document.onmouseup = null
                    }
                    return false
                }
            }

            // 执行属性初始化
            _setAttr() {
                // 主要设置
                let val = this.options.initRangeValue || 0
                this.right.style.left = val + 'px'
                this.content.style.width = val + 'px'
                this.contentText.innerText = val
            }

            // 获取 DOM 节点方法
            _get(selector) {
                return document.querySelector(selector)
            }

            // 文案同步刷新
            _textRefresh() {
                // 开始按钮距离 左边的距离
                let start = this.content.offsetLeft
                // 结束按钮距离 左边的距离
                let end = this.content.getBoundingClientRect().right - this.container.getBoundingClientRect().left
                // 容器的总宽度
                let total = this.container.offsetWidth
                // 刷新 左边按钮 tip 文案
                this.leftText.innerText = start
                // 刷新 右边按钮 tip 文案
                this.rightText.innerText = end
                // 刷新 内容按钮 tip 文案
                this.contentText.innerText = end - start
            }

            /**
             * @description: 手动设置右边按钮拉伸到右边,
             * @param { Number } n:设置的值 范围 为: {0, rightMax:右边最大距离值}
             */

            rightStretch(n) {
                // 边界处理
                let rightMax = this.container.offsetWidth - this.content.offsetLeft
                this.content.style.width = this.right.style.left = (n >= rightMax ? rightMax : n) + 'px'
                this._textRefresh()
                return this
            }

            /**
             * @description: 手动设置左边按钮拉伸到左边,
             * @param { Number } n:设置的值 范围 为: { leftMax:左边最大距离值,0}
             */

            leftStretch(n) {
                // <左边最大距离值>
                let leftMax = this.content.getBoundingClientRect().right - this.container.getBoundingClientRect().left
                // 如果左边按钮超出 最大距离左边边界值,则 就都设置成 <左边最大距离值>leftMax
                this.content.style.width = this.right.style.left = (n >= leftMax ? leftMax : n) + 'px'
                // 边界处理
                this.content.style.left = (n <= leftMax ? leftMax - n : 0) + 'px'
                this._textRefresh()
                return this
            }

            /**
             * @description: 手动设置滑块整体 向右 / 向右 移动
             * @param { Number } n :移动距离 {左边:0,右边:max }
             */

            move(n) {
                let max = this.container.offsetWidth - this.content.offsetWidth
                this.content.style.left = (n >= max ? max : n) + 'px'
                this._textRefresh()
                return this
            }
        }
        const rangeSlider = new RangeSlider({
            sliderContainer: '.highlights', // 滑块容器类
            sliderContent: '.selection', // 滑块内容类
            sliderLeft: '.dragLeft', //滑块左边按钮类
            sliderRight: '.dragRight', // 滑块右边按钮类
            leftText: '.leftText', // 滑块左边刻度类
            rightText: '.rightText', // 滑块右边刻度类
            contentText: '.selectionText', // 滑块内容文案类
            initRangeValue: 100, // 初始区间值
            rangeMax: 200, // 最大区间值
            rangeMin: 50 // 最小区间值
        })
    </script>
</html>

「两年博客,如果觉得我的文章对您有用,请帮助本站成长」

赞(1) 打赏

感谢您让我添加个鸡腿!

支付宝
微信
1

感谢您让我添加个鸡腿!

支付宝
微信
标签:

上一篇:

下一篇:

共有 0 条评论 - 【造轮子】左右伸缩兼左右滑动的区间滑块

博客简介

精彩评论

服务热线:
 177****6038

 QQ在线交流

 旺旺在线