HTML | 模板图片 轮播 (轮播图)

============================================ html

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
<!-- 放置在 head 中 -->
<link rel="stylesheet" href="图片轮播/lb.css">
<script src="图片轮播/lb.js"></script>
<script>
    window.onload = function () {<!-- -->
        // 轮播选项
        const options = {<!-- -->
            id: 'lb-1',              // 轮播盒ID
            speed: 600,              // 轮播速度(ms)
            delay: 3000,             // 轮播延迟(ms)
            direction: 'left',       // 图片滑动方向
            moniterKeyEvent: true,   // 是否监听键盘事件
            moniterTouchEvent: true  // 是否监听屏幕滑动事件
        }
        const lb = new Lb(options);
        lb.start();
    }
</script>

<!--轮播 图片-->
<div class="lb-box" id="lb-1">
    <!-- 轮播内容 -->
    <div class="lb-content">
        <div class="lb-item active">
            <a href="#">
                <img src="img/bg1.png" alt="picture loss">/*图片1*/
                <span>Description 1</span>
            </a>
        </div>
        <div class="lb-item">
            <a href="#">
                <img src="img/bg2.png" alt="picture loss">/*图片2*/
                <span>Description 2</span>
            </a>
        </div>
        <div class="lb-item">
            <a href="#">
                <img src="img/bg3.png" alt="picture loss">/*图片3*/
                <span>Description 3</span>
            </a>
        </div>
        <div class="lb-item">
            <a href="#">
                <img src="img/bg4.png" alt="picture loss">/*图片4*/
                <span>Description 4</span>
            </a>
        </div>
    </div>
    <!-- 轮播标志 -->
    <ol class="lb-sign">
        <li class="active">1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ol>
    <!-- 轮播控件 -->
    <div class="lb-ctrl left"><</div>
    <div class="lb-ctrl right">></div>
</div>

============================================ JS

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
/**
 * @desc 一个轮播插件
 * @author Mxsyx ([email protected])
 * @version 1.0.0
 */

class Lb {
    constructor(options) {
        this.lbBox = document.getElementById(options.id);
        this.lbItems = this.lbBox.querySelectorAll('.lb-item');
        this.lbSigns = this.lbBox.querySelectorAll('.lb-sign li');
        this.lbCtrlL = this.lbBox.querySelectorAll('.lb-ctrl')[0];
        this.lbCtrlR = this.lbBox.querySelectorAll('.lb-ctrl')[1];

        // 当前图片索引
        this.curIndex = 0;
        // 轮播盒内图片数量
        this.numItems = this.lbItems.length;

        // 是否可以滑动
        this.status = true;

        // 轮播速度
        this.speed = options.speed || 600;
        // 等待延时
        this.delay = options.delay || 3000;

        // 轮播方向
        this.direction = options.direction || 'left';

        // 是否监听键盘事件
        this.moniterKeyEvent = options.moniterKeyEvent || false;
        // 是否监听屏幕滑动事件
        this.moniterTouchEvent = options.moniterTouchEvent || false;

        this.handleEvents();
        this.setTransition();
    }

    // 开始轮播
    start() {
        const event = {
            srcElement: this.direction == 'left' ? this.lbCtrlR : this.lbCtrlL
        };
        const clickCtrl = this.clickCtrl.bind(this);

        // 每隔一段时间模拟点击控件
        this.interval = setInterval(clickCtrl, this.delay, event);
    }

    // 暂停轮播
    pause() {
        clearInterval(this.interval);
    }

    /**
     * 设置轮播图片的过渡属性
     * 在文件头内增加一个样式标签
     * 标签内包含轮播图的过渡属性
     */
    setTransition() {
        const styleElement = document.createElement('style');
        document.head.appendChild(styleElement);
        const styleRule = `.
        lb - item
        {
            transition: left
            ${this.speed}
            ms
            ease -in -out
        }`
    styleElement.sheet.insertRule(styleRule, 0);
    }

    // 处理点击控件事件
    clickCtrl(event) {
        if (!this.status) return;
        this.status = false;
        if (event.srcElement == this.lbCtrlR) {
            var fromIndex = this.curIndex,
                toIndex = (this.curIndex + 1) % this.numItems,
                direction = 'left';
        } else {
            var fromIndex = this.curIndex;
            toIndex = (this.curIndex + this.numItems - 1) % this.numItems,
                direction = 'right';
        }
        this.slide(fromIndex, toIndex, direction);
        this.curIndex = toIndex;
    }

    // 处理点击标志事件
    clickSign(event) {
        if (!this.status) return;
        this.status = false;
        const fromIndex = this.curIndex;
        const toIndex = parseInt(event.srcElement.getAttribute('slide-to'));
        const direction = fromIndex < toIndex ? 'left' : 'right';
        this.slide(fromIndex, toIndex, direction);
        this.curIndex = toIndex;
    }

    // 处理滑动屏幕事件
    touchScreen(event) {
        if (event.type == 'touchstart') {
            this.startX = event.touches[0].pageX;
            this.startY = event.touches[0].pageY;
        } else {  // touchend
            this.endX = event.changedTouches[0].pageX;
            this.endY = event.changedTouches[0].pageY;

            // 计算滑动方向的角度
            const dx = this.endX - this.startX
            const dy = this.startY - this.endY;
            const angle = Math.abs(Math.atan2(dy, dx) * 180 / Math.PI);

            // 滑动距离太短
            if (Math.abs(dx) < 10 || Math.abs(dy) < 10) return;

            if (angle >= 0 && angle <= 45) {
                // 向右侧滑动屏幕,模拟点击左控件
                this.lbCtrlL.click();
            } else if (angle >= 135 && angle <= 180) {
                // 向左侧滑动屏幕,模拟点击右控件
                this.lbCtrlR.click();
            }
        }
    }

    // 处理键盘按下事件
    keyDown(event) {
        if (event && event.keyCode == 37) {
            this.lbCtrlL.click();
        } else if (event && event.keyCode == 39) {
            this.lbCtrlR.click();
        }
    }

    // 处理各类事件
    handleEvents() {
        // 鼠标移动到轮播盒上时继续轮播
        this.lbBox.addEventListener('mouseleave', this.start.bind(this));
        // 鼠标从轮播盒上移开时暂停轮播
        this.lbBox.addEventListener('mouseover', this.pause.bind(this));

        // 点击左侧控件向右滑动图片
        this.lbCtrlL.addEventListener('click', this.clickCtrl.bind(this));
        // 点击右侧控件向左滑动图片
        this.lbCtrlR.addEventListener('click', this.clickCtrl.bind(this));

        // 点击轮播标志后滑动到对应的图片
        for (let i = 0; i < this.lbSigns.length; i++) {
            this.lbSigns[i].setAttribute('slide-to', i);
            this.lbSigns[i].addEventListener('click', this.clickSign.bind(this));
        }

        // 监听键盘事件
        if (this.moniterKeyEvent) {
            document.addEventListener('keydown', this.keyDown.bind(this));
        }

        // 监听屏幕滑动事件
        if (this.moniterTouchEvent) {
            this.lbBox.addEventListener('touchstart', this.touchScreen.bind(this));
            this.lbBox.addEventListener('touchend', this.touchScreen.bind(this));
        }
    }

    /**
     * 滑动图片
     * @param {number} fromIndex
     * @param {number} toIndex
     * @param {string} direction
     */
    slide(fromIndex, toIndex, direction) {
        if (direction == 'left') {
            this.lbItems[toIndex].className = "lb-item next";
            var fromClass = 'lb-item active left',
                toClass = 'lb-item next left';
        } else {
            this.lbItems[toIndex].className = "lb-item prev";
            var fromClass = 'lb-item active right',
                toClass = 'lb-item prev right';
        }
        this.lbSigns[fromIndex].className = "";
        this.lbSigns[toIndex].className = "active";

        setTimeout((() = > {
            this.lbItems[fromIndex].className = fromClass;
        this.lbItems[toIndex].className = toClass;
    }

).
    bind(

        this
),
        50
)
    ;

    setTimeout(

(() => {
        this
.
    lbItems

    [fromIndex]

.
    className = 'lb-item';
        this
.
    lbItems

    [toIndex]

.
    className = 'lb-item active';
        this
.
    status = true;  // 设置为可以滑动
}
).
bind(this), this.speed + 50
)
;
}
}

============================================ css

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
body {
    background-color: #252525
}

.lb-box {
    width: 100%; /*宽度*/
    height: 100%; /*高度*/
    margin: 15px auto;
    position: relative;
    overflow: hidden;
}

@media (max-width: 568px) {
    .lb-box {
        width: 76%;
        height: 220px;
    }
}

.lb-content {
    width: 100%;
    height: 100%;
}

.lb-item {
    width: 100%;
    height: 100%;
    display: none;
    position: relative;
}

.lb-item > a {
    width: 100%;
    height: 100%;
    display: block;
}

.lb-item > a > img {
    width: 100%;
    height: 100%;
}

.lb-item > a > span {
    width: 100%;
    display: block;
    position: absolute;
    bottom: 0px;
    padding: 15px;
    color: #fff;
    background-color: rgba(0, 0, 0, 0.7);
}

@media (max-width: 568px) {
    .lb-item > a > span {
        padding: 10px;
    }
}

.lb-item.active {
    display: block;
    left: 0%;
}

.lb-item.active.left {
    left: -100%;
}

.lb-item.active.right {
    left: 100%;
}

/*  */
.lb-item.next,
.lb-item.prev {
    display: block;
    position: absolute;
    top: 0px;
}

.lb-item.next {
    left: 100%;
}

.lb-item.prev {
    left: -100%;
}

.lb-item.next.left,
.lb-item.prev.right {
    left: 0%;
}

.lb-sign {
    position: absolute;
    right: 10px;
    top: 0px;
    padding: 5px 3px;
    border-radius: 6px;
    list-style: none;
    user-select: none;
    background-color: rgba(0, 0, 0, 0.7);
}

.lb-sign li {
    width: 22px;
    height: 20px;
    font-size: 14px;
    font-weight: 500;
    line-height: 20px;
    text-align: center;
    float: left;
    color: #aaa;
    margin: auto 4px;
    border-radius: 3px;
    cursor: pointer;
}

.lb-sign li:hover {
    color: #fff;
}

.lb-sign li.active {
    color: #000;
    background-color: #EBEBEB;
}

.lb-ctrl {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    font-size: 50px;
    font-weight: 900;
    user-select: none;
    background-color: rgba(0, 0, 0, 0.7);
    color: #fff;
    border-radius: 5px;
    cursor: pointer;
    transition: all 0.1s linear;
}

@media (max-width: 568px) {
    .lb-ctrl {
        font-size: 30px;
    }
}

.lb-ctrl.left {
    left: -50px;
}

.lb-ctrl.right {
    right: -50px;
}

.lb-box:hover .lb-ctrl.left {
    left: 10px;
}

.lb-box:hover .lb-ctrl.right {
    right: 10px;
}

.lb-ctrl:hover {
    background-color: #000;
}