这是项目开始前的基础
这是最基本的布局
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
<title></title>
<style type="text/css">
*{margin: 0;padding: 0;}
html,body{height: 100%;overflow: hidden;}
#wrap{height: 100%;overflow: hidden;}
.carousel-wrap > .list{list-style: none;}/*清除列表的默认样式*/
.carousel-wrap > .list > li > a,
.carousel-wrap > .list > li > a >img{display: block;}/*清除空隙*/
.carousel-wrap > .list > li > a >img{width: 100%;}/*宽度自适应*/
.carousel-wrap > .list > li{float: left;width: 20%;}/*width拿的是list的1/5,即20%*/
.carousel-wrap > .list{width: 500%;overflow: hidden;}/*500%为li的5张图浮动后的宽度;overflow: hidden;使清除浮动撑开高度*/
</style>
</head>
<body>
<div id="wrap">
<div class="carousel-wrap">
<ul class="list">
<li>
<a href="javascript:;">
<img src="img/01.jpg"/>
</a>
</li>
<li>
<a href="javascript:;">
<img src="img/02.jpg"/>
</a>
</li>
<li>
<a href="javascript:;">
<img src="img/03.jpg"/>
</a>
</li>
<li>
<a href="javascript:;">
<img src="img/04.jpg"/>
</a>
</li>
<li>
<a href="javascript:;">
<img src="img/05.jpg"/>
</a>
</li>
</ul>
</div>
</div>
</body>
<script type="text/javascript">
window.onload=function(){
/*阻止默认行为*/
document.addEventListener("touchstart",function(ev){
ev=ev||event;
ev.preventDefault();
});
}
</script>
</html>
但这样的布局不够动态,满足不了我们的要求。
因此改为以下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"/>
<title></title>
<style type="text/css">
*{margin: 0;padding: 0;}
html,body{height: 100%;overflow: hidden;}
#wrap{height: 100%;overflow: hidden;}
.carousel-wrap > .list{list-style: none;overflow: hidden;position: absolute;}/*定位后,carousel-wrap高度就为0,需要手动计算*/
.carousel-wrap > .list > li{float: left;}
.carousel-wrap > .list > li > a,.carousel-wrap > .list > li > a >img{display: block;}
.carousel-wrap > .list > li > a >img{width: 100%;}
</style>
</head>
<body>
<div id="wrap">
<!-- carousel-wrap为“包裹器” -->
<div class="carousel-wrap"></div>
</div>
</body>
<script type="text/javascript">
window.onload=function(){
/*阻止默认行为*/
document.addEventListener("touchstart",function(ev){
ev=ev||event;
ev.preventDefault();
});
var arr=["img/01.jpg","img/02.jpg","img/03.jpg","img/04.jpg","img/05.jpg"];//图片
carousel(arr);//调用函数
function carousel(arr){
var carouselWrap = document.querySelector(".carousel-wrap");//查看是否有“包裹器”
if(carouselWrap){//如果有“包裹器”
var ulNode = document.createElement("ul");//定义一个ul
var styleNode = document.createElement("style");//创建一个style标签,用来添加生成的css样式
ulNode.classList.add("list");//给定义的ul添加class(class="list")
for(var i=0;i<arr.length;i++){//循环将图片加入html结构
ulNode.innerHTML+='+ arr[i]+'"/>';
}
//动态定义宽度
styleNode.innerHTML=".carousel-wrap > .list > li{width: "+(1/arr.length*100)+"%;}.carousel-wrap > .list{width: "+arr.length+"00%}";
carouselWrap.appendChild(ulNode);//在html结构中加入ul
document.head.appendChild(styleNode);//在结构中加入生成的css样式
var imgNodes = document.querySelector(".carousel-wrap > .list > li > a >img");//获取图片
setTimeout(function(){//初始时是没有结构的,获取时并没有渲染,因此需要延迟,等渲染完成后再取得
carouselWrap.style.height=imgNodes.offsetHeight+"px";//carousel-wrap的高度为任意一张图片的高度即可
},100)
}
}
}
</script>
</html>
/*滑屏
1.拿到元素一开始的位置
2.拿到手指一开始点击的位置
3.拿到手指move的实时距离
4.将手指移动的距离加给元素
*/
var startX = 0;//手指一开始的位置
var elementX = 0;//元素一开始的位置
var disX = 0;//手指滑动的距离
var index = 0;//图片的下标,不能定义在“touchend”函数的里面,因为如果定义在里面,则每次触发这个事件时,都会重新定义index且为0
carouselWrap.addEventListener("touchstart",function(ev){
ev=ev||event;
var TouchC = ev.changedTouches[0];//可能触屏的有多根手指,只拿其中的第一根
startX = TouchC.clientX;//手指一开始的横坐标
elementX = ulNode.offsetLeft;//元素的横坐标
})
carouselWrap.addEventListener("touchmove",function(ev){
ev=ev||event;
var TouchC = ev.changedTouches[0];//可能触屏的有多根手指,只拿其中的第一根
var nowX = TouchC.clientX;//手指的实时位置
disX = nowX - startX;//差值为实时距离
ulNode.style.left = elementX+disX+"px";//手指拖动图片的位置 = 元素一开始的位置 + 手指滑动的距离
})
carouselWrap.addEventListener("touchend",function(ev){
/* 向左/右滑动一点点,即可切换到右/左的图片 */
ev=ev||event;
if(disX>0){//disX>0表示向右滑
index--;//向右滑
}else if(disX<0){//disX>0表示向左滑
index++;//向左滑
}
//图片滑动距离以一个视口的宽度为单位
ulNode.style.left = -index*(document.documentElement.clientWidth)+"px";//index与图片的偏移是相反的
})
var startX = 0;
var elementX = 0;
carouselWrap.addEventListener("touchstart",function(ev){
ev=ev||event;
var TouchC = ev.changedTouches[0];
startX = TouchC.clientX;
elementX = ulNode.offsetLeft;
})
carouselWrap.addEventListener("touchmove",function(ev){
ev=ev||event;
var TouchC = ev.changedTouches[0];
var nowX = TouchC.clientX;
var disX = nowX - startX;//此时disX不用设在全局作用域
ulNode.style.left = elementX+disX+"px";
})
carouselWrap.addEventListener("touchend",function(ev){
ev=ev||event;
//index抽象了ul的实时位置
var index = ulNode.offsetLeft/document.documentElement.clientWidth;
/* 此时,滑过图片的一半才会进行切换 */
index = Math.round(index);//此时,index为小数;round()方法可把一个数字舍入为最接近的整数
// /* 向左/右滑动一点点,即可切换到右/左的图片 */
// //需要将disX定义在全局作用域
// if(disX>0){
// index = Math.ceil(index);//向上取整
// }else if(disX<0){
// index = Math.floor(index);//向下取整
// }
ulNode.style.left = index*(document.documentElement.clientWidth)+"px";//此时,不用再加负号
})
<div id="wrap">
<div class="carousel-wrap">
<!-- 下方的小圆点 -->
<div class="points-wrap"></div>
</div>
</div>
.carousel-wrap{position: relative;}/* 用于小圆点的绝对定位 */
/* 下方的小圆点 */
.carousel-wrap > .points-wrap{
position: absolute;bottom: 0;
width: 100%;text-align: center;/*居中*/
z-index: 1;/*提升层级,使小圆点显示在图片的上面*/}
.carousel-wrap > .points-wrap > span{/* 每个小圆点 */
display: inline-block;/*span默认为块级元素不能设置宽高*/
width: 10px;height: 10px;border-radius: 50%;background: green;/*小圆点的样式*/
margin-left:5px;/*小圆点之间的间隔*/}
.carousel-wrap > .points-wrap > span.active{background: deeppink;}/*选中状态的小圆点*/
<script type="text/javascript">
window.onload=function(){
document.addEventListener("touchstart",function(ev){
ev=ev||event;
ev.preventDefault();
});
var arr=["img/01.jpg","img/02.jpg","img/03.jpg","img/04.jpg","img/05.jpg"];
carousel(arr);
function carousel(arr){
//布局
var carouselWrap = document.querySelector(".carousel-wrap");
if(carouselWrap){
var ulNode = document.createElement("ul");
var styleNode = document.createElement("style");
ulNode.classList.add("list");
for(var i=0;i<arr.length;i++){
ulNode.innerHTML+='+ arr[i]+'"/>';
}
styleNode.innerHTML=".carousel-wrap > .list > li{width: "+(1/arr.length*100)+"%;}.carousel-wrap > .list{width: "+arr.length+"00%}";
carouselWrap.appendChild(ulNode);
document.head.appendChild(styleNode);
var imgNodes = document.querySelector(".carousel-wrap > .list > li > a >img");
setTimeout(function(){
carouselWrap.style.height=imgNodes.offsetHeight+"px";
},100)
/* 下方的小圆点 */
var pointsWrap = document.querySelector(".carousel-wrap > .points-wrap");//取得相应的html结构
if(pointsWrap){//有小圆点这一结构,才表明需要这一功能
for(var i=0; i<arr.length; i++){/*小圆点的html结构*/
if(i==0){/*默认第一个小圆点为选中状态*/
pointsWrap.innerHTML += '';
}else{
pointsWrap.innerHTML += '';
}
}
//querySelectorAll的坑,只有结构已经生成,才能取得相应的结构
var pointsSpan = document.querySelectorAll(".carousel-wrap > .points-wrap > span");//取得所有的小圆点
}
var startX = 0;
var elementX = 0;
carouselWrap.addEventListener("touchstart",function(ev){
ev = ev||event;
var TouchC = ev.changedTouches[0];
ulNode.style.transition = "none";//刚开始时,清除transition过渡动画
startX = TouchC.clientX;
elementX = ulNode.offsetLeft;
})
carouselWrap.addEventListener("touchmove",function(ev){
ev = ev||event;
var TouchC = ev.changedTouches[0];
var nowX = TouchC.clientX;
var disX = nowX - startX;
ulNode.style.left = elementX+disX+"px";
})
carouselWrap.addEventListener("touchend",function(ev){
ev = ev||event;
//index抽象了ul的实时位置
var index = ulNode.offsetLeft/document.documentElement.clientWidth;
index = Math.round(index);
/* 超出控制 */
if(index>0){
index = 0;
}else if(index<1-arr.length){
index = 1-arr.length;
}
//处理后的index可以代表小圆点的位置,只是符号相反
for(var i=0;i<pointsSpan.length;i++){
pointsSpan[i].classList.remove("active");//小圆点去除选中状态,以重新定义哪一个为选中状态
}
pointsSpan[-index].classList.add("active");
ulNode.style.transition = ".5s left";//css的过渡动画
ulNode.style.left = index*(document.documentElement.clientWidth)+"px";
})
}
}
}
</script>
transform造成的位移最终是不会影响offsetLeft的,因为两者不在同一图层上。因此,有offsetLeft的地方,都需要修改,之前offsetLeft都在帮我们计算实时的偏移量,现在修改之后,我们则需要自己主动进行记录和同步。
<script type="text/javascript">
window.onload=function(){
document.addEventListener("touchstart",function(ev){
ev=ev||event;
ev.preventDefault();
});
var arr=["img/01.jpg","img/02.jpg","img/03.jpg","img/04.jpg","img/05.jpg"];
carousel(arr);
function carousel(arr){
var carouselWrap = document.querySelector(".carousel-wrap");
if(carouselWrap){
var ulNode = document.createElement("ul");
var styleNode = document.createElement("style");
ulNode.classList.add("list");
for(var i=0;i<arr.length;i++){
ulNode.innerHTML+='+ arr[i]+'"/>';
}
styleNode.innerHTML=".carousel-wrap > .list > li{width: "+(1/arr.length*100)+"%;}.carousel-wrap > .list{width: "+arr.length+"00%}";
carouselWrap.appendChild(ulNode);
document.head.appendChild(styleNode);
var imgNodes = document.querySelector(".carousel-wrap > .list > li > a >img");
setTimeout(function(){
carouselWrap.style.height=imgNodes.offsetHeight+"px";
},100)
var pointsWrap = document.querySelector(".carousel-wrap > .points-wrap");
if(pointsWrap){
for(var i=0; i<arr.length; i++){
if(i==0){
pointsWrap.innerHTML += '';
}else{
pointsWrap.innerHTML += '';
}
}
var pointsSpan = document.querySelectorAll(".carousel-wrap > .points-wrap > span");//取得所有的小圆点
}
var startX = 0;
var elementX = 0;
var translateX = 0;//用来记录实时的偏移量
carouselWrap.addEventListener("touchstart",function(ev){
ev = ev||event;
var TouchC = ev.changedTouches[0];
ulNode.style.transition = "none";
startX = TouchC.clientX;
//elementX = ulNode.offsetLeft;
elementX = translateX;
})
carouselWrap.addEventListener("touchmove",function(ev){
ev = ev||event;
var TouchC = ev.changedTouches[0];
var nowX = TouchC.clientX;
var disX = nowX - startX;
//var left = elementX + disX;
translateX = elementX + disX;
//ulNode.style.left = elementX+disX+"px";
ulNode.style.transform = 'translateX('+left+')';
})
carouselWrap.addEventListener("touchend",function(ev){
ev = ev||event;
//var index = ulNode.offsetLeft/document.documentElement.clientWidth;
var index = translateX/document.documentElement.clientWidth;
index = Math.round(index);
if(index>0){
index = 0;
}else if(index<1-arr.length){
index = 1-arr.length;
}
for(var i=0;i<pointsSpan.length;i++){
pointsSpan[i].classList.remove("active");
}
pointsSpan[-index].classList.add("active");
ulNode.style.transition = ".5s transform";
//ulNode.style.left = index*(document.documentElement.clientWidth)+"px";
translateX = index*(document.documentElement.clientWidth);
ulNode.style.transition = 'translateX('+translateX+')';
})
}
}
}
</script>
可以发现,每一次改动translateX都需要进行相应的记录和同步,因此,我们需要构造一个函数来解决这个问题。
鉴于前面的问题,我们想要写一个函数来专门处理transform的读取
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
#test{
width: 100px;
height: 100px;
background: pink;
/*transform:scale(2) translateX(100px);*/
}
</style>
</head>
<body>
<div id="test"></div>
</body>
<script type="text/javascript">
//css函数对transform的值进行读,写操作
//css(node,type) 读
//css(node,type,val) 写
//规避覆盖的风险
var test = document.querySelector("#test");
css(test,"translateX",100);
css(test,"translateX",200);
css(test,"scale",2);
console.log(css(test,"translateX"));//结果为:200
/*
{
translateX:val,
translateY:val,
scale:val,
rotate:val
}
*/
function css(node,type,val){
if(typeof node === "object" && typeof node["transform"] === "undefined" ){
node["transform"] = {};//如果没有这个属性,则添加;如果有,则覆盖
//不能每次都覆盖,否则上一次的记录就没了
}
/*
if(!node["transform"]){
node["transform"] = {};
}
在这里,我们不能这么写,逻辑是相同的,但对于组件,需要较高的容错性
*/
if(arguments.length>=3){//如果参数大于等于3,则为写入操作
var text = "";
node["transform"][type] = val;//每次调用都可以将值塞入对象的属性中
//拼串时一定要从对象中读取val的值,上面一行的val只是一次操作,拼串是要取决于对象的,因此我们要循环整个对象
for(item in node["transform"]){//将属性一个一个地读出,进行字符串拼串(先写入的先读出)
//hasOwnProperty()方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性,如果为true,则为自身属性
if(node["transform"].hasOwnProperty(item)){//判断是否是对象的直接属性,过滤掉原型链中的属性
switch (item){//switch取出的是属性名
//translateX和translateY放在一起
case "translateX":
case "translateY":
text += item+"("+node["transform"][item]+"px)";
break;
case "scale":
text += item+"("+node["transform"][item]+")";
break;
case "rotate":
text += item+"("+node["transform"][item]+"deg)";
break;
}
}
}
node.style.transform = node.style.webkitTransform = text;//兼容
}else if(arguments.length==2){//如果参数等于2,则为读取操作
val = node["transform"][type];//此时第三个参数已经不需要保留,但我们可以将其废物利用,而不用再定义一个新的变量
if(typeof val === "undefined"){//设置默认值
switch (type){
case "translateX":
case "translateY":
case "rotate":
val = 0;
break;
case "scale":
val = 1;
break;
}
}
return val;
}
}
</script>
</html>
虽然我们已经写出了组件,但是我们需要将其提出,而不是直接写在网页中。
我们需要将其暴露以使用,我们将函数绑给window
/* js文件 */
+(function(w){
w.css = function(node,type,val){...}
})(window)
此时,可以直接使用:
例如,
css(test."scale",2);
但是,如果我们再次定义css函数时,新定义的函数也是绑给window的,就会出现冲突
因此,我们采取以下方法,使用命名空间来解决命名冲突:
/* js文件 */
+(function(w){
w.damu = {};
w.damu.css = function(node,type,val){...}
})(window)
damu.css(test."scale",2);
不再需要translateX,对象已经拥有其功能
var translateX =0;//不再需要
elementX = translateX;
//变为 elementX = damu.css(ulNode,"translateX");
translateX = elementX+disX;
ulNode.style.transform = 'translateX('+translateX+'px)';
//变为 damu.css(ulNode,"translateX",elementX+disX);
index = translateX/document.documentElement.clientWidth;
//变为 var index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;
translateX=index*(document.documentElement.clientWidth);
ulNode.style.transform ='translateX('+translateX+'px)';
//变为 damu.css(ulNode,"translateX",index*(document.documentElement.clientWidth));
我们我们采用再复制一组图片加在原图片的后面的方式
function carousel(arr){
var carouselWrap = document.querySelector(".carousel-wrap");
if(carouselWrap){
var pointslength = arr.length;//定义一个变量,用于保存小圆点属性,因为复制一组图片后,arr.length为10
arr = arr.concat(arr);//复制一组图片
......
if(pointsWrap){
//将原来的arr.length改为pointslength
for(var i=0;i<pointslength;i++){...}
}
......
carouselWrap.addEventListener("touchend",function(ev){
......
//pointsSpan[-index].classList.add("active");
//使小圆点的下标不会超出5
pointsSpan[-index%pointslength].classList.add("active");
})
}
}
此时,第一张向右拉 / 最后一张向左拉 会出现空白
然后我们再来做成无缝的效果(即将空白替换为相应的图片,且让图片循环)
carouselWrap.addEventListener("touchstart",function(ev){
......
/* 无缝效果 */
//点击第一组的第一张时,瞬间跳到第二组的第一张
//点击第二组的最后一张时,瞬间跳到第一组的最后一张
//获取当前的偏移量以判断当前是在哪一张图片,其正负与图片下标相反
var index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;//index代表ul的位置
if(-index === 0){//如果在第一张则跳到第二组的第一张
index = -pointslength;//第二组的第一张
}else if(-index ==(arr.length-1)){
index = -(pointslength-1)//第二组的最后一张
}
damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);//进行相应的偏移
......
}
但是有时我们是不需要无缝的,因此我们需要在有这一要求的时候才添加无缝效果。
<div class="carousel-wrap" needCarousel><!-- 在结构中添加needCarousel,如果存在则表示需要无缝效果 -->
<div class="points-wrap"></div>
</div>
function carousel(arr){
......
/* 无缝效果 */
var needCarousel = carouselWrap.getAttribute("needCarousel");
needCarousel = needCarousel == null?false:true;//判断是否有needCarousel
if(needCarousel){
arr=arr.concat(arr);
}
......
carouselWrap.addEventListener("touchstart",function(ev){
......
//点击第一组的第一张时,瞬间跳到第二组的第一张
//点击第二组的最后一张时,瞬间跳到第一组的最后一张
if(needCarousel){
//获取当前的偏移量以判断当前是在哪一张图片,其正负与图片下标相反
var index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;//index代表ul的位置
if(-index === 0){//如果在第一张则跳到第二组的第一张
index = -pointslength;//第二组的第一张
}else if(-index ==(arr.length-1)){
index = -(pointslength-1)//第二组的最后一张
}
damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);//进行相应的偏移
}
......
})
}
function carousel(arr){
......
if(carouselWrap){
carouselWrap.addEventListener("touchstart",function(ev){
......
//手动点击后,清除自动轮播
clearInterval(timer);
})
carouselWrap.addEventListener("touchend",function(ev){
......
//手动操作完成后,恢复自动轮播
auto();
}
/* 自动轮播 */
var timer = 0;
var autoFlag = 0;//抽象图片下标
auto();
function auto(){
clearInterval(timer);
timer=setInterval(function(){
if(autoFlag == arr.length-1){
ulNode.style.transition = "none";
autoFlag = arr.length/2-1;
damu.css(ulNode,"translateX",-autoFlag*document.documentElement.clientWidth);
}
setTimeout(function(){
autoFlag++;
ulNode.style.transition = "1s transform";
xiaoyuandian(-autoFlag);
damu.css(ulNode,"translateX",-autoFlag*document.documentElement.clientWidth);
},50)
},2000)
}
//小圆点
function xiaoyuandian(index){
if(!pointsWrap){
return;
}
for(var i=0;i<pointsSpan.length;i++){
pointsSpan[i].classList.remove("active");
}
pointsSpan[-index%pointslength].classList.add("active");
}
}
}
现在需要解决手动轮播后与自动轮播的同步问题。
index抽象的是ul位置,autoFlag抽象的是图片下标,
我们可以将这两个变量合为同一个,只需要加负号即可
var autoFlag = 0;//抽象图片下标
//替换后变为 var index = 0;
//将其放在前面的滑屏逻辑中定义:
/*滑屏
1.拿到元素一开始的位置
2.拿到手指一开始点击的位置
3.拿到手指move的实时距离
4.将手指移动的距离加给元素
*/
var index = 0;
var startX = 0;//手指一开始的位置
var elementX = 0;//元素一开始的位置
......
//"touchstart"中的var index不需要去掉var,因为那是用于无缝的,和自动/手动轮播的逻辑无关
//"touchend"中的var index需要去掉var,使其使用同一个index
//自动轮播逻辑中需要修改减数和被减数,以调整正负值
//加入needAuto相应的逻辑,用于判断是否需要添加自动轮播效果
<div class="carousel-wrap" needAuto><!-- 在结构中添加needAuto,如果存在则表示需要自动轮播效果 -->
<div class="points-wrap"></div>
</div>
carouselWrap.addEventListener("touchend",function(ev){
......
//手动操作完成后,恢复自动轮播
if(needAuto){
auto();
}
}
/* 自动轮播 */
var timer =0;
//判断是否需要自动轮播
var needAuto = carouselWrap.getAttribute("needAuto");
needAuto = needAuto == null?false:true;
if(needAuto){
auto();
}
function auto(){
clearInterval(timer);
timer = setInterval(function(){
if(index == 1-arr.length){
ulNode.style.transition = "none";//清除过渡效果(第二组的最后一张回到第一组的第一张)
index = 1-arr.length/2;
damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);//相应的偏移
}
/*这里的定时器用于延迟,否则上面的“清除过渡效果”不产生作用
因为JS代码执行速度快,上面的“damu.css(...);”未渲染完成,就已经执行这个定时器中的代码*/
setTimeout(function(){
index--;
ulNode.style.transition = "1s transform";//添加过渡
xiaoyuandian(index);//小圆点
damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);//相应的偏移
},50)
},2000)
}
//小圆点
function xiaoyuandian(index){
if(!pointsWrap){
return;
}
for(var i=0;i<pointsSpan.length;i++){
pointsSpan[i].classList.remove("active");
}
pointsSpan[-index%pointslength].classList.add("active");
}
现在,我们可以将逻辑代码抽出,作为一个组件
+(function(w){
w.damu = {};
w.damu.css=function (node,type,val){
if(typeof node ==="object" && typeof node["transform"] ==="undefined" ){
node["transform"]={};
}
if(arguments.length>=3){
//设置
var text ="";
node["transform"][type] = val;
for( item in node["transform"]){
if(node["transform"].hasOwnProperty(item)){
switch (item){
case "translateX":
case "translateY":
text += item+"("+node["transform"][item]+"px)";
break;
case "scale":
text += item+"("+node["transform"][item]+")";
break;
case "rotate":
text += item+"("+node["transform"][item]+"deg)";
break;
}
}
}
node.style.transform = node.style.webkitTransform = text;
}else if(arguments.length==2){
//读取
val =node["transform"][type];
if(typeof val === "undefined"){
switch (type){
case "translateX":
case "translateY":
case "rotate":
val =0;
break;
case "scale":
val =1;
break;
}
}
return val;
}
}
w.damu.carousel=function (arr){
//布局
var carouselWrap = document.querySelector(".carousel-wrap");
if(carouselWrap){
var pointslength = arr.length;
//无缝
var needCarousel = carouselWrap.getAttribute("needCarousel");
needCarousel = needCarousel == null?false:true;
if(needCarousel){
arr=arr.concat(arr);
}
var ulNode = document.createElement("ul");
var styleNode = document.createElement("style");
ulNode.classList.add("list");
for(var i=0;i<arr.length;i++){
ulNode.innerHTML+='+ arr[i]+'"/>';
}
styleNode.innerHTML=".carousel-wrap > .list > li{width: "+(1/arr.length*100)+"%;}.carousel-wrap > .list{width: "+arr.length+"00%}";
carouselWrap.appendChild(ulNode);
document.head.appendChild(styleNode);
var imgNodes = document.querySelector(".carousel-wrap > .list > li > a >img");
setTimeout(function(){
carouselWrap.style.height=imgNodes.offsetHeight+"px";
},100)
var pointsWrap = document.querySelector(".carousel-wrap > .points-wrap");
if(pointsWrap){
for(var i=0;i<pointslength;i++){
if(i==0){
pointsWrap.innerHTML+='';
}else{
pointsWrap.innerHTML+='';
}
}
var pointsSpan = document.querySelectorAll(".carousel-wrap > .points-wrap > span");
}
/*滑屏
1.拿到元素一开始的位置
2.拿到手指一开始点击的位置
3.拿到手指move的实时距离
4.将手指移动的距离加给元素
*/
var index =0;
//手指一开始的位置
var startX = 0;
//元素一开始的位置
var elementX = 0;
//var translateX =0;
carouselWrap.addEventListener("touchstart",function(ev){
ev=ev||event;
var TouchC = ev.changedTouches[0];
ulNode.style.transition="none";
//无缝
/*点击第一组的第一张时 瞬间跳到第二组的第一张
点击第二组的最后一张时 瞬间跳到第一组的最后一张*/
//index代表ul的位置
if(needCarousel){
var index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;
if(-index === 0){
index = -pointslength;
}else if(-index ==(arr.length-1)){
index = -(pointslength-1)
}
damu.css(ulNode,"translateX",index*document.documentElement.clientWidth)
}
startX=TouchC.clientX;
//elementX=ulNode.offsetLeft;
//elementX=translateX;
elementX=damu.css(ulNode,"translateX");
//清楚定时器
clearInterval(timer);
})
carouselWrap.addEventListener("touchmove",function(ev){
ev=ev||event;
var TouchC = ev.changedTouches[0];
var nowX = TouchC.clientX;
var disX = nowX - startX;
//ulNode.style.left = elementX+disX+"px";
/*translateX = elementX+disX;
ulNode.style.transform = 'translateX('+translateX+'px)';*/
damu.css(ulNode,"translateX",elementX+disX);
})
carouselWrap.addEventListener("touchend",function(ev){
ev=ev||event;
//index抽象了ul的实时位置
//var index = ulNode.offsetLeft/document.documentElement.clientWidth;
//var index = translateX/document.documentElement.clientWidth;
index = damu.css(ulNode,"translateX")/document.documentElement.clientWidth;
index = Math.round(index);
//超出控制
if(index>0){
index=0;
}else if(index<1-arr.length){
index=1-arr.length;
}
xiaoyuandian(index);
ulNode.style.transition=".5s transform";
//ulNode.style.left = index*(document.documentElement.clientWidth)+"px";
/*translateX=index*(document.documentElement.clientWidth);
ulNode.style.transform ='translateX('+translateX+'px)';*/
damu.css(ulNode,"translateX",index*(document.documentElement.clientWidth));
//开启自动轮播
if(needAuto){
auto();
}
})
//自动轮播
var timer =0;
var needAuto = carouselWrap.getAttribute("needAuto");
needAuto = needAuto == null?false:true;
if(needAuto){
auto();
}
function auto(){
clearInterval(timer);
timer=setInterval(function(){
if(index == 1-arr.length){
ulNode.style.transition="none";
index = 1-arr.length/2;
damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);
}
setTimeout(function(){
index--;
ulNode.style.transition="1s transform";
xiaoyuandian(index);
damu.css(ulNode,"translateX",index*document.documentElement.clientWidth);
},50)
},2000)
}
function xiaoyuandian(index){
if(!pointsWrap){
return;
}
for(var i=0;i<pointsSpan.length;i++){
pointsSpan[i].classList.remove("active");
}
pointsSpan[-index%pointslength].classList.add("active");
}
}
}
})(window)
###复习1
1.布局
布局包裹器
滑屏元素(动态生成)
---queryselector的坑
---有时绘制跟不上js引擎的渲染
定时器
2.基本的滑屏
拿到元素和手指一开始(点击到布局包裹器上时)的位置
拿到元素实时的位置,再去计算手指实时的偏移量,将偏移量实时的同步给滑屏元素
3.
定位版(图片的下标 ul的位置)
offsetLeft:累加的过程
2d变换版(单独的图层,影响最小)
---变量(业务逻辑变得很复杂,因为变量只在对应的作用域中有效,属性更加的友好)
---定义了css函数
节点的属性来管理变换类型 他所对应的值
2个参数
读取
3个参数
设置(单位)
循环节点的属性
4.无缝 自动滑屏
无缝:复制一组图片,当点击第一组第一张时瞬间跳到第二组的第一张
当点击第二组最后一张时瞬间跳到第一组的最后一张
自动滑屏:循环定时器
函数包裹(重启定时器)
清定时器(循环定时器的逻辑没有必要同一时刻开启多次;暂停逻辑)
自动滑屏和无缝的冲突
使用同一个index变量就可以
现在开始正式编写实战项目,项目采用less,编译为css文件的过程这里就省略。
头部产品规格
###总的设计图宽为1080
###06_音乐台项目
整个页面背景色:#eee;
头部上半部分高度:135
logo部分:
log 图片大小:240px * 88px
log 左右内边距:17px
上内边距:26px
下内边距:21px
菜单按钮:
菜单元素 129 * 135
菜单按钮 雪碧图大小:82 * 233
背景图偏移位置(关闭): center 16
背景图偏移位置(开启): center -120
按钮容器:
上内边距 21
登录/注册按钮:(注意内联元素,需要浮动)
按钮大小: 111 * 78
行高:78
背景色 : #690
字体颜色: #ccc
右外边距: 15px
字体大小: 42
文本居中
圆角:8
小搜索按钮:
按钮大小: 130 * 88
行高:88
字体颜色: #fff
右外边距: 30px
上外边距: 3px
字体加粗
圆角:10
------------------------------------------------
搜索区:
高 :103;
上下左右内边距:16;
输入框:(注意boxsizing!!!)
宽(总): 829
高(总): 103
背景色: #999;
上下内边距: 5
左右内边距: 10
边框: 1px solid #5a5a5a;(input输入框我们一般都会加1px边框)
字体大小 : 41
字体颜色: #333
圆角:15
大搜索按钮
宽: 203
高: 103
边框:清除边框
背景颜色: #414040;
字体颜色: #fff;
字体大小 : 41
圆角: 15;
-------------------------------------------------
定位层:
宽度 :100%
绝对定位top : 135
上下内边距 : 10
上边框: 1px solid #6a6a6a
背景颜色:rgba(0, 0, 0, .8)
定位层元素:
宽度 : 22.5%
高度:135
行高:135
字体大小:54
文本居中
/* tai.less */
*{
margin: 0;
padding: 0;
}
html,body{height: 100%;overflow: hidden;}
@rem: 1080/16rem;// 1rem值为多少位图像素
#wrap{
height: 100%;
overflow: hidden;//禁止系统默认滚动条
.head{
position: absolute;//模拟固定定位
width: 100%;
height: 100px;
background: pink;
.logo{
img{
width: 240/@rem;
}
}
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0" />
<title></title>
<!-- 引用less编译后的css文件 -->
<link rel="stylesheet" href="css/tai.css" />
</head>
<body>
<div id="wrap">
<div class="head">
<div class="head-top">
<h1 class="logo">
<a href="http://www.atguigu.com">
<img src="img/logo.png" />
</a>
</h1>
</div>
</div>
</div>
</body>
<script type="text/javascript">
window.onload=function(){
/* 禁止系统默认行为 */
document.addEventListener("touchstart",function(ev){
ev=ev||event;
ev.preventDefault();
})
/* rem适配 */
;(function(){
var styleNode = document.createElement("style");
var w = document.documentElement.clientWidth/16;
styleNode.innerHTML = "html{font-size"+w+"px!important}";
document.head.appendChild(styleNode);
})()
}
</script>
</html>
在移动端,能给高度就尽量给高度,这样可以避免字体过大的问题;此外,可以让整体布局确定下来,如果容器是靠内容撑开的,假如内容发生变化,则容器高度会发生变化,可能对布局产生影响。
//css reset
html,body,ul,li,h1,h2,h3,h4,span,div,p,a,form,input{margin: 0;padding: 0;font-family: helvetica;}
html,body{height: 100%;overflow: hidden;}
ul{list-style: none;}
a{text-decoration: none;display: block}
a,input,button{-webkit-tap-highlight-color: rgba(0,0,0,0);-webkit-appearance: none;outline: none;border: none;}
img{display: block}
//1rem值伪多少位图像素
@rem:1080/16rem;
@import "mixin/1-px";
#wrap{
font-size: 16/@rem;//进行重置,排除.btns中font-size的影响
height: 100%;
overflow: hidden;//隐藏滚动条
background: #EEEEEE;//整体的背景色
.head{
position: absolute;
width: 100%;
height: 100px;
background: #232323;//头部的背景色
height: 270/@rem;//将头部布局高度定死
.head-top{
height: 135/@rem;
.logo{//logo
float: left;
padding: 26/@rem 17/@rem 21/@rem 17/@rem;
img{
width:240/@rem;
}
}
.menuBtn{//面包屑导航(菜单按钮)
float: left;
width: 129/@rem;
height: 135/@rem;
background: url(../img/menuBtn.png) no-repeat;
background-size: 82/@rem 233/@rem;//指定背景图大小,否则按原图大小
background-position: center 16/@rem;
&.active{//点开后的关闭按钮图形,"&"表示当前元素
background-position: center -120/@rem;
}
}
.btns{//按钮排
padding-top: 21/@rem ;
float: right;
a{
float: left;
width: 111/@rem;
height: 78/@rem;
line-height: 78/@rem;
background: #690;
color: #ccc;
margin-right: 15/@rem;
font-size: 42/@rem;//需要在wrap中重置
text-align: center;
border-radius: 8/@rem ;
&.search{//既是a标签,也是search,这里的样式会覆盖上面a标签中的样式
width: 130/@rem;
height: 88/@rem;
line-height: 88/@rem;
color: #fff;
margin-right: 30/@rem;
margin-top: 3/@rem;
font-weight: bold;
border-radius: 10/@rem;
}
}
}
}
.head-bottom{//搜索栏
height: 103/@rem;
padding: 16/@rem;
form{
height: 100%;
input[type='text']{
float: left;//将两个input同时浮动,可以进行对齐
box-sizing: border-box;
height: 103/@rem;
width: 829/@rem;
background: #999999;
padding: 5/@rem 10/@rem;
border: 1px solid #5a5a5a;
font-size: 41/@rem;
color: #333333;
border-radius: 15/@rem 0 0 15/@rem;
&::-webkit-input-placeholder{//处理提示的文字
color: #333333;
}
&:focus{//获取焦点时,改变背景色
background: white;
}
}
input[type='submit']{
float: right;
width: 203/@rem;
height: 103/@rem;
background: #414040;
color: #fff;
font-size: 41/@rem;
border-radius:0 15/@rem 15/@rem 0 ;
}
}
}
<body>
<div id="wrap">
<div class="head">
<div class="head-top">
<!--logo-->
<h1 class="logo">
<a href="http://www.atguigu.com">
<img src="img/logo.png" />
</a>
</h1>
<!--面包屑导航-->
<a href="javascript:;" class="menuBtn"></a>
<!--按钮排-->
<div class="btns">
<a href="javascript:;" class="search">搜索</a>
<a href="javascript:;">登录</a>
<a href="javascript:;">注册</a>
</div>
</div>
<div class="head-bottom">
<form method="post">
<input type="text" placeholder="请碰我一下" />
<input type="submit" value="搜索"/>
</form>
</div>
</div>
</div>
</body>
// 1物理像素
// 1-px.less
.1-px(@color){
position: relative;
&:before{
position: absolute;
content: "";
display: block;
top: 0;
width: 100%;
height: 1px;
background: @color;
@media (-webkit-device-pixel-ratio:2 ){
transform: scaleY(.5);
};//写两个是为了兼容
@media (-webkit-device-pixel-ratio:3 ){
transform: scaleY(.333333333333);
}
}
}
...
@import "mixin/1-px";//引入1物理像素相关的混合,mixin是只是路径
#wrap{
...
.head{
...
.mask{
.1-px(deeppink);
position: absolute;
left: 0;
top: 135/@rem;
width: 100%;
padding: 10/@rem 0;
background: rgba(0, 0, 0, .8);
display: none;//默认不显示
& > li{
width: 22.5%;
height: 135/@rem;
font-size: 54/@rem;
line-height: 135/@rem;
text-align: center;
float: left;
a{//每个按钮
color: white;
}
}
}
}
}
<body>
<div id="wrap">
<div class="head">
...
<ul class="mask">
<li>
<a href="javascript">首页</a>
</li>
<li>
<a href="javascript">MV</a>
</li>
<li>
<a href="javascript">悦单</a>
</li>
<li>
<a href="javascript">V榜</a>
</li>
<li>
<a href="javascript">音乐</a>
</li>
<li>
<a href="javascript">商城</a>
</li>
<li>
<a href="javascript">节目</a>
</li>
<li>
<a href="javascript">饭团</a>
</li>
<li>
<a href="javascript">咨询</a>
</li>
<li>
<a href="javascript">我的家</a>
</li>
<li>
<a href="javascript">APP下载</a>
</li>
<li>
<a href="javascript">热门应用</a>
</li>
</ul>
</div>
</div>
</body>
/* tools.js */
//操作active,classlist兼容性不好,因此自定义一个组件
(function(w){
w.tools = {};
tools.addClass=function (node,className){
var reg = new RegExp("\\b"+className+"\\b");
if(!reg.test(node.className)){
node.className += (" "+className);
}
}
tools.removeClass=function (node,className){
if(node.className){
var reg = new RegExp("\\b"+className+"\\b");
var classes = node.className;
node.className = classes.replace(reg,"");
if(/^\s*$/g.test(node.className)){
node.removeAttribute("class");
}
}else{
node.removeAttribute("class");
}
}
})(window)
<script src="js/tools.js"></script>
<script type="text/javascript">
window.onload=function(){
document.addEventListener("touchstart",function(ev){
ev=ev||event;
ev.preventDefault();
})
;(function(){
var styleNode = document.createElement("style");
var w = document.documentElement.clientWidth/16;
styleNode.innerHTML="html{font-size:"+w+"px!important}";
document.head.appendChild(styleNode);
})()
/* 搜索框的聚焦 */
/* 因为阻止了默认行为,因此需要我们自己手动实现聚焦 */
changeFocus()
function changeFocus(){
var inputText = document.querySelector("#wrap .head .head-bottom form input[type='text']");
inputText.addEventListener("touchstart",function(ev){//聚焦
ev = ev||event;
this.focus();
ev.stopPropagation();//阻止冒泡
ev.preventDefault();//每次阻止冒泡后都需要再次禁止默认事件
})
document.addEventListener("touchstart",function(){//失焦
inputText.blur();
})
}
/* 面包屑导航的展开与关闭 */
CMCFMenuBtn();
function CMCFMenuBtn(){
var menuBtn = document.querySelector("#wrap .head .head-top .menuBtn");
var mask = document.querySelector("#wrap .head .mask");
//isXX:false 频道按钮
//isXX:ture XX按钮
var isXX = false;//默认状态为关闭
menuBtn.addEventListener("touchstart",function(ev){
ev = ev||event;
var touchC = ev.changedTouches[0];
if(!isXX){/* 展开 */
tools.addClass(menuBtn,"active");
mask.style.display = "block";
}else{/* 隐藏 */
tools.removeClass(menuBtn,"active");
mask.style.display = "none";
}
isXX = !isXX;
/* menuBtn.addEventListener("touchstart" 和 document.addEventListener("touchstart"
因为事件冒泡,会造成冲突 */
ev.stopPropagation();//阻止冒泡
ev.preventDefault();//每次阻止冒泡后都需要再次禁止默认事件
})
/* 点击其他部分时,关闭展开 */
document.addEventListener("touchstart",function(){
if(isXX){
tools.removeClass(menuBtn,"active");
mask.style.display = "none";
isXX = !isXX;
}
})
/* 点击遮罩的非跳转部位时,遮罩不应该消失 */
mask.addEventListener("touchstart",function(ev){
ev = ev||event;
ev.stopPropagation();//阻止冒泡
ev.preventDefault();//每次阻止冒泡后都需要再次禁止默认事件
})
}
}
</script>
可拖拽导航产品规格
###总的设计图宽为1080
###06_音乐台项目
整个内容区: 270px 的头部空隙
导航: 高度+纵向padding+border 177(box-sizing)
border: 1
padding:上 31
下 14
导航元素: 高:129
左右内边距:38
默认字体颜色: #020202;
选中时背景颜色: #690;
选中时字体颜色: #fff;
这里需要修改1-px.less,添加位置参数,修改之后,之前的部分也需要相应的调整,这里就不再指出了。
/* 修改 1-px.less */
.1-px(top,@color:black){
position: relative;
&:before{
position: absolute;
content: "";
display: block;
top: 0;
width: 100%;
height: 1px;
background: @color;
@media (-webkit-device-pixel-ratio:2 ){
transform: scaleY(.5);
};
@media (-webkit-device-pixel-ratio:3 ){
transform: scaleY(.333333333333);
}
}
}
.1-px(bottom,@color:black){
position: relative;
&:before{
position: absolute;
content: "";
display: block;
bottom: 0;
width: 100%;
height: 1px;
background: @color;
@media (-webkit-device-pixel-ratio:2 ){
transform: scaleY(.5);
};
@media (-webkit-device-pixel-ratio:3 ){
transform: scaleY(.333333333333);
}
}
}
/* tai.less */
#wrap{
position: relative;
...
.content{
background: pink;
//---内容占满除头部外的区域
position: absolute;
top: 270/@rem;
bottom: 0;
left: 0;
right: 0;
//--------
.nav{
.1-px(bottom);//1像素的bottom边框
width: 100%;//与布局视口一样宽
height: 177/@rem;
box-sizing: border-box;
background: #EEEEEE;
padding: 31/@rem 0 14/@rem 0;
.list{
//需要让li都在同一行
//这里,每个li的宽度不同,因此无法使用轮播图的放大百分比宽度
//也不能使用浮动,浮动时宽度不够会自动换行
//这里使用父容器为white-space: nowrap;子元素为display: inline-block;
font-size: 0;//display: inline-block;后元素间会有空隙,清除空隙
white-space: nowrap;//不换行
//ul需要被撑开宽度,因为滑动处理时需要控制范围
float: left;//这个浮动对自身没有影响,但使ul可以被li撑开宽度
& > li{
height: 129/@rem;
line-height: 129/@rem;//居中
padding: 0 38/@rem;
font-size: 1rem;
display: inline-block;
a{
color: #020202;
}
&.active{//被选中状态
background: #690;
a{
color: #fff;
}
}
}
}
}
}
}
/* html */
<body>
<div id="wrap">
...
<div class="content">
<div class="nav"><!-- 滑屏区域 -->
<ul class="list">
<li class="active">
<a href="javascript:;">首页</a>
</li>
<li>
<a href="javascript:;">MV</a>
</li>
<li>
<a href="javascript:;">悦单</a>
</li>
<li>
<a href="javascript:;">V榜</a>
</li>
<li>
<a href="javascript:;">音乐</a>
</li>
<li>
<a href="javascript:;">商城</a>
</li>
<li>
<a href="javascript:;">节目</a>
</li>
<li>
<a href="javascript:;">饭团</a>
</li>
<li>
<a href="javascript:;">咨询</a>
</li>
<li>
<a href="javascript:;">我的家</a>
</li>
<li>
<a href="javascript:;">APP下载</a>
</li>
<li>
<a href="javascript:;">热门应用</a>
</li>
<li>
<a href="javascript:;">晓飞张</a>
</li>
<li>
<a href="javascript:;">金龙油</a>
</li>
<li>
<a href="javascript:;">邱海峰</a>
</li>
<li>
<a href="javascript:;">小贱贱</a>
</li>
<li>
<a href="javascript:;">你</a>
</li>
</ul>
</div>
</div>
</div>
</body>
<script src="js/damu.js"></script><!-- 引入damu.js -->
/* 滑屏逻辑js */
drag();
function drag(){
var wrap = document.querySelector("#wrap .content .nav");//滑屏区域
var item = document.querySelector("#wrap .content .nav .list");//滑屏元素
var startX=0;//元素一开始的位置
var elementX =0;//手指一开始的位置
wrap.addEventListener("touchstart",function(ev){
ev = ev||event;
var touchC = ev.changedTouches[0];
startX = touchC.clientX;
elementX = damu.css(item,"translateX");
})
wrap.addEventListener("touchmove",function(ev){
ev = ev||event;
var touchC = ev.changedTouches[0];
var nowX = touchC.clientX;//手指的当前位置
var disX = nowX - startX;//手指移动的距离
damu.css(item,"translateX",elementX+disX);
})
}
drag();
function drag(){
...
var minX = wrap.clientWidth - item.offsetWidth;//向右拉时产生的空隙距离
wrap.addEventListener("touchstart",function(ev){
...
item.style.transition="none";//正常滑动时,清除"touchend"中的过渡效果
})
wrap.addEventListener("touchmove",function(ev){
ev = ev||event;
var touchC = ev.changedTouches[0];
var nowX = touchC.clientX;//手指的当前位置
var disX = nowX - startX;//手指移动的距离
var translateX = elementX + disX;//手指一开始的位置 + 手指移动的距离
/*橡皮筋效果
在move的过程中,每一次touchmove真正的有效距离慢慢变小,元素的滑动距离还是在变大
*/
if(translateX > 0){//向右拉
//var scale = 1-translateX/document.documentElement.clientWidth;//这样写比例最终会变为负值
//scale范围为(0,1)
//分母可以乘以一个数,此时分母越大,越难拉;例如分母*2,则scale范围为(0,.5)
var scale = document.documentElement.clientWidth/((document.documentElement.clientWidth+translateX)*1.5);
translateX = elementX + disX*scale;//一开始的位置 + 手指移动的距离*不断变小的比例
//translateX=0;
}else if(translateX < minX){//向左拉
var over = minX - translateX;//不断向左拉动后,右边所产生的空隙距离
var scale = document.documentElement.clientWidth/((document.documentElement.clientWidth+over)*1.5);
translateX = elementX + disX*scale;
//translateX = minX;
}
//因为进入判断才会产生橡皮筋效果,因此其中的变量不能提取出来放到外面
//translateX = elementX + disX*scale;
damu.css(item,"translateX",translateX);
})
/* 橡皮筋的反弹效果 */
wrap.addEventListener("touchend",function(ev){
var translateX = damu.css(item,"translateX");
item.style.transition = "1s transform";//添加过渡效果
if(translateX > 0){
translateX = 0;
damu.css(item,"translateX",translateX);
}else if(translateX < minX){
translateX = minX;
damu.css(item,"translateX",translateX);
}
})
}
###复习2
1.头部布局 效果
---怎么使用less来弥补rem适配缺点
定义了一个变量@rem(代表1rem包含多少位图像素)
---表单
表单高亮 outline:none
表单内阴影 border:none
---1物理像素的实现
less 混合版
---移动端骨架搭建
meta标签
挑选一个适配方案(百分比 rem适配 viewport适配)
布局形式(流体+固定 275px )
全面禁止事件默认行为的
---js
每次冒泡的时候,记住阻止事件的默认行为
2.导航的布局 橡皮筋效果
---导航 滑屏区域 与 滑屏元素的布局
滑屏区域宽度必定占满一个视口
滑屏区域宽度百分百
滑屏元素必须被子项撑开
滑屏元素必须浮动(为了能被子项撑开 禁止子项换行)
子项统一inline-block
---无缝滑屏 滑屏区域 与 滑屏元素的布局
滑屏区域宽度必定占满一个视口
滑屏区域宽度百分百
滑屏元素必须被子项撑开
width:子项个数*100%
子项:1/子项个数 * 100%
###橡皮筋效果
减少每次move的有效距离,最终的移动距离还是一直在增大
move:每次手指移动的距离
###混合 继承
.mixin(){
规则集
}
#test{
.mixin()
//规则集
}
#test2{
.mixin()
//规则集
}
#test3{
.mixin()
//规则集
}
.extend{
规则集
}
#test{
&::extend(.extend)
}
#test1{
&::extend(.extend)
}
#test2{
&::extend(.extend)
}
#test,#test1,#test2{
规则集
}