注意:为了防止用户操作过快,导致动画叠加。在每一次新的动画前都需要调用
stop()
方法
1、 手风琴1
效果描述:每次点击一张图片,放置图片的父容器的宽从小逐渐变大。图片从垂直居中位置逐渐被拉开且前一张图片逐渐消失,被点击父容器内的图片逐渐出现。
效果图:
思路
由于每次点击一张图片,放置图片的父容器的宽从小逐渐变大。图片从垂直居中位置逐渐被拉开,故只需要使用自定义动画改变图片的高、放置图片父容器div的宽、图片的位置、图片的透明度即可。
每次点击不同div都要重新设置所有div的高、宽和left
- 最开始时先给每一个div父容器设置
data-index
,该值为每一个父容器对应的索引值。- 将所有操作封装成函数
setWAndH(indexTemp)
,该函数的参数为当前显示的图片的父容器的index(故之后点击每一个div时将其data-index
传入函数)- 在
setWAndH(indexTemp)
函数中进行设置每一个div的宽、高以及每一个div的位置(通过遍历(each()函数)实现),① 如果当前遍历的元素的index与indexTemp相等,则当前元素为显示元素,故将其宽设置为800,反之设置为60。②由于所有div的高是呈阶梯状,当前显示图片的高为500,其余元素的高与其自身index相关(500-Math.abs(indexTemp-index)*22
(22为每个相邻div高的差值))。③所有索引小于等于indexTemp
元素的left
都相差60,而大于indexTemp
的元素需要在原来计算的left
的基础上加上显示div的宽(即800)- 在
setWAndH(indexTemp)
函数中还要设置显现div的子元素图片的高、透明度及位置(注意:此设置需要以自定义动画的方式呈现),图片由最初的高度为0,不透明度为0以及top为50%变为高为父容器的100%,不透明度为1,top为0。非显示元素做与上述相反操作。
完整代码
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.all {
position: relative;
line-height: 424px;
width: 1000px;
height: 424px;
margin: 200px;
}
.all > div {
position: absolute;
border: 1px solid silver;
background: #ebffc6;
top: 0;
bottom: 0;
margin: auto;
}
.all>div>span{
position: absolute;
display: inline-block;
width: 100%;;
text-align: center;
}
img {
position: absolute;
width: 100%;
height: 0;
top: 50%;
}
</style>
</head>
<body>
<div class="all">
<div>
<span>1</span><img src="img/t1.png"/>
</div>
<div>
<span>2</span><img src="img/t2.png"/>
</div>
<div>
<span>3</span><img src="img/t3.png"/>
</div>
<div data-index="3">
<span>4</span><img src="img/t4.png"/>
</div>
<div>
<span>5</span><img src="img/t5.png"/>
</div>
<div>
<span>6</span><img src="img/t6.png"/>
</div>
<div>
<span>7</span><img src="img/t7.png"/>
</div>
</div>
</body>
<script src="js/jquery-1.9.1.js"></script>
<script src="js/jquery-3.0.0.js"></script>
<script>
//只需要变化图片的高以及div的宽即可。
$(function () {
setWAndH($(".all>div:nth-of-type(4)").attr("data-index"));
$(".all>div").on("click",function(){
setWAndH($(this).attr("data-index"))
});
function setWAndH(indexTemp) {
$(".all>div").each(function (index) {
//设置宽
if(!$(this).attr("data-index")){
$(this).attr("data-index",index);
}
var leftTemp =0;
if(indexTemp==index){
leftTemp = index*60;
$(this).stop(false,true).animate({
width:800,
height:500-Math.abs(indexTemp-index)*22,
left:leftTemp
}).children("img").stop(false,true).animate({
height: "100%",
opacity: 1,
top: 0
},300)
}else{
if(index>indexTemp){
leftTemp = (index-1)*60+800
}else{
leftTemp = index*60
}
$(this).stop(false,true).animate({
width:60,
height:500-Math.abs(indexTemp-index)*32,
left:leftTemp
}).children("img").stop(false,true).animate({
height: 0,
opacity: 0,
top: "50%"
}, 300);
}
//设置高
})
}
})
</script>
</html>
2. 手风琴2
点击一个
li
,该li
中的ul
显示,其余li
的ul
隐藏。默认情况下第一个li
的ul
显示,其余li
的ul
隐藏。
直接使用slideDown()和slideUp()
即可
效果图
完整代码
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<style>
*{
margin:0;
padding:0
}
li{
list-style:none
}
a{
text-decoration:none
}
.main>a{
display: inline-block;
height: 30px;
width: 240px;
background: -webkit-linear-gradient(top, #6c6e74 0%, #4b4d51 100%);
color:white;
text-align:center;
}
.main>ul>li{
height: 30px;
width: 240px;
background:#e5e5e5;
text-align:center;
color:#999;
border-bottom: 1px solid silver;
}
.all{
width: 300px;
margin:auto
}
.back{
background: -webkit-linear-gradient(top, #a5cd4e 0%, #6b8f1a 100%) !important;
}
.show{
display: block;
}
.menu{
display: none;
}
</style>
<body>
<ul class="all">
<li class="main">
<a class="back">菜单一</a>
<ul class="show">
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</li>
<li class="main">
<a>菜单二</a>
<ul class="menu">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</li>
<li class="main">
<a>菜单三</a>
<ul class="menu">
<li>1</li>
</ul>
</li>
<li class="main">
<a>菜单四</a>
<ul class="menu">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</li>
<li class="main">
<a>菜单五</a>
<ul class="menu">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
</ul>
</li>
</ul>
</body>
<script src="js/jquery-3.0.0.js"></script>
<script src="js/jquery-1.9.1.js"></script>
<script>
$(function(){
$(".main>a").each(function (index) {
$(this).click(function () {
$(this).siblings().removeClass().stop(false,true).slideDown().parent().siblings().find("ul").stop(false,true).slideUp();
$(this).addClass("back").parent().siblings().find("a").removeClass();
})
})
})
</script>
</html>
3. 选项卡(点餐)
效果描述:实现类似美团的点餐功能。当点击左边种类区时,右边会滑动至对应的种类区域最顶部。当滑动右边饭菜集合时,左边种类区也会切换到相应的位置。
效果图:
思路解析
- 当点击左边种类模块时,可通过点击
index
值计算右边滚动区域的scrollTop
,具体计算方法:用该index
对应的右边区域模块的position
中的top值(即相对于父元素顶部的距离)加上当前右边滚动区域的scrollTop
值,即为点击模块对应的右边区域最顶部。- 当滑动右边滚动区域时,可通过遍历右边滚动区域的所有
ul
,判断其position().top<=0
并且Math.abs($(this).position().top)<= $(this).height()
来确定当前可视区域对应的左边的index
(此处右边的每个ul
的index
值与左边可点击的每个模块的index
值是对应的)- 当点击左边的模块的
index
值大于等于左边div
的个数的一半时,将左边滚动区域的scrollTop
设置为滚动区域总高-可视区域高,当小于时,将左边滚动区域的scrollTop
设置为0
编写代码过程中遇到的问题
① 由于点击左边模块时,右边滚动区域会滚动,而右边滚动会重新设置左边选中模块。此时会出现左边选中模块一直切换的现象,直到右边滚动结束。此时可在点击左边某个模块后,右边滚动区域滚动结束前将右边滚动区域的滚动事件移除。在动画结束后再次绑定滚动事件。
② 在①中,在动画结束后绑定了滚动事件,虽然scrollTop
在意义上以及不再会改变了,但是仍会调用几次右边滚动事件(未解决(并不知道为啥,但不影响效果))。
③ 滚动事件在遍历的过程中,实际上会有两个index
符合if
判断(临界值的锅)。正确index
以及正确index
的前一个index
。但是由于遍历是从小到大遍历的,最终的结果还是正确的。
一些注意事项
① 当想要html
和body
与整个屏幕一样宽、高时,需设置html,body{width:100%;height:100%;}
② 当设置上下模块分别占不同比例时,设置margin
可能会导致一些错误。故可再添加一个顶部div
,当顶部和底部div
分别占页面的不同比例。
③ 当想要将滚动轴隐藏起来时,可将可滚动元素的宽稍微设置大一些。且给其父元素设置overflow:hidden
,则可实现。
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
<title>点外卖</title>
</head>
<style>
*{
margin:0;
padding:0;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
.header{
height: 30%;
}
.all{
display:flex;
width: 100%;
height: 70%;
overflow: hidden;
}
.leftOuter{
border:1px solid silver;
flex:1;
overflow: hidden;
}
.rightOuter{
border:1px solid silver;
flex: 3;
overflow: hidden;
position: relative;
}
.leftInner{
width: 110%;
overflow-y:scroll;
height: 100%;
}
.rightInner{
width: 110%;
overflow-y:scroll;
height: 100%;
}
.left,.right{
display: flex;
flex-direction: column;
}
.left{
height: 130%;
}
li{
list-style: none;
}
.left>div{
flex: 1;
line-height: 100px;
text-align: center;
border-bottom: 1px solid silver;
}
.right>ul>li{
height: 75px;
line-height: 75px;
text-align: center;
border-bottom: 1px solid silver;
}
.selectItem{
background: #cd94ff;
color:white
}
</style>
<body>
<div class="header"></div>
<div class="all">
<div class="leftOuter">
<div class="leftInner">
<div class="left">
<div class="selectItem">热销</div>
<div>折扣</div>
<div>必点</div>
<div>素菜</div>
<div>饮料</div>
<div>主食</div>
<div>餐盒</div>
<div>套餐</div>
</div>
</div>
</div>
<div class="rightOuter">
<div class="rightInner">
<div class="right">
<ul>
<li>热销</li>
<li>热销</li>
<li>热销</li>
</ul>
<ul>
<li>折扣</li>
<li>折扣</li>
<li>折扣</li>
</ul>
<ul>
<li>必点</li>
<li>必点</li>
</ul>
<ul>
<li>素菜</li>
<li>素菜</li>
<li>素菜</li>
<li>素菜</li>
<li>素菜</li>
<li>素菜</li>
</ul>
<ul>
<li>饮料</li>
<li>饮料</li>
<li>饮料</li>
</ul>
<ul>
<li>主食</li>
<li>主食</li>
<li>主食</li>
<li>主食</li>
<li>主食</li>
<li>主食</li>
<li>主食</li>
<li>主食</li>
</ul>
<ul>
<li>餐盒1</li>
<li>餐盒2</li>
<li>餐盒3</li>
<li>餐盒4</li>
<li>餐盒5</li>
<li>餐盒6</li>
<li>餐盒7</li>
</ul>
<ul>
<li>套餐1</li>
<li>套餐2</li>
<li>套餐3</li>
<li>套餐4</li>
<li>套餐5</li>
<li>套餐6</li>
<li>套餐7</li>
</ul>
</div>
</div>
</div>
</div>
<script src="js/jquery-1.9.1.js"></script>
<script src="js/jquery-3.0.0.js"></script>
<script>
$(function(){
$(".rightInner").on("scroll",scrollEvent)
$(".left>div").each(function (index) {
$(this).click(function () {
$(".rightInner").off("scroll",scrollEvent);
setTop(index);
$(this).addClass("selectItem").siblings().removeClass();
var initTop = $(".rightInner").scrollTop();
$(".rightInner").stop(true,true).animate({
"scrollTop":$(".right>ul").eq(index).position().top+initTop
},function () {
//在scrollTop改变后还会调用一两次scroll对应的函数,三种添加函数方式都会调用(我猜是不可避免的)
$(".rightInner").on("scroll",scrollEvent)
});
})
});
function scrollEvent() {
$(this).find("ul").each(function (index) {
if($(this).position().top<=0 && Math.abs($(this).position().top)<= $(this).height()){
//会进来两次,一次是点击的index对应的模块,一次是点击的index的上一个索引模块(最终会取点击的index对应的模块)
$(".left>div").eq(index).addClass("selectItem").siblings().removeClass();
setTop(index);
}
})
}
function setTop(index) {
console.log(index);
if(index>=$(".left>div").length/2){
$(".leftInner").stop().animate({
scrollTop:$(".leftInner").height()
})
}else{
$(".leftInner").stop().animate({
scrollTop:0
})
}
}
})
</script>
</body>
</html>
4. 图片轮播
效果图
核心思想:
- 在准备展示第二张图片时(即
nowIndex==图片总个数(包含最后一张图片)
),先让整体的marginLeft
变为0,并让nowIndex
变为1(nowIndex
用来控制marginLeft
值),再根据nowIndex
求marginLeft
.此处注意:当展示最后一张图片时(与第一张相同),应让第一个圆圈变色。- 在点击向左移动的按钮时,先
nowIndex--
,再判断nowIndex<0
,若为true,则将marginLeft
设置为最右边对齐。将nowIndex
设置为图片总个数-2,然后再根据nowIndex
求新的marginLeft
值。- 在点击向右移动的按钮时,先
nowIndex++
,若nowIndex
为图片个数-1,其余操作不变,但底部第一个圆圈被选中。若nowIndex
为图片个数时,将marginLeft
设置为0,nowIndex
设置为1。再根据nowIndex
求新的marginLeft
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.all{
position: relative;
width: 500px;
height: 300px;
overflow: hidden;
margin: auto;
}
.inner{
width: 3000px;
height: 300px;
font-size: 0;
}
.inner>img{
width: 500px;
height: 300px;
display: inline-block;
}
.circle{
width: 150px;
position: absolute;
bottom: 5px;
left:0;
right:0;
margin:auto;
text-align:center;
}
.circle>span{
display: inline-block;
width: 15px;
height:15px;
border-radius:50%;
border:1px solid white;
}
.choose{
background: red;
}
.pos{
position: absolute;
top:0;
bottom:0;
margin:auto;
height: 20px;
width: 100%;
}
.pos>span{
display: inline-block;
width: 20px;
height: 20px;
}
.left{
position:absolute;
left:0;
background: white;
}
.right{
position: absolute;
right: 0;
background: white;
}
</style>
</head>
<body>
<div class="all">
<div class="inner">
<img src="img/1.jpg">
<img src="img/2.jpg">
<img src="img/3.jpg">
<img src="img/4.jpg">
<img src="img/5.jpg">
<img src="img/1.jpg">
</div>
<div class="circle">
<span class="choose"></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div class="pos">
<span class="left">左</span>
<span class="right">右</span>
</div>
</div>
</body>
<script src="js/jquery-3.0.0.js"></script>
<script>
$(function () {
var nowIndex=0;
var width = 500;
var timer;
function set(){
$(".inner").stop().animate({
"marginLeft":-nowIndex*width
});
$(".circle").find("span").eq(nowIndex).addClass("choose").siblings().removeClass();
}
function intervalTimer(){
//在准备播放第二张图片时,让整体的marginLeft变为0,并让nowIndex为1
nowIndex++;
if(nowIndex==$(".inner").children().length){
$(".inner").css({
marginLeft: 0
});
nowIndex=1;
}
set();//当nowIndex==$(".inner").children().length-1时,虽然找不到对应的圆圈,但是也不会报错
if(nowIndex==$(".inner").children().length-1){
$(".circle").find("span").eq(0).addClass("choose").siblings().removeClass();
}
}
timer=setInterval(intervalTimer,1000);
$(".all").on("mousemove mouseleave",function (e) {
if(e.type=="mousemove"){
clearInterval(timer)
}else{
timer=setInterval(intervalTimer,1000);
}
});
$(".pos").children().click(function () {
if($(this).html()=="左"){
nowIndex--;
if(nowIndex<0){
nowIndex=$(".inner").children().length-2;
$(".inner").css({
marginLeft:-(nowIndex+1)*width
});
}
set();
}else{
nowIndex++;
if(nowIndex==$(".inner").children().length){
$(".inner").css({
marginLeft: 0
});
nowIndex=1;
}
if(nowIndex==$(".inner").children().length-1){
//该判断可放到调用set前也可放到调用set后,由于无法找到nowIndex对应的圆圈,故在执行了set()方法后也不会改变选中的圆圈。
$(".circle").find("span").eq(0).addClass("choose").siblings().removeClass();
}
set();
}
});
$(".circle").children().each(function (index) {
$(this).mouseenter(function () {
nowIndex=index;
set();
})
})
})
</script>
</html>
转载:https://blog.csdn.net/weixin_43314846/article/details/102466678