移动设备与PC设备最大的差别在于屏幕,这主要体如今屏幕尺寸和屏幕分辨率两个方面。javascript
一般咱们所指的屏幕尺寸,实际上指的是屏幕对角线的长度(通常用英寸来度量)。css
而分辨率则通常用像素来度量 px
,表示屏幕水平和垂直方向的像素数,例如 1920*1080 指的是屏幕垂直方向和水平方向分别有1920和1080个像素点而构成。html
在Web开发中可使用px
(像素)、em
、pt
(点)、in
(英寸)、cm
(厘米)作为长度单位,咱们最经常使用px
(像素)作为长度单位。前端
咱们能够将上述的几种长度单位划分红相对长度单位和绝对长度单位。java
例如:iPhone3G/S和iPhone4/S的屏幕尺寸都为 3.5 英寸(in)可是屏幕分辨率却分别为 480x320px、960x480px,由此咱们能够得出英寸是一个绝对长度单位,而像素是一个相对长度单位(像素并无固定的长度)。git
DPI(Dots Per Inch)是印刷行业中用来表示打印机每英寸能够喷的墨汁点数,计算机显示设备从打印机中借鉴了DPI的概念,因为计算机显示设备中的最小单位不是墨汁点而是像素,因此用PPI(Pixels Per Inch)值来表示屏幕每英寸的像素数量,咱们将PPI、DPI都称为像素密度,但PPI应用更普遍,DPI在Android设备比较常见。github
利用屏幕分辨率计算 PPI :web
随着技术发展,设备不断更新,出现了不一样PPI的屏幕共存的状态(如iPhone3G/S为163PPI,iPhone4/S为326PPI),像素再也不是统一的度量单位,这会形成一样尺寸的图像在不一样PPI设备上的显示大小不同。数组
以下图,假设你设计了一个163x163的蓝色方块,在PPI为163的屏幕上,那这个方块看起来正好就是1x1寸大小,在PPI为326的屏幕上,这个方块看起来就只有0.5x0.5寸大小了。浏览器
可是作为用户是不会关心这些细节的,他们只是但愿在不一样PPI的设备上看到的图像内容差很少大小,因此这时咱们须要一个新的单位,这个新的单位可以保证图像内容在不一样的PPI设备看上去大小应该差很少,这就是独立像素,在IOS设备上叫PT(Point),Android设备上叫DIP(Device independent Pixel)或DP。
举例说明就是iPhone 3G(PPI为163)1pt = 1px,iPhone 4(PPI为326)1pt = 2px。
经过上面例子咱们不难发现 pt 同px是有一个对应(比例)关系的,这个对应(比例)关系是操做系统肯定并处理,目的是确保不一样PPI屏幕所能显示的图像大小是一致的,经过 window.devicePixelRatio
能够得到该比例值。
因此,咱们如何处理在不一样 pt/px 比例上使得显示相同大小的图片呢?
很简单,在美工设计图片的时候,多设计几种尺寸的图片。
物理像素指的是屏幕渲染图像的最小单位,属于屏幕的物理属性,不可人为进行改变,其值大小决定了屏幕渲染图像的品质,咱们以上所讨论的都指的是物理像素。
获取屏幕的物理像素尺寸:
window.screen.width;
window.screen.height;
CSS像素,与设备无关像素,指的是经过CSS进行网页布局时用到的单位,其默认值(PC端)是和物理像素保持一致的(1个单位的CSS像素等于1个单位的物理像素),可是咱们可通缩放来改变CSS像素的大小。
咱们须要理解的是物理像素和CSS像素的一个关系,1个物理像素并不老是等于一个CSS像素,经过缩放,一个CSS像素可能大于1个物理像素,也可能小于1个物理像素。
现代主流浏览器均支持移动开发模拟调试,一般按F12能够调起,其使用也比较简单,能够帮咱们方便快捷定位问题。
模拟调试能够知足大部分的开发调试任务,可是因为移动设备种类繁多,环境也十分复杂,模拟调试容易出现差错,因此真机调试变的很是必要。
有两种方法能够实现真机调试:
一、将作好的网页上传至服务器或者本地搭建服务器,而后移动设备经过网络来访问。(重点)
二、借助第三方的调试工具,如weinre、debuggap、ghostlab(推荐) 等。
真机调试必须保证移动设备同服务器间的网络是相通的。
视口(viewport)是用来约束网站中最顶级块元素<html>的,即它决定了<html>的大小。
在PC设备上viewport的大小取决于浏览器窗口的大小,以CSS像素作为度量单位。
经过以往CSS的知识,咱们都能理解<html>的大小是会影响到咱们的网页布局的,而viewport又决定了<html>的大小,因此viewport间接的决定并影响了咱们网页的布局。
/* 获取viewport的大小 */ document.documentElement.clientWidth; document.documentElement.clientHeight;
在PC端,咱们经过调整浏览器窗口能够改变 viewport 的大小,为了保证网页布局不发生错乱,须要给元素设定较大固定宽度。
移动设备屏幕广泛都是比较小的,可是大部分的网站又都是为PC设备来设计的,要想让移动设备也能够正常显示网页,移动设备不得不作一些处理,经过上面的例子咱们能够知道只要viewport足够大,就能保证本来为PC设备设计的网页也能在移动设备上正常显示,移动设备厂商也的确是这样来处理的。
在移动设备上viewport再也不受限于浏览器的窗口,而是容许开发人员自由设置viewport的大小,一般浏览 器会设置一个默认大小的 viewport,为了可以正常显示那些专为PC设计的网页,通常这个值的大小会大于屏幕的尺寸。
以下图为常见默认viewport大小(仅供参考):
从图中统计咱们得知不一样的移动厂商分别设置了一个默认的viewport的值,这个值保证大部分网页能够正常在移动设备下浏览。
可是因为咱们手机的屏幕很小,而 viewport 的值却很大,因此页面全部的内容就会缩小以适应屏幕,因此用手机看起来,这些字体和图片就会特别小,这就像手机设置里面有个电脑版显示同样。
要解释上面的缘由,须要进一步对移动设备的 viewport 进行分析,移动设备上有2个viewport(为了方便讲解人为定义的),分别是 layout viewport
和 ideal viewport
。
一、layout viewport
(布局视口)指的是咱们能够进行网页布局区域的大小,一样是以CSS像素作为计量单位,能够经过下面方式获取
/* 获取layout viewport */ document.documentElement.clientWidth; document.documentElement.clientHeight;
经过前面介绍咱们知道,若是要保证为PC设计的网页在移动设备上布局不发生错乱,移动设备会默认设置一个较大的viewport(如IOS为980px),这个viewport实际指的是layout viewport。
二、ideal viewport
(理想视口)设备屏幕区域,(以设备独立像素PT、DP作为单位)以CSS像素作为计量单位,其大小是不可能被改变,经过下面方式能够获取。
/* 获取ideal viewport有两种情形 */ /* 新设备 */ window.screen.width; window.screen.height; /* 老设备 */ window.screen.width / window.devicePixelRatio; window.screen.height / window.devicePixelRatio;
理解两个viewport后咱们来解释为何网页会被缩放或出现水平滚动条:
其缘由在于移动设备浏览器会默认设置一个layout viewport,而且这个值会大于ideal viewport,那么咱们也知道ideal viewport就是屏幕区域,layout viewport是咱们布局网页的区域,那么最终layout viewport是要显示在ideal viewport里的,而layout viewport大于ideal viewport时,因而就出现滚动条了,那么为何有的移动设备网页内容被缩放了呢?移动设备厂商认为将网页完整显示给用户才最合理,而不应出现滚动条,因此就将layout viewport进行了缩放,使其刚好完整显示在ideal viewport(屏幕)里,其缩放比例为ideal viewport / layout viewport。
移动端开发主要是针对IOS和Android两个操做系统平台的,除此以外还有Windows Phone。
移动端主要能够分红三大类,系统自带浏览器、应用内置浏览器、第三方浏览器。
指跟随移动设备操做系统一块儿安装的浏览器,通常不能卸载。好比 iPhone 的 safari 浏览器。
一般在移动设备上都会安装一些APP例如 QQ、微信、微博、淘宝等,这些APP里每每会内置一个浏览器,咱们称这个浏览器为应用内置浏览器(也叫WebView),这个内置的浏览器通常功能比较简单,而且客户端开发人员能够更改这个浏览器的某些设置。
指安装在手机的浏览器如FireFox、Chrome、360等等。
在IOS 和 Android 操做系统上自带浏览器、应用内置浏览器都是基于Webkit内核的。
通过分析咱们获得,移动页面最理想的状态是,避免滚动条且不被默认缩放处理,咱们能够经过设置 <meta name="viewport" content="">
来进行控制,并改变浏览器默认的layout viewport的宽度。
viewport 是由苹果公司为了解决移动设备浏览器渲染页面而提出的解决方案,后来被其它移动设备厂商采纳,其使用参数以下:
经过设置属性 content=""
实现,中间以逗号分隔。
示例:
<meta name="viewport" content="width=device-width, initital-scale=1.0, user-scalable=no">
width
:设置 layout viewport 宽度,其取值可为数值或者device-width。
height
:设置layout viewport 高度,其取值可为数值或者device-height
initital-scale
:设置页面的初始缩放值,为一个数字,能够带小数。
maximum-scale
:容许用户的最大缩放值,为一个数字,能够带小数。
minimum-scale
:容许用户的最小缩放值,为一个数字,能够带小数。
user-scalable
:是否容许用户进行缩放,值为"no"(不能缩放)或"yes"(能够缩放)。
注:device-width 和 device-height 就是 ideal viewport 的宽和高。
设置 <meta name="viewport" content="initial-scale=1">
,这时咱们发现网页没有被浏览器设置缩放。
设置 <meta name="viewport" content="width=device-width">
,这时咱们发现网页也没有被浏览器设设置缩放。
当咱们设置 width=device-width
,也达到了 initial-scale=1
的效果,得知其实 initial-scale = ideal viewport / layout viewport
。
两种方式均可以控制缩放,开发中通常同时设置 width=device-width 和 initial-scale=1.0(为了解决一些兼容问题)参见 移动前端开发之viewport深刻理解 (http://www.cnblogs.com/2050/p...,即:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
关于 em 和 rem
em 是相对长度单位(参照父元素),其参照当前元素字号大小,若是当前元素未设置字号则会继承其祖先元素字号大小。
例如: .box {font-size: 16px;}
则 1em = 16px
.box {font-size: 32px;}
则 1em = 32px,0.5em = 16px
rem 相对长度单位(参照 html 元素),其参照根元素(html)字号大小。
例如 :html {font-size: 16px;}
则 1rem = 16px
html {font-size: 32px;}
则 1rem = 32px,0.5rem = 16px.
vw:viewport width,视口宽度 (1vw = 1%视口宽度)
vh:viewport height 视口高度 (1vh = 1%视口高度)
网易淘宝适配方案:https://www.manster.me/?p=311
相关源码已放置 Github:https://github.com/Daotin/Web...
html 源码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <link rel="stylesheet" href="./css/base.css"> <link rel="stylesheet" href="./css/index.css"> <script src="./js/index.js"></script> </head> <body> <div class="jd"> <!-- 搜索栏开始 --> <div class="search"> <a href="javascript:;" class="search-logo"></a> <form action="" class="search-text"> <input type="text" placeholder="请输入商品名称"> </form> <a href="javascript:;" class="search-login">登陆</a> </div> <!-- 搜索栏结束 --> <!-- 轮播图开始 --> <div class="slideshow"> <ul class="slideshow-img clearfix"> <li> <a href="javascript:;"> <img src="./uploads/l1.jpg" alt=""> </a> </li> <li> <a href="javascript:;"> <img src="./uploads/l2.jpg" alt=""> </a> </li> <li> <a href="javascript:;"> <img src="./uploads/l3.jpg" alt=""> </a> </li> <li> <a href="javascript:;"> <img src="./uploads/l4.jpg" alt=""> </a> </li> <li> <a href="javascript:;"> <img src="./uploads/l5.jpg" alt=""> </a> </li> <li> <a href="javascript:;"> <img src="./uploads/l6.jpg" alt=""> </a> </li> <li> <a href="javascript:;"> <img src="./uploads/l7.jpg" alt=""> </a> </li> <li> <a href="javascript:;"> <img src="./uploads/l8.jpg" alt=""> </a> </li> </ul> <ul class="slideshow-dot"> <li class="select"></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <!-- 轮播图结束 --> <!-- 导航栏开始 --> <div class="nav"> <ul class="nav-ul clearfix"> <li> <a href="javascript:;"> <img src="./uploads/nav0.png"> </a> <p>商品分类</p> </li> <li> <a href="javascript:;"> <img src="./uploads/nav1.png"> </a> <p>商品分类</p> </li> <li> <a href="javascript:;"> <img src="./uploads/nav2.png"> </a> <p>商品分类</p> </li> <li> <a href="javascript:;"> <img src="./uploads/nav3.png"> </a> <p>商品分类</p> </li> <li> <a href="javascript:;"> <img src="./uploads/nav4.png"> </a> <p>商品分类</p> </li> <li> <a href="javascript:;"> <img src="./uploads/nav5.png"> </a> <p>商品分类</p> </li> <li> <a href="javascript:;"> <img src="./uploads/nav6.png"> </a> <p>商品分类</p> </li> <li> <a href="javascript:;"> <img src="./uploads/nav7.png"> </a> <p>商品分类</p> </li> </ul> </div> <!-- 导航栏结束 --> <!-- 主体内容开始 --> <div class="content"> <div class="content-box clearfix content-box-sk"> <div class="content-title"> <span class="content-title-left-clock"></span> <span class="content-title-left-text fl">掌上秒杀</span> <div class="content-title-left-time fl"> <span>0</span> <span>0</span> <span>:</span> <span>0</span> <span>0</span> <span>:</span> <span>0</span> <span>0</span> </div> <span class="content-title-right fr">更多秒杀...</span> </div> <lu class="content-ul clearfix"> <li> <a href="javascript:;"> <img src="./uploads/detail01.jpg" alt="" class="br"> </a> <p>¥10.00</p> <p class="content-ul-delete">¥20.00</p> </li> <li> <a href="javascript:;"> <img src="./uploads/detail01.jpg" alt="" class="br"> </a> <p>¥10.00</p> <p class="content-ul-delete">¥20.00</p> </li> <li> <a href="javascript:;"> <img src="./uploads/detail01.jpg" alt=""> </a> <p>¥10.00</p> <p class="content-ul-delete">¥20.00</p> </li> </lu> </div> <div class="content-box clearfix"> <div class="content-title"> <h3>京东超市</h3> </div> <lu class="content-ul"> <li class="fl"> <a href="javascript:;"> <img src="./uploads/cp1.jpg" alt=""> </a> </li> <li class="fl bl bb"> <a href="javascript:;"> <img src="./uploads/cp2.jpg" alt=""> </a> </li> <li class="fl bl"> <a href="javascript:;"> <img src="./uploads/cp3.jpg" alt=""> </a> </li> </lu> </div> <div class="content-box clearfix"> <div class="content-title"> <h3>京东超市</h3> </div> <lu class="content-ul"> <li class="fr"> <a href="javascript:;"> <img src="./uploads/cp4.jpg" alt=""> </a> </li> <li class="fl bl bb"> <a href="javascript:;"> <img src="./uploads/cp5.jpg" alt=""> </a> </li> <li class="fl bl"> <a href="javascript:;"> <img src="./uploads/cp6.jpg" alt=""> </a> </li> </lu> </div> </div> <!-- 主体内容结束 --> </div> </body> </html>
CSS 源码:
CSS 初始化代码:
@charset "UTF-8"; /*css 初始化 */ html, body, ul, li, ol, dl, dd, dt, p, span, h1, h2, h3, h4, h5, h6, form, fieldset, legend, img, input, div { margin: 0; padding: 0; /* 盒模型 */ box-sizing: border-box; /* 去掉移动端特有的点击高亮效果: transparent 透明色*/ -webkit-tap-highlight-color: transparent; } body { width: 100%; font: 12px/150% "Microsoft YaHei", sans-serif; color: #666; background: #fff } fieldset, img, input, button { /*fieldset组合表单中的相关元素*/ border: none; padding: 0; margin: 0; outline-style: none; /*去除蓝色边框*/ } ul, ol, li { list-style: none; /*清除列表风格*/ } a, a:hover { text-decoration: none; } a:active { color: red; } select, input { vertical-align: middle; /*图片文字垂直居中*/ } select, input, textarea { font-size: 12px; margin: 0; } textarea { resize: none; /*不能改变多行文本框的大小*/ } img { border: 0; vertical-align: middle; /* 去掉图片低测默认的3像素空白缝隙*/ } table { border-collapse: collapse; /*合并外边线*/ } .clearfix::before, .clearfix::after { content: ""; display: block; height: 0; line-height: 0; clear: both; visibility: hidden; } .clearfix { *zoom: 1; /*IE/7/6*/ } h1, h2, h3, h4, h5, h6 { text-decoration: none; font-weight: normal; font-size: 100%; } s, i, em { font-style: normal; text-decoration: none; } /*公共类*/ .w { /*版心 提取 */ width: 1225px; margin: 0 auto; } .fl { float: left } .fr { float: right } .al { text-align: left } .ac { text-align: center } .ar { text-align: right } .hide { display: none } .bl { border-left: 1px solid #ccc; } .br { border-right: 1px solid #ccc; } .bb { border-bottom: 1px solid #ccc; }
CSS 主要代码:
.jd { width: 100%; /* height: 1000px; */ /* 最大宽度 */ max-width: 640px; /* 最小宽度 */ min-width: 320px; margin: 0 auto; background-color: #eee; } /* 搜索栏开始 */ .search { width: 100%; max-width: 640px; height: 40px; background-color: rgba(233, 35, 34, 0); position: fixed; z-index: 10; } .search-logo { width: 56px; height: 20px; background-image: url("../images/jd-sprites.png"); background-size: 200px 200px; background-position: left -109px; position: absolute; left: 10px; top: 10px; } .search-login { color: #fff; font-size: 14px; line-height: 40px; position: absolute; right: 10px; top: 0; } .search-login:visited { color: #fff; } .search-text { width: 100%; height: 100%; padding-left: 76px; padding-right: 50px; } .search-text>input { width: 100%; height: 30px; margin-top: 5px; border-radius: 15px; color: #666; padding-left: 30px; font-size: 14px; } .search-text::before { content: ""; width: 19px; height: 20px; background-image: url("../images/jd-sprites.png"); background-size: 200px 200px; background-position: -60px -109px; position: absolute; left: 83px; top: 10px; } /* 搜索栏结束 */ /* 轮播图开始 */ .slideshow { width: 100%; overflow: hidden; position: relative; } .slideshow-img { width: 800%; } .slideshow-img>li { width: 12.5%; float: left; } .slideshow-img>li img { width: 100%; } .slideshow-dot { width: 80px; height: 10px; position: absolute; left: 50%; bottom: 0; transform: translateX(-50%); } .slideshow-dot>li { width: 6px; height: 6px; float: left; border-radius: 50%; border: 1px solid #fff; margin: 0 2px; } .slideshow-dot>li.select { background-color: #fff; } /* 轮播图结束 */ /* 导航栏开始 */ .nav { width: 100%; box-shadow: 0 2px 2px #ccc; } .nav-ul { width: 100%; background-color: #fff; } .nav-ul>li { width: 25%; float: left; text-align: center; margin-top: 10px; } .nav-ul>li img { width: 60px; height: 60px; } .nav-ul>li p { margin: 5px 0; } /* 导航栏结束 */ /* 主体内容开始 */ .content { width: 100%; } .content-box { width: 100%; margin-top: 10px; background-color: #fff; box-shadow: 0 2px 2px #ccc; } .content-title { border-bottom: 1px solid #ccc; position: relative; } .content-box>.content-title { height: 30px; line-height: 30px; } .content-title>h3 { margin-left: 20px; position: relative; font-weight: 700; } .content-title>h3::before { content: ""; width: 3px; height: 10px; background-color: #e92322; position: absolute; left: -8px; top: 10px; } .content-ul { width: 100%; } .content-ul>li { width: 50%; } .content-ul>li img { width: 100%; display: block; } .content-title-left-clock { display: block; width: 16px; height: 20px; background-image: url("../images/jd-sprites.png"); background-size: 200px 200px; background-position: -85px -111px; position: absolute; left: 3px; top: 4px; } .content-title-left-text { padding: 0 10px 0 25px; color: #e92322; } .content-title-left-time>span { display: inline-block; width: 12px; height: 18px; line-height: 18px; background-color: #363634; color: #e5d790; text-align: center; font-weight: bold; } .content-title-left-time>span:nth-of-type(3n) { background-color: transparent; width: 3px; } .content-title-right { margin-right: 10px; } .content-box-sk { padding: 10px; } .content-box-sk>.content-title { border-bottom: 0; margin-bottom: 10px; } .content-box-sk .content-ul { padding: 10px 0; display: flex; justify-content: space-around; } .content-box-sk .content-ul>li { /* width: 33.33%; */ text-align: center; } .content-box-sk .content-ul>li img { width: 100%; display: inline-block; padding: 0 30px; margin-bottom: 5px; } .content-ul-delete { text-decoration: line-through; color: #aaa; } /* 主体内容结束 */
javaScript 代码:
window.onload = function () { bannerEffect(); timeCount(); slideshowEffect(); }; // 搜索栏上下滚动时改变透明度 function bannerEffect() { var bannerObj = document.querySelector(".search"); var slideshowObj = document.querySelector(".slideshow") // 获取搜索栏的高度 var bannerHeight = bannerObj.offsetHeight; //40 // 获取轮播图高度 var slideshowHeight = slideshowObj.offsetHeight; //311 window.addEventListener("scroll", function () { // 页面向上滚动的距离(兼容代码) var scrolllen = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; if (scrolllen < (slideshowHeight - bannerHeight)) { var setopacity = scrolllen / (slideshowHeight - bannerHeight); bannerObj.style.backgroundColor = "rgba(233, 35, 34, " + setopacity + ")"; } }, false); } // 主体内容秒杀栏目的倒计时 function timeCount() { var spanObjs = document.querySelector(".content-title-left-time").children; var titleCount = 2 * 60 * 60; // 2小时倒计时 var timeId = setInterval(function () { titleCount--; var hour = Math.floor(titleCount / 3600); var minute = Math.floor((titleCount % 3600) / 60); var second = titleCount % 60; if (titleCount >= 0) { // 下面的true实际想表达的是不执行任何操做,可是必需要写个语句,因此用true代替。 spanObjs[0].innerHTML == Math.floor(hour / 10) ? true : spanObjs[0].innerHTML = Math.floor(hour / 10); spanObjs[1].innerHTML == hour % 10 ? (true) : spanObjs[1].innerHTML = hour % 10; spanObjs[3].innerHTML == Math.floor(minute / 10) ? true : spanObjs[3].innerHTML = Math.floor(minute / 10); spanObjs[4].innerHTML == minute % 10 ? true : spanObjs[4].innerHTML = minute % 10; spanObjs[6].innerHTML == Math.floor(second / 10) ? true : spanObjs[6].innerHTML = Math.floor(second / 10); spanObjs[7].innerHTML == second % 10 ? true : spanObjs[7].innerHTML = second % 10; } else { titleCount = 0; clearInterval(timeId); return; } }, 1000); } // 轮播图 function slideshowEffect() { // 1. 自动轮播图 // 思路:1.一、使用js在图片开头动态添加本来最后一张图片 // 1.二、使用js在图片结尾动态添加本来第一张图片 // 获取轮播图 var slideshowObj = document.querySelector(".slideshow"); // 获取ul var ulObj = document.querySelector(".slideshow-img"); // 获取全部li var liObjs = ulObj.children; // 设置li的索引值 var index = 1; // 要添加的第一个li和最后一个li var first = liObjs[0].cloneNode(true); var last = liObjs[liObjs.length - 1].cloneNode(true); // 在li开头结尾添加克隆图片 ulObj.appendChild(first); ulObj.insertBefore(last, ulObj.firstElementChild); // 设置ul宽度 ulObj.style.width = liObjs.length + "00%"; // 设置每一个li的宽度 for (var i = 0; i < liObjs.length; i++) { liObjs[i].style.width = slideshowObj.offsetWidth + "px"; } // 默认显示第一张图 ulObj.style.transform = "translateX(" + -(slideshowObj.offsetWidth) + "px)" // 改变窗口大小的时候自动调节轮播图的宽度 window.addEventListener("resize", function () { ulObj.style.width = liObjs.length + "00%"; for (var i = 0; i < liObjs.length; i++) { liObjs[i].style.width = slideshowObj.offsetWidth + "px"; } // 改变窗口的大小的时候,不能仅仅回到第一张,要回到第index张 ulObj.style.transform = "translateX(" + -(slideshowObj.offsetWidth * index) + "px)" }, false); // 1. 实现自动轮播效果 var timerId; var timerStart = function () { timerId = setInterval(function () { index++; ulObj.style.transition = "transform 0.5s ease-in-out"; ulObj.style.transform = "translateX(" + -(slideshowObj.offsetWidth * index) + "px)"; // 设置小白点 if(index >= liObjs.length - 1) { setDot(1); return; } setDot(index); // 因为过渡效果,使得过渡的时候,就进行if、判断,没法显示最后一张图片。 // 因此进行延时过渡的时候,等全部过渡效果完成后再进行判断是否到达最后一张。 setTimeout(function () { if (index >= liObjs.length - 1) { index = 1; // 从最后一张调到第一张的时候,取消过渡效果 ulObj.style.transition = "none"; ulObj.style.transform = "translateX(" + -(slideshowObj.offsetWidth * index) + "px)"; } }, 500); }, 1500); }; timerStart(); // 2. 轮播图的手动滑动效果 // 2.一、记录手指的起始位置 // 2.二、记录手指滑动时与起始位置水平轴的偏移距离 // 2.三、设置当手指松开后,判断偏移距离的大小,决定回弹仍是翻页。 var startX, diffX; // 设置节流阀,避免手动滑动过快,在过渡过程当中也有滑动,形成的最后图片会有空白的操做,也就是index越界了,没有执行相应的 webkitTransitionEnd 事件。 var isEnd = true; ulObj.addEventListener("touchstart", function (e) { // 手指点击轮播图时,中止自动轮播效果 clearInterval(timerId); startX = e.targetTouches[0].clientX; }, false); // 最开始的时候不触发,缘由ul的高度为0 ulObj.addEventListener("touchmove", function (e) { if (isEnd) { // 手指移动的距离 diffX = e.targetTouches[0].clientX - startX; // 关闭过渡效果,不然手指滑动困难 ulObj.style.transition = "none"; ulObj.style.transform = "translateX(" + -(slideshowObj.offsetWidth * index - diffX) + "px)"; } }, false); ulObj.addEventListener("touchend", function (e) { isEnd = false; // 判断当前滑动的距离是否超过必定的距离,则翻页 if (Math.abs(diffX) > 100) { if (diffX > 0) { index--; } else { index++; } // 翻页 ulObj.style.transition = "transform 0.5s ease-in-out"; ulObj.style.transform = "translateX(-" + slideshowObj.offsetWidth * index + "px)"; } else if (Math.abs(diffX) > 0) { // 回弹 ulObj.style.transition = "transform 0.5s ease-in-out"; ulObj.style.transform = "translateX(-" + slideshowObj.offsetWidth * index + "px)"; } // 每次离开手指清除startX, diffX的值 startX = 0; diffX = 0; if(index == liObjs.length-1) { setDot(1); return; } else if(index == 0) { setDot(liObjs.length-2); return; } setDot(index); // 手指离开从新开启定时器 timerStart(); }, false); // 咱们发如今第一张往右滑动,或者最后一张往左滑动时,会形成空白 /*webkitTransitionEnd:能够监听当前元素的过渡效果执行完毕,当一个元素的过渡效果执行完毕的时候,会触发这个事件*/ ulObj.addEventListener("webkitTransitionEnd", function () { // 若是到了第一张(index=0),让index=count-2 // 若是到了最后一张(index=count-1),让index=1; if (index == 0) { index = liObjs.length - 2; // 从第一张到最后一张的时候,取消过渡效果 ulObj.style.transition = "none"; ulObj.style.transform = "translateX(" + -(slideshowObj.offsetWidth * index) + "px)"; } else if (index >= liObjs.length - 1) { index = 1; // 从最后一张调到第一张的时候,取消过渡效果 ulObj.style.transition = "none"; ulObj.style.transform = "translateX(" + -(slideshowObj.offsetWidth * index) + "px)"; } // 设置过渡效果完成后,才能够继续滑动 setTimeout(function () { isEnd = true; }, 100); }, false); // 3. 设置轮播图小白点 function setDot(index) { var dotliObjs = document.querySelector(".slideshow-dot").children; // 建议不使用className,由于class属性可能有多个,使用dotliObjs[i].className = "";可能将其余的类样式一块儿清除。 for (var i = 0; i < dotliObjs.length; i++) { // 清除全部select样式 dotliObjs[i].classList.remove("select"); } // 设置当前索引的样式为select dotliObjs[index-1].classList.add("select"); } }
这里面的难点和重点就是轮播图部分:
一、思路:
要实现轮播图,必须在首尾添加图片,若是直接在 html 代码直接添加图片的话,因为图片的数量是不固定的,那么每次图片的数量发生改变的话,不只须要设置 html 的源码,并且还要设置对应的 css 代码,因此,为了从后台获取的图片数量不固定的状况下,也可以实现轮播效果,咱们可使用 js 来动态的添加图片。
轮播图要首尾链接,关键是先后加图。
二、在手动轮播的时候,必定记得将自动轮播时的过渡效果清除。还要关闭定时器,在手指离开的时候再次设置是定时器。关于手动轮播的相关触摸事件知识点在下面介绍。
touchstart
: 手指触摸屏幕时触发
touchmove
: 手指在屏幕上移动时触发
touchend
: 手指离开屏幕时触发
touchcancel
: 手指要移动的事件中,touchmove事件被打断的时候触发(好比忽然来了个弹框等)
细节:
touch 事件的触发,必须保证元素有大于0的宽高值,不然没法触发。(好比 ul 下 li 有宽高,ul 会被撑开,有了宽高,可是当 li 浮动起来后,ul 的宽还在, 高为0,此时没法对 ul 触发 touch 事件。)
event 事件对象是手指触摸屏幕时触发的事件对象,在这个对象中,咱们主要关注三个对象数组。
touches
:指屏幕上全部的触摸的手指列表
targetTouched
:当前目标上全部的触摸的手指列表
changedTouches
:指当前屏幕上变换的手指对象。在 touchstart 时为新接触屏幕的手指,在 touchend 时为新离开屏幕的手指。
PS:没有对比出 touches 同 targetTouches 的差别,推荐使用 targetTouches。
示例:手指拖动小球box
targetTouches 对象中有几个坐标值值得咱们关注:
screenX/screenY
:手指的触摸点相对屏幕左上角的距离。
clientX/clientY
:手指的触摸点相对视口(移动端屏幕左上角)的距离。
pageX/pageY
:手指的触摸点相对当前页面的左上角的距离(当前页面可能有滚动条,因此距离包含滚动的距离)。
而,通常当咱们在移动端设置了 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
以后,clientX/clientY 的距离和 pageX/pageY 的距离是相同的了。因此通常使用 clientX/clientY。
还有2件事拜托你们一:求赞 求收藏 求分享 求留言,让更多的人看到这篇内容
二:欢迎添加个人我的微信
备注“资料”, 300多篇原创技术文章,海量的视频资料便可得到
备注“加群”,我会拉你进技术交流群,群里大牛学霸具在,哪怕您作个潜水鱼也会学到不少东西