1. 前端指导思想:
内容(HTML)、样式(CSS)与行为(JS)分离
- 如果用HTML写样式,会让内容很冗长复杂,会有很多多余的标签,很难区分逻辑结构。
- 如果用CSS表示内容,一是用户无法选中该内容,二是JS无法取不到这个内容。
- 如果用JS控制内容,比如假设
CSS div{display: none},$div.hide() // display: none,这个是没有争议的,但如果是$div.show() // display: block or inline-felx,这种不确定性会影响页面布局。
我们应该只用JS加class,具体的样式CSS自己搞定。 - 在实际应用中会迫不得已地违反此标准,但如果经常违反,那你就没有遵循这个标准,你写的代码将会混乱不堪。
2. 轮播
记录我写一个简单的轮播效果的过程。
实际操作步骤:
一:让图片横起来,且只显示一个。
- 找三个图片放上去,设置宽300PX,前端是不会让图片变形的,所以要不找三个大小一样的,要不就自己P图。我是找了三个300*200的。
- 用一个窗口包裹imgs。
- 让三个图片横起来:
display: felx;,但是flex默认会尽量让所有东西放在一行里。 - 所以再加一句
align-items: flex-start;这样就可以了。具体原理自己理解,或者可以强行记忆。 - 给window和imgs加边框,因为屏幕不够宽,所有没有包裹住所有图片。最右边的图片会超过边际。
- 这可以写一个
overflow: hidden;遮挡住超出边际的部分,本次不需要这样。 - 给window加一个宽度
width: 300px; overflow: hidden;这样一次就只显示一个图片。
二:实现轮播
- 加三个按钮,点击不同的按钮出现不同的图片。
- 在js里用jQuery给三个按钮分别添加onclick函数,点击就改版translateX的值。
- 加个过渡:因为动的是images,所以在miges里加上
transition: transform 0.5s;
代码如下:
html:
<!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
<style>
.images{
display: flex;
align-items: flex-start;
border: 5px solid red;
transition: transform 0.5s;
}
.iamges > img{
vertical-align: top;
}
.window{
border: 10px solid black;
width: 300px;
overflow: hidden;
}
</style>
</head>
<body>
<div class="window">
<div class="images" id=images>
<img src="https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=4137085231,3132721994&fm=15&gp=0.jpg" width=300 height=200 alt="">
<img src="https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1192434636,812615715&fm=15&gp=0.jpg" width=300 height=200 alt="">
<img src="https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1683434367,3791017001&fm=15&gp=0.jpg" width=300 height=200 alt="">
</div>
</div>
<button id="p1">第1张</button>
<button id="p2">第2张</button>
<button id="p3">第3张</button>
</body>
</html>
JS:
$(p1).on('click',function(){
$(images).css({
transform: 'translateX(0)'
})
})
$(p2).on('click',function(){
$(images).css({
transform: 'translateX(-300px)'
})
})
$(p3).on('click',function(){
$(images).css({
transform: 'translateX(-600px)'
})
})
- 为什么布局用flex,而不用float?
因为用flex写的代码少(2句),float代码多(4句)。 - 为什么用
$(images).css,而不是xxx.style?
因为jQuery就是这样设计的。.css去改版style,这是个设计问题,现在没法改了,只能用这。
3. 为什么要用$(p1).on('click',function(){...})这样的写法,而不是用xxx.onclick?
因为jQuery推荐这样的写法,也好记。第一个参数是什么事件,第二个参数是事件触发要执行什么函数。
$(p1).on('click',function(){}) === $(p1).onclick(function(){}),后者是简便写法。
- 知识点:
.on:先把一个元素封装一下得到一个新的对象,这个对象提供了.on的API,它接受两个参数,第一个是事件名,第二个是时间触发时要执行的函数。这个函数也是有一个参数的,这个参数记录了事件的所有信息。
- 不是说了要遵守规则吗,怎么还在img上面写了宽度?
因为img是可替换元素,页面没有打开的时候是不知道图片的大小的,浏览器先用一个小的图片占位,等到下载图片的时候要给图片让位置,很浪费性能,所以如果我们已经知道了图片的宽高,我们最好是直接写上去,这样浏览器就少一次让后面图片让位的步骤。 - 不是说了要遵守规则吗,怎么还用JS控制CSS呢?
如果分开写,要写很多代码,每一张图片都要在CSS里写个样式,JS要添加class并删除别的图片添加的class,这次只有三个,如过有100张呢?所以迫不得已,只能打破这个原则了。
这是一个新手应该想到的轮播,但是有很多不足的地方。
- 仔细观看图片切换,能看出来切换的过程中图片会轻微的蹦一下!这是CSS的问题
- 排查问题,通过各种删除,比如先删除图片,把button改成span等来找出问题的地方。我们发现,是images的问题。我们只改变了images的transform,然后给images设置宽高还是出问题,这更加确定是transform的问题,所以我们就不用它了,改用margin-left。
- 再排查,发现是因为页面放大110%的问题,改回100%就可以了,emmm,CSS就是这么蛋疼。
优化JS
JS部分发现代码都比较相似,所以有优化的可能。
- 用span包裹三个button,用for循环监听用户点击的是哪个按钮
- 使用
$().index()找到用户点击的图片是第几个。 - 根据用户点击的按钮添加CSS
var allButtons = $('#buttons > button')
for(let i=0; i<allButtons.length; i++){
$(allButtons[i]).on('click',function(x){
var index = $(x.currentTarget).index()
var p = index * -300
$('#images').css({
transform: 'translate(' + p + 'px)'
})
})
}
自动轮播
如果让三张图片自动轮播呢?我们只需要循环点击三个按钮即可。
- 设置一个n,随时间增加而增加,如果是三张图,
n%3得到的就是0 1 2 0 1 2 ... - 获取到一个元素的第
n%3个儿子:使用.eq()。
知识点:$(a).eq(b)会找到找出对应的dom并封装成一个jq对象。- dom :a[b].xxx
- .eq : a.eq(b).xxx
- 点击
知识点:可以直接用$(a).eq(b).click,也可以用$(a).eq(b).trigger('click'),推荐使用trigger,因为它功能更强大,可以接任何事件的名字。 - 使用setInterval()控制循环间隔。
代码如下:
var n = 0;
setInterval( ()=> {
n += 1
allButtons.eq(n%3).trigger('click')
},1000)
优化
- 有几张图片是不固定的,不能写死,所以用一个变量代替。
var size = allButtons.length - 播到哪张图片,就让那个图片的按钮变红。
css:
.red{
color: red;
}
JS:
var n = 0;
var size = allButtons.length;
setInterval( ()=> {
n += 1
allButtons.eq(n%size).trigger('click')
.addClass('red')
.siblings('.red').removeClass('red')
},1000)
- 鼠标悬停到图片上停止轮播,离开继续轮播
注意,监听的是window,而不是images
JS:
$('.window').on('mouseenter', function(){
window.clearInterval(timeId)
})
$('.window').on('mouseleave', function(){
timeId = setInterval( ()=> {
n += 1
allButtons.eq(n%size).trigger('click')
.addClass('red')
.siblings('.red').removeClass('red')
},1000)
})
- 发现一个小bug:我想点按钮,从我点的按钮处继续轮播
原本轮播就是按照n的值一直轮播,跟我点的index没有关系,那我让n=index,这样就可以了。
...
for(let i=0; i<allButtons.length; i++){
$(allButtons[i]).on('click',function(x){
var index = $(x.currentTarget).index()
var p = index * -300
$('#images').css({
transform: 'translate(' + p + 'px)'
})
// 新加代码 ↓
n = index
allButtons.eq(n)
.addClass('red')
.siblings('.red').removeClass('red')
})
}
...
- 重复的代码很多,优化一下
var allButtons = $('#buttons > button')
for(let i=0; i<allButtons.length; i++){
$(allButtons[i]).on('click',function(x){
var index = $(x.currentTarget).index()
var p = index * -300
$('#images').css({
transform: 'translate(' + p + 'px)'
})
n = index
avtiveButton(allButtons.eq(n))
})
}
var n = 0;
var size = allButtons.length;
playSlide(n%size)
var timeId = setTimer()
$('.window').on('mouseenter', function(){
window.clearInterval(timeId)
})
$('.window').on('mouseleave', function(){
timeId = setTimer()
})
function avtiveButton($button){
$button
.addClass('red')
.siblings('.red').removeClass('red')
}
function playSlide(index){
allButtons.eq(index).trigger('click')
}
function setTimer(){
return setInterval( ()=> {
n += 1
playSlide(n%size)
},3000)
}