js 轮播图(使用class实现)
纯属无聊,还花了一晚上时间o(╥﹏╥)o
1. js部分的代码
/**
* 判断对象是否为DOM元素
* @param {Object} obj
* @returns
*/
const isDOM = (obj) => (typeof HTMLElement === 'object')
? obj instanceof HTMLElement
: obj && typeof obj === 'object' &&
(obj.nodeType === 1 || obj.nodeType === 9) &&
typeof obj.nodeName === 'string'
const createDom = (className = '', tag = 'div') => {
const ele = document.createElement(tag)
ele.className = className
return ele
}
// 返回0-num之间的数
const getRandomInt = (num) => Math.floor(Math.random() * num)
// eslint-disable-next-line no-unused-vars
const getDom = (selector, all = false) => {
return all ? document.querySelectorAll(selector) : document.querySelector(selector)
}
class LoopImages {
constructor (container, srcArr, config) {
// 默认配置
this.config = {
loop: true, // 是否循环播放
autoPlay: true, // 是否自动播放
random: false, // 随机播放
arrowAlwaysShow: false,
duration: 3000 // 自动播放间隔
}
// 覆盖默认配置
Object.assign(this.config, config)
// 初始化容器,如果container为DOM对象则直接赋值,否则根据选择器查找
if (isDOM(container)) {
this.container = container
} else {
this.container = document.querySelector(container)
}
// 如果容器不存在
if (!isDOM(this.container)) {
throw new Error('未找到容器')
}
// 循环播放图片的地址数组
if (!!srcArr && !(srcArr instanceof Array)) {
throw new Error('srcArr 为数组')
}
this.srcArr = srcArr || []
this.length = this.srcArr.length
// 当前播放到的位置
this.current = 0
// 初始化内部的容器
this.init()
// 自动播放
this.config.autoPlay && this.autoPlay()
}
get _length () {
return this.length
}
get _srcArr () {
return this.srcArr
}
set _srcArr (value) {
if (!(this.srcArr instanceof Array)) {
throw new Error('srcArr 为数组')
}
this.srcArr = value
this.length = this.srcArr.length
}
get _current () {
return this.current
}
set _current (value) {
let errMsg
if (isNaN(Number(value))) {
errMsg = 'current 必须为数字'
}
if (errMsg) {
throw new Error(errMsg)
}
this.current = Math.min(this.length - 1, value)
this.setCurrent()
this.rePlay()
}
render () {
if (this.container && this.container.hasChildNodes()) {
return
}
// 渲染DOM
this.initImageList()
this.initCircleBtn()
this.initArrowBtn()
this.setCurrent()
this.addEventListener()
this.container && this.container.appendChild(this.loopImgBox)
}
// 设置当前circleBtn和图片
setCurrent () {
const that = this
;(this.cricleBtnList || []).forEach((btn, index) => {
index === that.current ? btn.classList.add('current') : btn.classList.remove('current')
})
;(this.loopImgList || []).forEach((img, index) => {
index === that.current ? img.classList.add('current') : img.classList.remove('current')
})
}
init () {
if (this.loopImgBox) {
return
}
const loopImgBox = document.createElement('div')
loopImgBox.className = 'loop-img-box'
this.loopImgBox = loopImgBox
}
// 初始化next,prev按钮
initArrowBtn () {
// 生成容器
if (this.arrowBtnBox) {
return
}
const arrowBtnBox = createDom('arrow-btn-box')
this.arrowBtnBox = arrowBtnBox
const prev = createDom('arrow-btn arrow-btn-prev')
this.prevBtn = prev
const next = createDom('arrow-btn arrow-btn-next')
this.nextBtn = next
if (this.config.arrowAlwaysShow) {
prev.classList.add('arrow-always-show')
next.classList.add('arrow-always-show')
}
arrowBtnBox.appendChild(prev)
arrowBtnBox.appendChild(next)
this.loopImgBox && this.loopImgBox.appendChild(arrowBtnBox)
}
initCircleBtn () {
if (this.circleBtnBox) {
return
}
const circleBtnBox = createDom('circle-btn-box')
this.circleBtnBox = circleBtnBox
// 循环生成小圆点, this.length 为当前图片链接数组的长度
this.cricleBtnList = []
for (let i = 0; i < this.length; i++) {
const circleBtn = createDom('circle-btn circle-btn-' + i)
this.cricleBtnList.push(circleBtn)
circleBtnBox.appendChild(circleBtn)
}
this.loopImgBox && this.loopImgBox.appendChild(circleBtnBox)
}
// 图片数组
initImageList () {
if (this.loopImgList) {
return
}
const loopImgListBox = createDom('loop-img-list')
this.loopImgList = []
this.loopImgListBox = loopImgListBox
Array.from(this.srcArr).forEach(src => {
// eslint-disable-next-line no-unused-vars
// const linkA = createDom('loop-img-link', 'a')
// linkA.setAttribute('href', '')
const img = createDom('loop-img-item', 'img')
img.setAttribute('src', src)
this.loopImgList.push(img)
loopImgListBox.appendChild(img)
})
this.loopImgBox && this.loopImgBox.appendChild(loopImgListBox)
}
// 更新视图
update () {
}
addEventListener () {
this.prevBtn && (this.prevBtn.onclick = (e) => {
e.stopPropagation()
this.prev()
})
this.nextBtn && (this.nextBtn.onclick = (e) => {
e.stopPropagation()
this.next()
})
;(this.cricleBtnList || []).forEach((btn, index) => {
btn.onclick = () => ((i) => {
this._current = i
})(index)
})
}
autoPlay () {
if (this.config.autoPlay) {
// 自动播放
this.autoPlayInterval = setInterval(() => {
this.config.random ? this.random() : this.next()
}, this.config.duration)
}
}
stopAutoPlay () {
clearInterval(this.autoPlayInterval)
}
rePlay () {
this.stopAutoPlay()
this.autoPlay()
}
next () {
// xia一张
const current = this.current + 1
if (current === this.length) {
if (this.config.loop) {
this._current = (current) % this.length
}
} else {
this._current = (current) % this.length
}
}
prev () {
// shang一张
let current = this.current
if (this.current === 0) {
if (this.config.loop) {
current = this.length
this._current = (current - 1) % this.length
}
} else {
this._current = (current - 1) % this.length
}
}
random () {
// 随机一张
let rand = getRandomInt(this.length)
while (rand === this.current) {
rand = getRandomInt(this.length)
}
this._current = rand
}
}
module && (module.exports = {
LoopImages
})
2. css 部分的样式
文件里的 …/img/prev.png 这张小图标如果觉得不大行的话直接到阿狸图标上找一张代替就行
…/img/prev.png
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.loop-img-box {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
}
.loop-img-list {
width: 100%;
height: 100%;
position: relative;
}
.loop-img-item {
display: none;
width: 100%;
height: 100%;
}
.loop-img-item.current {
display: block;
}
.circle-btn-box {
position: absolute;
display: flex;
justify-content: space-between;
width: 46px;
bottom: 10px;
left: calc(50% - 46px / 2);
}
.circle-btn {
cursor: pointer;
width: 10px;
height: 10px;
border: 1px solid #afafaf;
border-radius: 50%;
}
.circle-btn.current {
background: #272841;
}
.arrow-btn-box {
width: 100%;
height: 40px;
display: flex;
justify-content: space-between;
top: calc(50% - 20px);
position: absolute;
}
.arrow-btn-box:hover .arrow-btn {
background-image: url('../img/prev.png');
}
.arrow-always-show {
background-image: url('../img/prev.png');
}
.arrow-btn-prev {
cursor: pointer;
width: 30px;
height: 100%;
/*background-image: url('../img/prev.png');*/
background-repeat: no-repeat;
background-position: center;
background-size: cover;
}
.arrow-btn-next {
cursor: pointer;
width: 30px;
height: 100%;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
transform: rotate(180deg);
}
.arrow-btn-next:hover, .arrow-btn-prev:hover {
background-image: url('../img/prev.png');
}
3. 使用
<template>
<div>
<div class="loop-img-container" ref="loopImg"></div>
</div>
</template>
<script>
const { LoopImages } = require('@/assets/js/utils')
export default {
mounted () {
const loopImg = new LoopImages(this.$refs.loopImg, [
require('@/assets/logo.png'),
require('@/assets/img/prev.png'),
require('@/assets/logo.png'),
require('@/assets/img/prev.png')
], {
arrowAlwaysShow: true,
})
loopImg.render()
}
}
</script>
<style scoped>
.loop-img-container {
width: 90%;
border: 1px solid #1f1f1f;
height: 200px;
margin: 20px auto;
}
</style>