1. BOM
Browser Object Model,浏览器对象模型,提供与浏览器窗口进行交互的对象,核心对象是 window。
- BOM 缺乏标准,兼容性较差;DOM(W3C)、JavaScript 语法(ECMA);
BOM 比 DOM 更大,它包含了 document、location、navigation、screen、history。
2. window 对象
它是浏览器的顶级对象,具有双重角色:
- 既是JS访问浏览器窗口的一个接口;
- 也是一个全局对象。定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。
注意,window 对象有一个特殊属性 window.name,它是有意义的,所以不要给变量起名为 name。
3. window 对象的常用事件
① 页面加载事件
**window.onload = function(){ }**
或者**window.addEventListener('load' , function(){ })**
【说明】当页面内容完全加载完成后(包括图像、其余的JS、CSS等)才会触发该事件,随后调用处理函数。
【注意】window.onload 传统注册方式只能写一次,如果有多个,则会以最后一个为准;
- 使用 window.addEventListener 新标准方式则不会有上述限制;
- 点击 a 标签的超链接、点击浏览器的前进后退按钮、刷新页面,都能触发 load 事件。
【相似事件】DOM 加载事件 **document.addEventListener('DOMContentLoaded' , function(){ })**
【说明】当 DOM 加载完成后(即标签元素加载完成,不包括图像、CSS等)就会触发该事件,随后调用处理函数。
【注意】
- 兼容性:IE 9+
- 事件顺序:先 DOM 加载事件,后页面加载事件
使用场合:当页面图片较多时使用,保证页面的结构和交互效果不受图片加载速度的影响。
② 调整窗口大小事件
**window.onresize = function(){ }**
或者**window.addEventListener('resize' , function(){ })**
【说明】当窗口的大小被调整时(像素级别),会触发该事件,随后调用处理函数。
【注意】只要窗口的宽度或高度发生像素变化,就会触发该事件;
利用该事件,配合属性 window.innerWidth ( 当前屏幕的宽度,单位px ),可以完成响应式布局。
4. window 对象的常用方法
① 四种定时器方法
【方法1】
**window.setTimeout( function(){ } [, 延迟的毫秒数] );**
【说明】该方法用于设置一个定时器,当定时器到期后就会执行回调函数( callback ),window 可省略。
【注意】延迟时间的单位是毫秒,单位不需要写出来,如果省略时间,则默认延迟时间为0,即立刻异步执行回调函数;
- 处理函数可直接在 function 里,也可以写函数名。
- 页面中可以同时存在多个定时器,那么我们可以给它们添加标识符(起名),方法如下:
var timer1 = setTimeout(callback, 3000);
var timer2 = setTimeout(callback, 6000);
【方法2】 **window.clearTimeout(timeoutID);**
【说明】该方法可取消通过 setTimeout() 来建立的定时器,timeoutID 是定时器的标识符。
var btn = document.querySelector('button');
var timer = setTimeout(callback , 5000);
// 定时器 timer 到期前点击 button 就可以取消,要是到期后再点击就没意义了
btn.addEventListener('click' , function(){
clearTimeout(timer);
})
【方法3】 **window.setInterval( function(){ } [, 间隔的毫秒数] );**
【说明】该方法可重复执行回调函数,每隔一定时间,就会去执行一次。
【注意】同 setTimeout(),window 可省略。
【方法4】 **window.clearInterval(timeoutID);**
【说明】该方法可取消通过 setInterval() 来建立的定时器,timeoutID 是定时器的标识符。
【案例1】简易倒计时器(重点必会)
【代码较长,请查看“倒计时器-简易案例.html”文件,已做好注释】
【案例2】按钮倒计时器
【代码较长,请查看“倒计时器-按钮案例.html”文件,已做好注释】
② this 的指向问题
【说明】一般情况下,this 的最终指向是它的调用者,当然程序员也能手动更改它的指向。
【具体请查看“this指向问题.html”文件,已做好注释】
5. JavaScript 执行机制
① JavaScript 语言的一大特点就是单线程,即JS同一时间只能做一件事。单线程就意味着所有任务都需要排队,前一个任务结束后才能执行后一个任务。这就容易造成页面渲染不连贯,使得页面加载出现不连贯的感觉。
② 为了解决这个问题,JavaScript 提供了异步操作,并提出“同步”和“异步”这两个概念:
【同步】前一个任务结束后再执行后一个任务,即任务执行顺序与排列顺序是一致的,称之为“同步”
【异步】若某个任务需要花费大量时间,那就先不处理这个任务,而执行下一个任务,称之为“异步”
③ 执行机制详解
- JS 引擎在编译代码时,会创建两个队列:同步任务队列 和 异步任务队列(又称:事件任务队列);
- 接着,JS 引擎会把代码中所有的任务按照制定好的规则分配到两种队列里;
- 等 JavaScript 执行线程开始后,按照先进先出的原则,先执行同步任务队列里的所有任务,再执行异步任务队列里的所有任务,这就是 JavaScript 的执行机制。
【任务分配规则】
【说明】异步任务队列,又称事件任务队列。一般来说,异步任务队列会存放以下三种类型的回调函数:
- DOM 事件的回调函数,比如 click、resize、focus、blur 等;
- 资源加载事件的回调函数,比如 load、error 等;
定时器方法的回调函数,包括 setTimeout、setInterval 等。
// 有如下代码:
console.log(1);
setTimeout( function(){
console.log(3);
},5000);
console.log(2);
// 被分配到同步任务队列里的任务是:
//【1】console.log(1);
//【2】setTimeout(function , 5000); 注:这里开始计时,但不需要等待5秒,计时开始后即可往下执行任务【3】
//【3】console.log(2);
// 被分配到异步任务队列里的任务是:
//【4】function(){console.log(3);}
// 输出结果:1 2 3
/*
需要注意的是,当5秒计时结束后,任务【4】才会被分配到异步任务队列里
但是,只有同步任务队列里所有任务执行完成后,才能执行异步任务队列里的任务
也就是说,如果同步任务需要处理5秒以上,那么即使5秒倒计时结束了,也无法执行异步任务
*/
【事件循环 ( Event Loop ) 】JavaScript 执行线程会不断的重复获取任务、执行任务、再获取、再执行,于是我们称之为事件循环。
// 有如下代码:
console.log(1);
document.onclick = function(){
console.log('click');
}
console.log(2);
// 被分配到同步任务队列里的任务是:
//【1】console.log(1);
//【2】document.onclick = function;
//【3】console.log(2);
// 被分配到异步任务队列里的任务是:
//【4】function(){console.log('click');}
/*
需要注意的是,只有用户点击了页面后,任务【4】才会被分配到异步任务队列里,而且该任务可以重复多次出现(用户点击后就会出现)
所以 JS 执行线程需要不断地监视异步任务队列,只要检测到任务出现,它就会获取并执行之,这就是所谓的事件循环(Event Loop)
*/
【参考资料】https://blog.csdn.net/weixin_43789897/article/details/85210069
6. location 对象
① 概念
window 对象给我们提供了一个 location 属性,用于获取或设置窗体的URL,并且可以用于解析URL。
因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象。
② 统一资源定位符(Uniform Resource Loactor,URL)
【语法格式】
protocol://host[:port]/path/[?query]#fragment
【用词说明】protocol 通信协议,常见的有 http、ftp、maito 等
- host 主机(域名),例如 www.bilibili.com
- port 端口号,可选,省略时使用方案的默认端口,例如 http 协议的默认端口为80
- path 路径,由多个 ‘ / ‘ 符号隔开的字符串,一般用于表示主机上的一个目录或文件地址
- query 参数,可选,以键值对的形式呈现,通过 ‘ & ‘ 符号连接多个键值对
fragment 片段,即 ‘ # ‘ 后面的内容,常见于链接锚点
③ location 对象的常用属性
location.href 获取或者设置整个URL(直接输出则是当前页面的URL,重新赋值则能跳转到新页面)
- location.host 返回主机(域名),例如 www.itheima.com
- location.port 返回端口号,如果未写返回空字符串
- location.pathname 返回路径,主机(域名)后面的内容
- location.search 返回参数,? 后面的内容(包括 ? )
- location.hash 返回片段,# 后面的内容(包括 #)
【例1】5秒钟之后自动跳转至新页面
<body>
<div></div>
</body>
<script>
var div = document.querySelector('div');
var time = 5;
setInterval(function(){
if (time==0) {
location.href = 'http://www.bilibili.com';
} else {
div.innerHTML = '您将在 ' + time + ' 秒钟之后跳转到首页';
time--;
}
}, 1000);
</script>
【例2】两页面之间的参数传递(参考资料:https://blog.csdn.net/wzwenhuan/article/details/7803510)
【login.html】
<body>
<!-- 默认采用 get 请求方式,数据以 name=value 的键值对方式存放在URL中 -->
<form action="index.html"> <!-- action 属性指定了处理这些表单数据的页面 -->
用户名:<input type="text" name="uname">
<input type="submit" value="登录"> <!-- 没有 name 属性,不会生成键值对 -->
</form>
</body>
【index.html】
<body>
<div></div>
</body>
<script>
console.log(location.search); // 假设获取到的参数是 '?uname=andy'
// 1. 先去掉问号 '?' ,利用字符串方法 substr( '起始的位置' [, 截取几个字符] );
var params = location.search.substr(1);
console.log(params); // uname=andy
// 2. 把字符串分割为数组,利用字符串方法 split('=');
var arr = params.split('=');
console.log(arr); // ["uname", "ANDY"]
// 3. 把数据写入 div 标签内
var div = document.querySelector('div');
div.innerHTML = arr[1] + '欢迎您';
</script>
④ location 对象的常用方法
location.assign('URL');
跟 href 一样,可以进行页面跳转,记录历史,能进行页面后退location.replace('URL');
替换当前页面,但是不记录历史,所以不能进行页面后退location.reload();
重新加载页面,相当于刷新按钮或者F5,如果参数为true,进行强制刷新ctrl+F57. navigator 对象
【说明】
该对象包含有关浏览器的信息,它有很多属性,我们最常用的是 userAgent。
- 这个属性可以返回由客户端发送至服务器的 user-agent 头部的值。
- 该属性值包含了客户端的浏览器、浏览器内核以及操作系统的版本号。
我们可以通过获取这个属性的值来判断客户端是 PC 还是智能移动设备,从而让用户访问正确的页面。
8. history 对象
① window 对象提供的 history 对象能与浏览器历史记录进行交互,该对象包含用户(在浏览器窗口中)访问过的URL。
② history 对象常用方法history.back(); 后退功能
- history.forward(); 前进功能
- history.go(参数); 前进后退功能,参数如果是1,前进1个页面;如果是-1,后退1个页面
PC 端网页特效
1. 元素偏移量 offset 系列
① offset 基础
【概述】offset 即偏移量,使用 offset 系列相关属性可以 [ 动态地 ] 得到该元素的位置(偏移)、大小等。
【注意】
- 可获得子元素距离父元素的位置,但要求父元素带有定位,返回值不带单位;
-
② offset 常用属性
element.offsetLeft 返回元素相对于带有定位的父元素左边框的偏移,如果父级都没有定位,则以 body 为准(返回值不带单位)
- element.offsetTop 返回元素相对于带有定位的父元素上边框的偏移,如果父级都没有定位,则以 body 为准(返回值不带单位)
- element.offsetWidth 返回自身包括 padding、边框、内容区的宽度(返回值不带单位)
- element.offsetHeight 返回自身包括 padding、边框、内容区的高度(返回值不带单位)
element.offsetParent 返回带有定位的父级元素节点,如果父级都没有定位,则返回 body
③ 各种区别
【element.parentNode 和 element.offsetParent 的区别】
parentNode 返回的是最近一级的父级元素节点,不局限于有没有定位;
- offsetParent 返回的是带有定位的父级元素节点,不局限于最近一级。
【offset 和 style 的区别】
offset | style |
---|---|
可以得到任意样式表中的样式值 | 只能得到行内样式表中的样式值 |
获得的数值是没有单位的 | 获得的是带有单位的字符串 |
offsetWidth 包含 padding+border+width | style.width 获得不包含 padding 和 border |
offsetWidth 等属性是只读属性,只能获取不能赋值 | style.width 是可读写属性,可以获取也可以赋值 |
综上,想要获取元素大小位置,用 offset 更合适 | 综上,想要给元素更改数值,用 style 更合适 |
【案例】获取鼠标在盒子内的坐标
【原理】
● 先通过鼠标事件对象 ( e.pageX / e.pageY ) 获取鼠标在页面上的坐标;
● 再通过元素偏移量 ( offsetLeft / offsetTop ) 获取盒子再页面上的偏移;
● 最后把坐标值减去偏移量就能得到鼠标在盒子内的坐标(盒子是坐标系)。
<body>
<div class="box"></div>
</body>
<script>
var box = document.querySelector('.box');
box.addEventListener('mousemove' , function(e){
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
this.innerHTML = '鼠标的x坐标是' + x + ' y坐标是' + y;
})
</script>
【案例】弹出式模态框(可拖拽)
【分析】
● 点击弹出层,模态框和遮罩层就会显示出来 dispaly:block; 点击关闭按钮隐藏模态框和遮罩层 dispaly:none
● 在页面中拖拽元素时,鼠标操作的两个步骤:先按下(down)并移动(move)鼠标,再松开(mouseup)鼠标
● 实现拖拽效果:鼠标移动的过程中,获取其最新的坐标值,经过处理后赋值给模态框的 left 和 top 即可
● 处理方式:利用鼠标在页面上的坐标值减去鼠标在模态框内的坐标值,就能得到模态框在页面上的最新坐标
● 允许鼠标按下触发拖拽的事件源是模态框最上面那一行,id 是 title
【代码较长,请查看“弹出式模态框案例.html”文件,已做好注释】
【案例】商品图片放大镜(仅 JavaScript 代码)
【分析】
● 鼠标经过小图片盒子时,黄色遮罩层和大图片盒子显示;鼠标离开小图片盒子后它们消失;
● 在小图片盒子内,黄色遮罩层随鼠标一起移动,但不得超出小图片盒子的范围;
● 在大图片盒子内,显示的是小图片在黄色遮罩层范围下的放大版;
● 黄色遮罩层移动的同时,大图片盒子内的图片一起移动。
window.addEventListener('load' , function(){
var preview_img = document.querySelector('.preview_img'); // 小图片盒子
var mask = document.querySelector('.mask'); // 黄色遮罩层(绝对定位在小图片盒子内部)
var big = document.querySelector('.big'); // 大图片盒子(绝对定位在小图片盒子外部右侧)
// 1. 当我们鼠标经过 preview_img 就显示和隐藏 mask 遮挡层 和 big 大盒子
preview_img.addEventListener('mouseover', function(){
mask.style.display = 'block';
big.style.display = 'block';
})
preview_img.addEventListener('mouseout', function(){
mask.style.display = 'none';
big.style.display = 'none';
})
// 2. 鼠标移动的时候,让黄色遮罩层盒子跟着鼠标来走(黄色盒子的坐标就是鼠标在小图片盒子内的坐标)
preview_img.addEventListener('mousemove', function(e){
// (1) 先计算出鼠标在小图片盒子内的坐标
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// (2) 让鼠标对齐黄色遮罩层盒子的中间点,即让黄色盒子移动自己宽高的一半的距离
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// (3) 限制黄色遮罩层盒子的位置,不让它跑到小图片盒子外,这就需要计算它允许的最大移动距离
// 遮罩层最小移动距离是0,最大移动距离是 小图片盒子宽度(高度) 减去 遮罩层盒子宽度(高度)
var maskXMax = preview_img.offsetWidth - mask.offsetWidth;
var maskYMax = preview_img.offsetHeight - mask.offsetHeight;
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskXMax) {
maskX = maskXMax;
}
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskYMax) {
maskY = maskYMax;
}
// 最终黄色遮罩层的移动距离
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
// 3. 计算大图片移动的距离,因为移动距离比例要一致,所以可知:
// 大图片的移动距离与其最大移动距离的比值 = 遮罩层的移动距离与其最大移动距离的比值,得出公式:
// 大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
var bigIMG = document.querySelector('.bigImg'); // 获取大图片元素节点
// 大图片最大移动距离
var bigXMax = bigIMG.offsetWidth - big.offsetWidth;
var bigYMax = bigIMG.offsetHeight - big.offsetHeight;
// 大图片的移动距离 X Y
var bigX = maskX * bigXMax / maskXMax;
var bigY = maskY * bigYMax / maskYMax;
// 遮罩层往右走,但大图是往左走的,所以要加 - 号
bigIMG.style.left = -bigX + 'px';
bigIMG.style.top = -bigY + 'px';
})
})
2. 元素可视区 client 系列
① client 基础
【概述】client 翻译过来就是客户端,通过 client 的相关属性可以动态地得到该元素的边框大小、元素大小等。
② client 常用属性
- element.clientTop 返回元素上边框的大小
- element.clientLeft 返回元素左边框的大小
- element.clientWidth 返回自身包括 padding、内容区的宽度 ( 不含边框,返回值不带单位 )
- element.clientHeight 返回自身包括 padding、内容区的高度 ( 不含边框,返回值不带单位 )
【client 和 offset 的区别】
- client 返回的元素宽高不包含边框宽度,但 offset 返回的元素宽高包含;
client 可以单独返回元素的边框宽度,但 offset 不可以。
3. 元素滚动 scroll 系列
① scroll 基础
【概述】使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。
② scroll 常用属性(返回值不带单位)
element.scrollTop 返回被卷去的上侧距离(内容区域有滚动条的时候使用)
- element.scrollLeft 返回被卷去的左侧距离(内容区域有滚动条的时候使用)
- element.scrollwidth 返回自身实际的内容宽度,包含 padding,不含边框
- element.scrollHeight 返回自身实际的内容高度,包含 padding,不含边框
【scroll 和 client 的区别】client 返回的元素宽高仅仅是元素可视区域的宽高,不包括滚动区域的宽高
③ scroll 滚动事件
【说明】当元素的滚动条发生变化时(被用户拖动)触发的事件
div.addEventListener('scroll' , function(){
console.log( div.scrollTop ); // 输出被卷去的内容顶部距离元素顶部的距离
console.log( div.scrollLeft ); // 输出被卷去的内容左侧距离元素左侧的距离
})
【案例】仿淘宝固定侧边栏
【功能】
- 原先侧边栏是绝对定位
- 当页面往下滚动一定距离,侧边栏改为固定定位,固定在网页右侧
- 页面再滚动一定距离后,侧边栏会出现“返回顶部”的功能按钮
- 点击“返回顶部”按钮,页面以动画的方式网上滚动至页面顶部(涉及 JavaScript 动画)
【分析】
- 需要用到页面滚动事件scroll,因为是页面滚动,所以事件源是 document
- 判断滚动到某个位置,就是判断页面被卷去的那一部分的高度值大小
- 页面被卷去的头部高度值可通过 window.pageYOffset 获得
- 注意,element.scrollTop 获取的是元素被卷去的头部高度值,并不是页面,所以没用到 scrollTop
【代码较长,请查看“仿淘宝固定侧边栏案例.html”文件,已做好注释】
【offset、client、scroll 三大系列总结】
- offset 系列常用于获取元素的位置(offsetLeft、offsetTop)
- client 系列常用于获取元素的大小(clientWidth、clientHeight)
- scroll 系列常用于获取元素的内容滚动距离(scrollTop、scrollLeft)
特别注意:获取页面的滚动距离是通过 window.pageXOffset / pageYOffset 来获取的
4. JavaScript 动画函数封装
① 动画实现原理
【核心原理】通过定时器 setInterval( ) 不断移动盒子的位置
【步骤分解】获取盒子当前的位置,利用 element.offsetLeft 即可,但这个属性是只读属性,不可写入;
- 让盒子在当前位置加上一个移动距离,注意此盒子需要添加定位才能使用 element.style.left;
- 利用定时器
setInterval()
不断重复这个操作; 最后还需设置一个定时器结束
clearInterval()
的条件。var div = document.querySelector('div'); var timer = setInterval(function(){ if ( div.offsetLeft == 200 ) { clearInterval( timer ); } div.style.left = div.offsetLeft + 1 +'px'; }, 30);
② 动画函数简单封装
【传参】注意动画函数需要传递最少两个参数,动画对象(谁要动起来)和移动距离(什么时候结束动画)
// 封装动画函数 function simpleAnimate(obj , target){ var timer = setInterval(function(){ if ( obj.offsetLeft == target ) { clearInterval( timer ); } obj.style.left = obj.offsetLeft + 1 +'px'; }, 30); } // 调用动画函数 var div = document.querySelector('div'); simpleAnimate(div , 400);
【问题出现】如果多个元素都使用这个动画函数,每次都要 var 声明定时器,这会浪费大量内存。
【解决方法】利用 JavaScript 是一门动态语言的特性,我们可以很方便地给当前对象添加属性。// 封装动画函数 function simpleAnimate(obj , target){ // 给不同的元素指定了不同的定时器,既不容易混淆,也不需要开辟新空间浪费内存 obj.timer = setInterval(function(){ if ( obj.offsetLeft == target ) { clearInterval( obj.timer ); } obj.style.left = obj.offsetLeft + 1 +'px'; }, 30); } // 调用动画函数 var div = document.querySelector('div'); simpleAnimate(div , 400);
【问题又出现】
如果给元素添加一个按钮,点击才执行动画函数。此时若用户不断点击按钮,元素移动速度会明显加快。
- 因为用户多次点击按钮,会给同一个元素开启多个定时器,它们会同时工作,速度当然会变快。
【解决方法】限制元素的定时器个数为一个即可。
// 封装动画函数
function simpleAnimate(obj , target){
// 先清除之前所有的定时器,保证当前时刻只有一个定时器在运行
clearInterval( obj.timer );
obj.timer = setInterval(function(){
if ( obj.offsetLeft == target ) {
clearInterval( obj.timer );
}
obj.style.left = obj.offsetLeft + 1 +'px';
}, 30);
}
// 调用动画函数
var div = document.querySelector('div');
simpleAnimate(div , 400);
③ 缓动动画
【效果】让元素运动速度有所变化,常见的是让速度慢慢降为0。
【原理】
- 让盒子每次移动的距离慢慢变小,速度就会慢慢降为0;
- 核心算法:( 目标位置 - 当前位置 ) / 10 作为每次移动的距离,即步长;
- 停止条件:盒子到达目标位置时就停止计时器;
- 特别注意:步长值需要取整,不然元素永远无法到达目标位置
// 封装缓动动画函数 function simpleAnimate(obj , target){ clearInterval( obj.timer ); obj.timer = setInterval(function(){ // 每次移动前先计算步长 var step = ( target - obj.offsetLeft ) / 10; // 如果步长为正数,向上取整;如果步长为负数,向下取整 step = step > 0 ? Math.ceil( step ) : Math.floor( step ); if ( obj.offsetLeft == target ) { clearInterval( obj.timer ); } obj.style.left = obj.offsetLeft + step +'px'; }, 30); } // 调用缓动动画函数 var div = document.querySelector('div'); simpleAnimate(div , 400);
④ 给动画函数添加回调函数
【回调函数原理】函数可以作为一个参数,传到另一个函数里面,当那个函数执行完之后再执行传进去的函数,这个过程就叫做回调。// 封装缓动动画函数,callback 是回调函数 function simpleAnimate(obj , target , callback){ clearInterval( obj.timer ); obj.timer = setInterval(function(){ var step = ( target - obj.offsetLeft ) / 10; step = step > 0 ? Math.ceil( step ) : Math.floor( step ); if ( obj.offsetLeft == target ) { clearInterval( obj.timer ); // 因为要等计时器结束后再执行回调函数,所以回调函数的调用写在这里 // 短路运算原理,先判断参数callback是否为空,不为空才进行下一步执行函数 callback && callback(); } obj.style.left = obj.offsetLeft + step +'px'; }, 30); } // 调用缓动动画函数 var div = document.querySelector('div'); simpleAnimate( div , 400 , function(){ div.style.backgroundColor = 'red'; alert('动画结束啦!'); });
【案例】网页轮播图(重点掌握)
【功能需求】
- 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮
- 点击右侧按钮一次,图片往左播放—张,以此类推,左侧按钮同理
- 图片播放的同时,下面小圆圈模块跟随一起变化
- 点击小圆圈,可以播放相应图片
- 鼠标不经过轮插图,轮播图也会自动播放图片
- 鼠标经过,轮播图模块,自动捅放停止
【节流阀】防止轮播图按钮连续点击而造成动画播放过快
- 核心原理:利用回调函数,在里面添加一个变量,用于锁住或解锁缓动动画函数
【代码较长,请查看“网页轮播图.js”文件,已做好注释】
移动端网页特效
① 触屏事件 touch 系列
touch 对象代表一个触摸点,可响应用户手指或触控笔对屏幕的操作
② 常见的触摸屏事件
- touchstart 手指 [ 触摸 ] 到一个 DOM 元素时触发
- touchmove 手指在一个 DOM 元素上 [ 滑动 ] 时触发
touchend 手指从一个 DOM 元素上 [ 移开 ] 时触发
③ 触摸事件对象 TouchEvent
【概述】
TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。
- 这类事件用于描述一个或多个触点,使开发者可以检测触点的移动、增加或减少等触点变化。
【常见对象列表】
- e.touches 正在触摸 [ 屏幕 ] 的所有手指的一个列表
- e.targetTouches 正在触摸 [ 当前 DOM 元素 ] 上的手指的一个列表(常用)
- e.changedTouches 状态发生了改变的手指列表(从无到有,从有到无的改变)
【区别】
当所有手指离开屏幕后,touches 和 targetTouches 列表就无法获取任何手指信息了,但 changedTouches 可以获取到,因为这些手指的状态发生了改变。
④ 拖动元素
【概述】
利用 touchstart、touchmove、touchend 可以实现拖动元素;
- 但是拖动元素需要当前手指的坐标值,我们可以使用 e.targetTouches[0] 里面的 pageX 和 pageY;
- 移动端拖动的原理:计算出手指的移动距离,那么,盒子原来的位置 + 手指移动的距离 = 盒子最终的位置;
- 手指移动的距离:手指滑动中的位置减去手指刚开始触摸的位置。
【步骤】
- 触摸元素 touchstart:获取手指初始坐标,同时获得盒子原来的位置
- 移动手指 touchmove:计算手指的滑动距离,并且移动盒子
- 离开手指 touchend:无任何操作
注意:手指移动也会触发滚动屏幕事件,所以这里要阻止默认的屏幕滚动
e.preventDefault();
<style> div { position: absolute; left: 0; width: 100px; height: 100px; background-color: pink; } </style> <body> <div></div> </body> <script> var div = document.querySelector('div'); // 声明全局变量 手指初始坐标 var startX = 0; var startY = 0; // 声明全局变量 元素初始坐标 var x = 0; var y = 0; div.addEventListener('touchstart' , function(e){ // 获取手指的初始坐标 startX = e.targetTouches[0].pageX; startY = e.targetTouches[0].pageY; // 获取元素的初始坐标 x = this.offsetLeft; y = this.offsetTop; }); div.addEventListener('touchmove' , function(e){ // 阻止默认的屏幕滚动事件 e.preventDefault(); // 计算手指的滑动距离:手指移动之后的坐标减去手指的初始坐标 var moveX = e.targetTouches[0].pageX - startX; var moveY = e.targetTouches[0].pageY - startY; // 移动元素:元素最终的坐标 = 元素初始的坐标 + 手指移动的距离 this.style.left = x + moveX + 'px'; this.style.top = y + moveY + 'px'; }); </script>
⑤ 移动端轮播图
【功能需求】
功能基本与 PC 端一致
- 额外添加手指可拖动轮播图的功能
【功能实现】
- 移动端可以不用考虑兼容性问题,故图片移动效果可使用 CSS3 的 translateX 来制作
- 修改元素类名: classList 返回元素所有类名 / classList.remove(‘类名’) 去掉某个类名 / classList.add(‘类名’) 追加一个类名 / classList.toggle(‘类名’) 类名有无的切换
【代码较长,请查看“移动端网页轮播图案例.js”文件,已做好注释】
⑥ 移动端 click 事件延时问题
【问题说明】移动端 click 事件会有300ms的延时,原因是移动端屏幕双击默认会缩放页面。
【解决方案】
- 禁用缩放:禁用浏览器默认的双击缩放行为即可去掉300ms的点击延迟
- 代码:
<meta name="viewport" content="user-scalable=no">
- 代码:
- 利用 touch 事件自行封装一个事件解决300ms延迟,原理就是:
- 第一步:当我们手指触摸屏幕,记录此刻的触摸时间
- 第二步:当我们手指离开屏幕,用离开的时间减去触摸的时间,得到间隔时间
- 第三步:如果间隔时间小于150ms,并且没有滑动过屏幕,那么我们就定义为点击
- 利用 fastclick 插件:GitHub官网地址 https://github.com/ftlabs/fastclick
⑦ 开源触摸滑动插件
【Swiper】https://www.swiper.com.cn
【SuperSlide】http://www.superslide2.com/
【iscroll】https://github.com/cubiq/iscroll
【使用方法】
- 确认插件实现的功能;
- 去官网查看使用说明;
- 下载插件;
- 打开demo实例文件,查看需要引入的相关文件,并且引入;
- 复制demo实例文件中的结构 html,css 样式以及 js 代码。
Storage 本地存储
1. 特性
- 数据存储在用户浏览器中;
- 设置、读取方便、甚至页面新都不会丢失数据;
- 容量较大,sessionStorage 约5M、localStorage 约20M;
只能存储字符串,可以将对象 JSON.stringify() 编码后存储。
2. window.sessionStorage
① 生命周期:关闭浏览器页面就结束(不是关闭浏览器,而是关闭标签页就结束)
② 共享范围:在同一页面下数据可共享
③ 存储形式:以键值对的形式存储使用
④ 使用方法【存储数据】
sessionStorage.setItem(key , value);
- 【获取数据】
sessionStorage.getItem(key);
- 【删除数据】
sessionStorage.removeItem(key);
-
3. window.localStorage
① 生命周期:永久生效,除非手动删除,否则关闭页面也不会消失
② 共享范围:同一浏览器的多个页面,数据都可共享
③ 存储方式:以键值对的形式存储使用
④ 使用方法 【存储数据】
localStorage.setItem(key , value);
- 【获取数据】
localStorage.getItem(key);
- 【删除数据】
localStorage.removeItem(key);
- 【清空数据】
localStorage.clear();
【案例】记住用户名
<body>
<input type="text" id="username">
<input type="checkbox" id="remember">记住用户名
</body>
<script>
var username = document.querySelector ('#username');
var remember = document.querySelector('#remember');
if ( localStorage.getItem('username') ){
username.value = localStorage.getItem('username');
remember.checked = true;
}
remember.addEventListener('change' , function(){
if ( this.checked ) {
localStorage.setItem('username' , username.value);
} else {
localStorage.removeItem('username');
}
}
</script>