HTML+CSS+JS简易轮播图
直接上代码
<!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>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
position: relative;
width: 730px;
height: 464px;
overflow: hidden;
}
.carousel {
display: flex;
width: 100%;
height: 100%;
transition: 1s all;
transform: translateX(-100%);
}
img {
width: 100%;
height: 100%;
}
.item{
min-width: 100%;
min-height: 100%;
width: 100%;
height: 100%;
}
.indicator {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 0;
}
span {
background-color: rgb(232,237,242);
display: inline-block;
width: 40px;
height: 5px;
}
.arrow_left,
.arrow_right {
width: 80px;
height: 80px;
background: url(./images/right.svg);
background-size: 80px 80px;
position: absolute;
margin-top: -40px;
}
.active{
background-color: rgb(18,150,219);
}
.arrow_left {
left: 0;
top: 50%;
transform: rotate(180deg);
}
.arrow_right {
right: 0;
top: 50%;
}
</style>
</head>
<body>
<div class="container">
<div class="carousel">
<div class="item"><img src="./images/banner5.jpg" alt=""></div>
<div class="item"><img src="./images/banner1.jpg" alt=""></div>
<div class="item"><img src="./images/banner2.jpg" alt=""></div>
<div class="item"><img src="./images/banner3.jpg" alt=""></div>
<div class="item"><img src="./images/banner4.jpg" alt=""></div>
<div class="item"><img src="./images/banner5.jpg" alt=""></div>
<div class="item"><img src="./images/banner1.jpg" alt=""></div>
</div>
<div class="indicator">
<span class="active"></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div class="arrow">
<div class="arrow_left"></div>
<div class="arrow_right"></div>
</div>
</div>
</body>
</html>
<script>
let set;
// 定义初始位置 第一张图片
let index = 1;
// 获取dom元素
let left = document.querySelector(".arrow_left");
let right = document.querySelector(".arrow_right");
let carousel = document.querySelector(".carousel");
let count = document.querySelectorAll(".item").length - 2;
let span = document.querySelectorAll("span");
// 移动函数
function move() {
document.querySelector(".active").removeAttribute("class","active");
span[index-1].classList.add("active");
let movement = (index * 100) * -1 + "%";
carousel.style.transform = `translateX(${movement})`;
}
// 点击向右移动
right.onclick = function () {
clearInterval(set);
init();
// 成功到达最后一张
if (index == count) {
// 去除动画回到0那个位置
carousel.style.transform = "translateX(0%)";
carousel.style.transition = "none"
// // 随意读个东西 触发浏览器的强制渲染
carousel.clientHeight;
// 恢复动画 注意此时是最后一张来到第0张了
carousel.style.transition = "1s all";
// 直接去1实现无缝连接
index = 1;
} else {
index++;
}
move();
}
// 向左移动
left.onclick = function () {
clearInterval(set);
init();
if (index == 1) {
carousel.style.transform = `translateX(${(count + 1) * 100 * -1}%)`;
carousel.style.transition = "none"
carousel.clientHeight;
carousel.style.transition = "1s all";
index = count;
} else {
index--;
}
move();
}
// 点击跳转
for (let i = 0; i < span.length; i++) {
span[i].onclick = function () {
clearInterval(set);
init();
index = (i + 1);
move();
}
}
// 自动轮播
init();
function init(){
set = setInterval(() => {
if (index == count) {
// 去除动画回到0那个位置
carousel.style.transform = "translateX(0%)";
carousel.style.transition = "none"
// // 随意读个东西 触发浏览器的强制渲染
carousel.clientHeight;
// 恢复动画 注意此时是最后一张来到第0张了
carousel.style.transition = "1s all";
// 直接去1实现无缝连接
index = 1;
} else {
index++;
}
move();
}, 4000);
}
</script>
上效果图
写完html转换一下vue代码
<template>
<div class="container">
<!-- 图片展示区域 用css的transform: translateX(-100%);实现图片的轮播 -->
<div class="carousel1" ref="carousel">
<div class="item" v-for="(item, index) in list" :key="index">
<img :src="item.src" alt="" />
</div>
</div>
<!-- 五个指示器 -->
<div class="indicator">
<span @click="span(index1)" :class="{'active':index == index1+1}" v-for="(item, index1) in len" :key="index1"></span>
</div>
<!-- 左右按钮 -->
<div class="arrow">
<div class="arrow_left" @click="left"></div>
<div class="arrow_right" @click="right"></div>
</div>
</div>
</template>
<script>
export default {
name: "Banner1",
// 接受具体想获取哪些图片的资源
props: ["type"],
data: function () {
return {
// 图片数组
list: [],
// 需要展示的图片数量
len: 0,
// 需要展示的图片顺序
index: 1,
// 定时器
set: null,
};
},
methods: {
//初始化图片数据
async initImage(type) {
let result = await this.$API.reqImage(type);
this.list = result.data;
this.len = this.list.length;
this.list.push(this.list[0]);
this.list.unshift(this.list[this.list.length - 2]);
this.auto();
},
// 移动函数
move() {
// 计算需要更改的具体值
let movement = this.index * 100 * -1 + "%";
// 更改css实现移动
this.$refs.carousel.style.transform = `translateX(${movement})`;
},
// 左移动
left() {
clearInterval(this.set);
this.auto();
if (this.index == 1) {
this.$refs.carousel.style.transform = `translateX(${
(this.len + 1) * 100 * -1
}%)`;
this.$refs.carousel.style.transition = "none";
this.$refs.carousel.clientHeight;
this.$refs.carousel.style.transition = "1s all";
this.index = this.len;
} else {
this.index--;
}
this.move();
},
// 右移动
right() {
clearInterval(this.set);
this.auto();
// 成功到达最后一张
if (this.index == this.len) {
// 去除动画回到0那个位置
this.$refs.carousel.style.transform = "translateX(0%)";
this.$refs.carousel.style.transition = "none";
// // 随意读个东西 触发浏览器的强制渲染
this.$refs.carousel.clientHeight;
// 恢复动画 注意此时是最后一张来到第0张了
this.$refs.carousel.style.transition = "1s all";
// 直接去1实现无缝连接
this.index = 1;
} else {
this.index++;
}
this.move();
},
// 自动播放
auto() {
this.set = setInterval(() => {
// 图片到达最后一张
if (this.index == this.len) {
// 去除动画回到0那个位置
this.$refs.carousel.style.transform = "translateX(0%)";
this.$refs.carousel.style.transition = "none";
// // 随意读个东西 触发浏览器的强制渲染
this.$refs.carousel.clientHeight;
// 恢复动画 注意此时是最后一张来到第0张了
this.$refs.carousel.style.transition = "1s all";
// 直接去1实现无缝连接
this.index = 1;
} else {
this.index++;
}
this.move();
}, 4000);
},
span(index){
clearInterval(this.set);
this.auto();
this.index = index+1;
this.move();
}
},
mounted() {
this.initImage(this.type);
},
};
</script>
<style scoped>
.container {
margin-top:.2rem;
margin-left: -0.4rem;
position: relative;
width: 730px;
height: 464px;
overflow: hidden;
}
.carousel1 {
display: flex;
width: 100%;
height: 100%;
transition: 1s all;
transform: translateX(-100%);
}
img {
width: 100%;
height: 100%;
}
.item {
min-width: 100%;
min-height: 100%;
width: 100%;
height: 100%;
}
.indicator {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 0;
}
span {
background-color: rgb(232, 237, 242);
display: inline-block;
width: 40px;
height: 5px;
margin-left: 0.5rem;
}
.arrow_left,
.arrow_right {
width: 80px;
height: 80px;
background: url(./images/right.svg);
background-size: 80px 80px;
position: absolute;
margin-top: -40px;
}
.active {
background-color: rgb(18, 150, 219);
}
.arrow_left {
left: 0;
top: 50%;
transform: rotate(180deg);
}
.arrow_right {
right: 0;
top: 50%;
}
</style>
代码一切完美运行无报错 然后随意找个地方加个空格报错了(超级神奇) 然后手动F5刷新不报错完美,随意找个地方加个空格让vue编译就报错
然后看具体报错的那行代码
说this.$res.carousel是undefined未定义 很显然我们在vue的template中写了这个东西的
然后上百度呗 看到了这篇文章
尝试了一下 打印有时候正常有时候两种方式都是undefined
考虑vue代码执行顺序这个问题(当时是分析dom没有渲染完毕然后获取不到为undefined嘛) 于是发现了这篇文章(只截图了关键性有用的信息) 回首看了一下自己的代码发现我们写的代码也是在mouted中调用的啊
后来看了一下官方文档 发现这个this.nexttick这个好东西当时心想就是获取不到就是dom没有渲染出来,用这个东西一定就解决问题(写在这个函数里面的东西就是一个异步的等待dom渲染完毕应该执行的代码,我代码中()=> 这个没写function是ES6语法的简写形式箭头函数) 实际上并没有解决问题还是最先的那个报错
于是自己想了一下加上这个if判断必须有你才给我执行,这样百分百解决报错。但不过该执行的代码报错,加上这样不报错,代码执行肯定达不到我预期的效果,实际上代码不报错了,也达到了我预期的效果
后面分析我的轮播图是4s自动切换一次嘛于是data中声明一个变量count来记录执行次数
效果图是这样的,VM224开头是第一次打开网页执行没清理的,然后我加了空格后保存,按理论来说应该count会清零重新计算 实际上红色箭头的重新计算了从0开始,然而上一次也就是第一次打开的也就是VM224开头的还在计算,这说明什么 上一次mouted函数还在执行,上一次的函数都还在执行,vue重新编译只刷新了dom元素,这些js代码还在执行没有正确的被回收,上一次的dom刷新了,就没有了carousel这个节点,再用js操作必定会报错,因为找不到所以undefined。 最后证明了一个问题vue的编译不会像我们按F5那样全局刷新网页,这算是我vscode的问题还是谷歌浏览器没清理缓存的问题呢我也不清楚。