今天要跟大家分享是利用js+css定位实现滑动盒子模型,其实这种滑动盒子模型是非常常见的,在很多网页中的banner或者是需要翻页的容器中经常会被用到。如下是最终的效果图:
如果你还没接触过这种有翻页动画的盒子,你也许会觉得很神奇,不知道该怎么实现。
下面再给你看一下真正的原理。
没错,其实就是这么简单!
其实它就是先把所有的选项排成一排,然后放入一个容器中,接着就是利用css的相对定位,改变left的值,这样就实现了左右移动的效果,最后再把外层容器的overflow属性设置为hidden,把超出部分隐藏,这样就实现了翻页效果。
接下来是具体的实现步骤:
①布局和样式,这里不需要多说,
1)需要注意的是用来容纳选项的里层盒子的宽度一定要大于所有选项宽度的总和,这样才能把所有的选项都放在一行。
2)还有需要注意的是,我们一定要计算好每一个选项的宽度,还有用来展示选项的宽度(也是一页的宽度),因为最后翻页是我们是要改变选项容器的left值的,而每翻一页,就是移动一页的宽度,这样才能美观。
3)最后也是最需要注意的细节是:装选项的移动盒子必须设置css的position属性为relative 并把left值设为0px,否则后面盒子是不能移动的。
//盒子模型
<div class="platform">
<span class="pre btn"><span>
<nav class="listBox">
<div class="innerBox">
<div class="item">1div>
<div class="item">2div>
<div class="item">3div>
<div class="item">4div>
<div class="item">5div>
<div class="item">6div>
<div class="item">7div>
<div class="item">8div>
<div class="item">9div>
div>
nav>
<span class="next btn">>span>
div>
*{
margin:0;
padding:0;
}
.platform{
position: relative;
margin:30px auto;
width:585px;
border:1px solid #000;
}
.listBox{
width:100%;
height: 250px;
overflow: hidden;
}
/*长度足够放12个item*/
.innerBox{
width:2340px;
height: 100%;
position: relative;
left:0px;//一定要显示写出0px
}
.item{
float:left;
margin:5px 15px 5px 0;
height: 240px;
width:180px;
color:#fff;
font-size:36px;
font-weight: 700;
line-height: 240px;
text-align:center;
border-radius: 4px;
}
.btn{
display:block;
width:36px;
height: 36px;
line-height:36px;
text-align:center;
font-size:20px;
font-weight: 700;
color:#fff;
background-color:#999;
border-radius: 50%;
cursor: pointer;
z-index:99;
}
.pre{
position: absolute;
display: none;
left:-40px;
top:50%;
margin-top:-18px;
}
.next{
position: absolute;
right:-40px;
top:50%;
margin-top:-18px;
}
.item:first-child{
background-color:blueviolet
}
.item:nth-child(2){
background-color:brown;
}
.item:nth-child(3){
background-color:burlywood;
}
.item:nth-child(4){
background-color:cadetblue;
}
.item:nth-child(5){
background-color:chartreuse;
}
.item:nth-child(6){
background-color:chocolate
}
.item:nth-child(7){
background-color:coral;
}
.item:nth-child(8){
background-color:cornflowerblue;
}
.item:nth-child(9){
background-color:crimson;
}
1)写移动函数,因为移动是有动画效果的,所有我们需要使用定时器来慢慢的改变left的值,
这个函数参数比较多,也比较复杂,请读者慢慢分析,这个函数是比较通用的,
这里我们是要改变left的值,所以,我们再调用时参数dir传入的值是'left'。具体调用看后面代码。
/**
* 移动函数,可以改变宽高,位置
* @param {*} obj 对象
* @param {*} target 目标位置
* @param {*} space 变化速度
* @param {*} dir 方向
* @param {*} callBack 回调函数
*/
function move(obj,target,space,dir,callBack){
//关闭上一个定时器
clearInterval(obj.timer);
//可改变方向
var oldValue = parseInt(getStyle(obj,dir));
if(oldValue > target){
space = -space;
};
//定义每个对象的定时器
obj.timer = setInterval(function(){
//获取旧值
var oldValue = parseInt(getStyle(obj,dir));
//变成新值
var newValue = oldValue + space;
//超过目标,把值变为目标值
if(space>0 && newValue>target || space<0 && newValue<target){
newValue = target;
}
obj.style[dir] = newValue +"px";
if(newValue==target){
//到达目标,清除定时器
clearInterval(obj.timer);
//有回调函数就执行,没有就不执行
callBack && callBack();
}
},10);
}
为了函数的通用性和可拓展性,我还定义了获取任意样式的函数
function getStyle(obj,name){
/**
* 要写成window.getComputedStyle
* 不能写getComputedStyle,
* 前者是属性,后者是变量,没有属性不会报错,而是返回undefined
* 后者是变量,变量没有找着就会报错
*/
//一般浏览器
if(window.getComputedStyle){
return getComputedStyle(obj,null)[name];
}else{
//ie8及以下浏览器
return obj.currentStyle[name];
}
}
接下来就是对两个翻页按钮绑定单击相应事件,调用移动函数 (585是一页的宽度,也可以使用外层容器的clientWidth,更灵活)
//获取列表容器
var innerBox = document.querySelector(".innerBox");
//获取左按钮
var preBtn = document.querySelector(".pre");
//获取右按钮
var nextBtn = document.querySelector(".next");
preBtn.firstClick = true;
nextBtn.firstClick = true;
preBtn.onclick = function(){
move(innerBox,parseInt(getStyle(innerBox,"left"))+585,20,"left",null);
}
nextBtn.onclick = function(){
move(innerBox,parseInt(getStyle(innerBox,"left"))-585,20,"left",null);
}
代码写到这里基本上,翻页功能是实现了的
but!!还有一些小细节需要注意!!
问题1:当翻到最后一页应该是不能在继续往下翻了,同样,在首页时,应该是不能往前翻了。
问题2:当翻页按钮被连续快速点击时,由于不断的触发移动函数,导致翻页后的位置错乱。
解决办法:
1、我们可以定义一个判断翻页按钮是否出现的函数,根据选项容器再移动后的位置来确定是否显示按钮:当left为0px时,表示当前展示第一页,那么就把上一页按钮隐藏;而当left为一页的宽度x(总页数-1)时,表示当前展示最后一页,那么就把下一页按钮隐藏,最后如果在其余位置就把两个按钮都显示。
2、如果我们能够使得选项容器再移动过程中,点击失效(不再调用move函数),那么就能避免move函数多次被调用而使移动错位了。
怎么实现?我们可以给两个按钮增加一个判断是否是第一次点击的属性,类型为boolean,初始值为true,当第一次点击后,把它更改为false,当move函数调用完后,再通过回调函数,把这个属性重新设置为true。
那么我们就要更改按钮单击事件绑定的函数了
preBtn.firstClick = true;
nextBtn.firstClick = true;
preBtn.onclick = function(){
if(this.firstClick){
this.firstClick = false;
move(innerBox,parseInt(getStyle(innerBox,"left"))+585,20,"left",function(){
preBtn.firstClick = true;
judge(innerBox,585*2,preBtn,nextBtn);
});
}
}
nextBtn.onclick = function(){
if(this.firstClick){
this.firstClick = false;
move(innerBox,parseInt(getStyle(innerBox,"left"))-585,20,"left",function(){
nextBtn.firstClick = true;
judge(innerBox,585*2,preBtn,nextBtn);
});
}
}
/**
* 回调函数,上一个程序执行完后在执行这个函数
* 判断函数
* 根据位置判断是否箭头展示
* 参数有(移动的对象,箭头消失时移动对象的位置条件,左箭头,右箭头)
*/
function judge(obj,length,leftArrow,rightArrow){
//获取当前位置
var position = parseInt(getStyle(obj,"left"));
//初始位置
if(position == 0){
leftArrow.style.display = "none";
rightArrow.style.display = "block";
//翻到最后一页
}else if(position == -length){
rightArrow.style.display = "none";
leftArrow.style.display = "block";
}else{
leftArrow.style.display = "block";
rightArrow.style.display = "block";
}
}
这样就把问题给解决啦!!
最后把超出部分隐藏起来
搞定!!!