技术标签: 前端练手
如果想看最优解,请跳到Version 2
第一次自己尝试轮播图,思路大概是这样的:
点击按钮切换图片&导航点→点击导航点切换图片→自动播放图片并切换导航点→添加过渡效果
其中,切换图片用的是修改src的方式,导致我在添加过渡时绕了弯路,最后的效果差强人意,这只是过渡轮播图的第一版。
后来又尝试了把图片横着排,改变left的第二版,意识到官网的过渡效果应该同时包括淡入和淡出,即上一张图片淡出的时候下一张图片淡入,我前两次的尝试都是把每张图片分开的,不论是修改src还是修改left,两张图片没有交集,自然做不出好的过渡效果。
HTML
<div class="banner-wrapper">
<div class="banner w">
<ul class="img">
<li><a href="#"><img class="banner-img"src="./img/banner1.jpg"></a></li>
</ul>
<div class="dot-wrapper">
<a href="#" class="dot"></a>
<a href="#" class="dot"></a>
<a href="#" class="dot"></a>
<a href="#" class="dot"></a>
<a href="#" class="dot"></a>
</div>
<div>
<a href="#" class="prev"></a>
</div>
<div>
<a href="#" class="next"></a>
</div>
</div>
</div>
CSS
.banner{
position: relative;
height: 460px;
}
.banner .img li{
position: absolute;
}
.banner .banner-img{
width: 100%;
}
.transition{
width: 100%;
animation: Ani 800ms linear 1;
}
@keyframes Ani{
0%{
opacity: 0.4;
}
100%{
opacity: 1;
}
}
.dot-wrapper{
width: 80px;
height: 10px;
bottom: 22px;
right: 35px;
position: absolute;
}
.dot{
width: 6px;
height: 6px;
border-radius: 50%;
background-color: rgba(0, 0, 0, .4);
border: 2px rgba(255, 255, 255, .4) solid;
margin-left: 6px;
float: left;
}
.active{
border-color: rgba(0, 0, 0, .4);
background-color:rgba(255, 255, 255, .4);
}
.dot:hover{
border-color: rgba(0, 0, 0, .4);
background-color:rgba(255, 255, 255, .4);
}
.prev,.next{
display: block;
position: absolute;
width: 41px;
height: 69px;
background-image: url(../img/icon-slides.png);
top: 184px;
}
.prev{
left: 233px;
background-position: -83px;
}
.prev:hover{
background-position: 0px;
}
.next{
right: 0;
background-position: -124px;
}
.next:hover{
background-position: -41px;
}
JS
window.onload = function(){
let prev = document.getElementsByClassName("prev")[0];
let next = document.getElementsByClassName("next")[0];
let img = document.getElementsByClassName("banner-img")[0];
let dots = document.getElementsByClassName("dot");
let imgArr = ["img/banner1.jpg","img/banner2.jpg","img/banner3.jpg","img/banner4.jpg","img/banner5.jpg"];
let index = 0;
//let count = 0; 动画播放次数计时器
dots[index].className = "dot active"//让第一个导航点选中
//点击按钮切换图片,改变导航点,设置过渡
prev.onclick = function(){
index--;
// count++;
if(index < 0){
index = imgArr.length - 1;
}
// if(img.className == "transition2" || img.className == "banner-img"){
// img.className = "transition1";
// }
// if(img.className == "transition1" || img.className == "banner-img"){
// img.className = "transition2";
// }
//尝试双类名交替,让动画多次播放,失败
//img.className = "transition";
//img.style.animationIterationCount = count;
//尝试增加播放次数,让动画多次播放,失败
img.className = "transition";//这一句必需,否则transition函数的第一句无法发挥作用,达不到预期效果
transition();//必须在第一句的下面
img.src = imgArr[index];
dots[index].className = "dot active";//让当前导航点选中
if(index+1 <= dots.length-1){
dots[index+1].className = "dot";
}
else{
dots[0].className = "dot";
}
clearInterval(timer);//关闭之前的定时器(每次点击按钮时要重新开始计时)
timer = autoRun();//设置新的定时器
}
next.onclick = function(){
index++;
if(index > imgArr.length -1){
index = 0;
}
img.className = "transition";
transition();
img.src = imgArr[index];
dots[index].className = "dot active";//让当前导航点选中
if(index-1 >= 0){
dots[index-1].className = "dot"
}
else{
dots[dots.length-1].className = "dot"
}
clearInterval(timer);//关闭之前的定时器
timer = autoRun();//设置新的定时器
}
//点击导航点切换图片
let tmp = 0;
for(let i = 0;i < dots.length; i++){
dots[i].onclick = function(){
dots[index].className = "dot";
//双变量方法:index是点击prev和next对应的图片编号,i是属于每个导航点的编号
//不能在2个for循环内都用index,否则无法修改index,即最后一行的代码无法实现
//先让index对应的导航点未选中
dots[tmp].className = "dot";
//tmp表示之前 通过点击导航点 而选中的导航点,让它未选中
dots[i].className = "dot active";
//让 最新一次点击的导航点 选中
img.src = imgArr[i];
img.className = "transition";
transition();
//改变图片
tmp = i;
//更新tmp
index = i;
//修改index,否则再次点击prev或next时会出问题
clearInterval(timer);//关闭之前的定时器
timer = autoRun();//设置新的定时器
}
}
timer = autoRun();
img.style.transitionDuration = "1s";
//图片的自动轮播函数
function autoRun(){
let timer = setInterval(function(){
index++;
if(index >= imgArr.length){
index = 0;
dots[dots.length-1].className = "dot";
}
else{
dots[index-1].className = "dot";
}
img.src = imgArr[index];
img.className = "transition";
transition();
dots[index].className = "dot active";
},5000);
// let timer_ = transition();
// img.style.opacity = 1;
return timer;
//timer封装在autoRun函数内,外层访问不到,必须返回timer,这样才能关闭定时器
}
//轮播的过渡效果
function transition(){
// img.style.opacity = 1; 默认值
// let timer_ = setTimeout(() => {
// img.style.opacity = 0;
// }, 4000);
// img.style.opacity = 1;
//如果像上边这样写,会先执行最后一行代码,再执行定时器,错误
//setTimeOut定时器不可行,因为在点击按钮和导航点时是等不到4s的,会失去过渡效果,而且定时器的开关问题比较麻烦
document.querySelector(".transition").className = "banner-img";
//注意,需要先在prev,next和导航点的onclick回调函数中,将img的className设为transition
window.requestAnimationFrame(function(time){
window.requestAnimationFrame(function(time){
document.querySelector(".banner-img").className = "transition";
});
});
}
//如果不在上方直接调用transition函数,写成这种绑定的形式也可以:
// document.querySelector(".prev").addEventListener("click", transition, false);
// document.querySelector(".next").addEventListener("click", transition, false);
// for(let j = 0;j < dots.length;j++){
// dots[j].addEventListener("click", transition, false);
// }
}
最后过渡的效果,是反复执行一段动画(半透明→不透明)实现的,至于如何反复执行一段动画,参考了CSS动画之animation再次触发与防止多次触发
后来上网查,发现正确做法应该是:把所有图片叠在一起,每次只有一张的opacity值为1,其它为0,切换图片时候就把要隐藏元素的opacity设为0,要显示的设为1,再加上transition过渡,大功告成
HTML
<div class="banner-wrapper">
<div class="banner w">
<ul class="img-list">
<li class="banner-img no-trans"><a href="#"><img src="./img/banner1.jpg"></a></li>
<li class="banner-img"><a href="#"><img src="./img/banner2.jpg"></a></li>
<li class="banner-img"><a href="#"><img src="./img/banner3.jpg"></a></li>
<li class="banner-img"><a href="#"><img src="./img/banner4.jpg"></a></li>
<li class="banner-img"><a href="#"><img src="./img/banner5.jpg"></a></li>
</ul>
<div class="dot-wrapper">
<a href="#" class="dot"></a>
<a href="#" class="dot"></a>
<a href="#" class="dot"></a>
<a href="#" class="dot"></a>
<a href="#" class="dot"></a>
</div>
<div>
<a href="#" class="prev"></a>
</div>
<div>
<a href="#" class="next"></a>
</div>
</div>
</div>
CSS
.banner{
position: relative;
height: 460px;
}
.banner li{
position: absolute;
opacity: 0;
transition: opacity 800ms;
}
.banner li.no-trans{
opacity: 1;
/*让第一张图片设为不透明,避免刷新页面时多余的过渡*/
/*需要提高该选择器的优先级*/
}
.banner img{
width: 100%;
}
.dot-wrapper{
width: 80px;
height: 10px;
bottom: 22px;
right: 35px;
position: absolute;
}
.dot{
width: 6px;
height: 6px;
border-radius: 50%;
background-color: rgba(0, 0, 0, .4);
border: 2px rgba(255, 255, 255, .4) solid;
margin-left: 6px;
float: left;
}
.active{
border-color: rgba(0, 0, 0, .4);
background-color:rgba(255, 255, 255, .4);
}
.dot:hover{
border-color: rgba(0, 0, 0, .4);
background-color:rgba(255, 255, 255, .4);
}
.prev,.next{
display: block;
position: absolute;
width: 41px;
height: 69px;
background-image: url(../img/icon-slides.png);
top: 184px;
}
.prev{
left: 233px;
background-position: -83px;
}
.prev:hover{
background-position: 0px;
}
.next{
right: 0;
background-position: -124px;
}
.next:hover{
background-position: -41px;
}
JS
window.onload = function(){
let prev = document.getElementsByClassName("prev")[0];
let next = document.getElementsByClassName("next")[0];
let imgs = document.getElementsByClassName("banner-img");
let dots = document.getElementsByClassName("dot");
let index = 0;
imgs[index].style.opacity = 1;
dots[index].className = "dot active"
prev.onclick = function(){
index--;
if(index >= 0){
imgs[index].style.opacity = 1;
imgs[index + 1].style.opacity = 0;
dots[index].className = "dot active";
dots[index + 1].className = "dot";]
else{
index = imgs.length - 1;
imgs[index].style.opacity = 1;
imgs[0].style.opacity = 0;
dots[0].className = "dot";
dots[dots.length - 1].className = "dot active";
}
clearInterval(timer);
timer = autoRun();
}
next.onclick = function(){
index++;
if(index < imgs.length){
imgs[index - 1].style.opacity = 0;
imgs[index].style.opacity = 1;
dots[index].className = "dot active";
dots[index - 1].className = "dot";
}
else{
index = 0;
imgs[imgs.length - 1].style.opacity = 0;
imgs[index].style.opacity = 1;
dots[dots.length - 1].className = "dot";
dots[0].className = "dot active";
}
clearInterval(timer);
timer = autoRun();
}
for(let i = 0; i < dots.length; i++){
dots[i].onclick = function(){
imgs[index].style.opacity = 0;
dots[index].className = "dot";
imgs[i].style.opacity = 1;
dots[i].className = "dot active";
index = i;
clearInterval(timer);
timer = autoRun();
}
}
function autoRun(){
let timer = setInterval(function(){
index++;
if(index < imgs.length){
imgs[index - 1].style.opacity = 0;
imgs[index].style.opacity = 1;
dots[index].className = "dot active";
dots[index - 1].className = "dot";
}
else{
index = 0;
imgs[imgs.length - 1].style.opacity = 0;
imgs[index].style.opacity = 1;
dots[dots.length - 1].className = "dot";
dots[0].className = "dot active";
}
},5000);
return timer;
}
let timer = autoRun();
}
Version2基本上就能还原小米官网的轮播图了
如果有帮助的话,请帮我Star一下→谢谢大佬动动手指
文章浏览阅读1.6w次,点赞8次,收藏41次。生活中我们无时不刻不都要在网站搜索资源,但就是缺少一个趁手的资源搜索网站,如果有一个比较好的资源搜索网站可以帮助我们节省一大半时间!今天小编在这里为大家分享5款超厉害的资源搜索网站,每一款都可以让你的资源丰富精彩!网盘传奇一款最有效的网盘资源搜索网站你还在为找网站里面的资源而烦恼找不到什么合适的工具而烦恼吗?这款网站传奇网站汇聚了4853w个资源,并且它每一天都会持续更新资源;..._最全资源搜索引擎
文章浏览阅读4.5k次,点赞5次,收藏18次。阅读测试程序,设计一个Book类。函数接口定义:class Book{}该类有 四个私有属性 分别是 书籍名称、 价格、 作者、 出版年份,以及相应的set 与get方法;该类有一个含有四个参数的构造方法,这四个参数依次是 书籍名称、 价格、 作者、 出版年份 。裁判测试程序样例:import java.util.*;public class Main { public static void main(String[] args) { List <Book>_6-1 book类的设计java
文章浏览阅读613次,点赞28次,收藏27次。相比于以前的传统手工管理方式,智能化的管理方式可以大幅降低学校的运营人员成本,实现了校园导航的标准化、制度化、程序化的管理,有效地防止了校园导航的随意管理,提高了信息的处理速度和精确度,能够及时、准确地查询和修正建筑速看等信息。课题主要采用微信小程序、SpringBoot架构技术,前端以小程序页面呈现给学生,结合后台java语言使页面更加完善,后台使用MySQL数据库进行数据存储。微信小程序主要包括学生信息、校园简介、建筑速看、系统信息等功能,从而实现智能化的管理方式,提高工作效率。
传统上用户登陆状态会以 Session 的形式保存在服务器上,而 Session ID 则保存在前端的 Cookie 中;而使用 JWT 以后,用户的认证信息将会以 Token 的形式保存在前端,服务器不需要保存任何的用户状态,这也就是为什么 JWT 被称为无状态登陆的原因,无状态登陆最大的优势就是完美支持分布式部署,可以使用一个 Token 发送给不同的服务器,而所有的服务器都会返回同样的结果。有状态和无状态最大的区别就是服务端会不会保存客户端的信息。
文章浏览阅读784次。发表于10小时前| 2674次阅读| 来源TechCrunch| 19 条评论| 作者Jon EvansiOSAndroid应用开发产品编程语言JavaObjective-C摘要:即便Android市场份额已经超过80%,对于开发者来说,使用哪一个平台做开发仍然很难选择。本文从开发环境、配置、UX设计、语言、API、网络、分享、碎片化、发布等九个方面把Android和iOS_ios 开发角度
搜索引擎的发展历史可以追溯到20世纪90年代初,随着互联网的快速发展和信息量的急剧增加,人们开始感受到了获取和管理信息的挑战。这些阶段展示了搜索引擎在技术和商业模式上的不断演进,以满足用户对信息获取的不断增长的需求。
文章浏览阅读990次。对象特性是指控制对象的输出参数和输入参数之间的相互作用规律。放大系数K描述控制对象特性的静态特性参数。它的意义是:输出量的变化量和输入量的变化量之比。时间常数T当输入量发生变化后,所引起输出量变化的快慢。(动态参数) ..._控制对象特性
文章浏览阅读5.7w次,点赞50次,收藏276次。FRP搭建内网穿透1.概述:frp可以通过有公网IP的的服务器将内网的主机暴露给互联网,从而实现通过外网能直接访问到内网主机;frp有服务端和客户端,服务端需要装在有公网ip的服务器上,客户端装在内网主机上。2.简单的图解:3.准备工作:1.一个域名(www.test.xyz)2.一台有公网IP的服务器(阿里云、腾讯云等都行)3.一台内网主机4.下载frp,选择适合的版本下载解压如下:我这里服务器端和客户端都放在了/usr/local/frp/目录下4.执行命令# 服务器端给执_locyanfrp
文章浏览阅读687次。题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93745#problem/A题意:给出r*c的01矩阵,可以翻转格子使得0表成1,1变成0,求出最小的步数使得每一行中1的个数相等,每一列中1的个数相等。思路:网络流。容量可以保证每一行和每一列的1的个数相等,费用可以算出最小步数。行向列建边,如果该格子是_uva12534
文章浏览阅读504次。1、Let's Encrypt 90天,支持泛域名2、Buypass:https://www.buypass.com/ssl/resources/go-ssl-technical-specification6个月,单域名3、AlwaysOnSLL:https://alwaysonssl.com/ 1年,单域名 可参考蜗牛(wn789)4、TrustAsia5、Alpha..._csdn alphassl免费申请
文章浏览阅读1.6k次。测试算法的性能 很多时候我们需要对算法的性能进行测试,最简单的方式是看算法在特定的数据集上的执行时间,简单的测试算法性能的函数实现见testSort()。【思想】:用clock_t计算某排序算法所需的时间,(endTime - startTime)/ CLOCKS_PER_SEC来表示执行了多少秒。【关于宏CLOCKS_PER_SEC】:以下摘自百度百科,“CLOCKS_PE_算法性能测试
文章浏览阅读1.2k次。fromhttps://towardsdatascience.com/finding-lane-lines-simple-pipeline-for-lane-detection-d02b62e7572bIdentifying lanes of the road is very common task that human driver performs. This is important ..._lanedetectionlite