JavaScript教程(二)
BOM浏览器对象模型
什么是BOM
- BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window;
- BOM由一系列相关的对象构成,并且每个对象都提供了很多方法与属性;
- BOM缺乏标准,JavaScript语法的标准化组织是ECMA,DOM的标准化组织是W3C,DOM最初是Netscape浏览器标准的一部分;
BOM的构成
- window对象是浏览器的顶级对象,它具有双重角色;
(1)、它是JS访问浏览器窗口的一个接口;
(2)、它是一个全局对象。定义在全局作用域中的变量、函数都会变成window对象的属性和方法;在调用的时候可以省略window,对话框alert()
prompt()
等就属于window对象方法;
注意:window下的一个特殊属性windw.name
var num=10;
console.log(num) // 10
console.log(window.num)// 10function fn(){console.log(111)
}
fn();
window.fn();
window对象的常见事件
1、窗口加载事件
window.onload=function(){}
或者
window.addEventListener('load',function(){})
window.onload
是窗口(页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS文件等),就调用的处理函数;
<script>window.onload=function(){var btn=document.querySelector('button');btn.addEventListener('click',function(){alert('111')})}
</script>
<button>点击</button>
- 注意:
(1)、有了window.onload
就可以把JS代码写到页面元素的上方,因为onload是等页面内容全部加载完毕,再去执行处理函数;
(2)、window.onload
【传统注册事件方式】只能写一次,如果有多个,会以最后一个window.onload
为准;
(3)、如果使用addEventListener
则没有限制;
//提倡写法(没有限制)
<script>
window.addEventListener('load',function(){var btn=document.querySelector('button');btn.addEventListener('click',function(){alert('111')})
})
</script>
<button>点击</button>
window.addEventListener('DOMContentLoaded',function(){})
DOMContentLoaded事件触发时,仅当DOM元素加载完成,不包括样式表、图片、flash等等(所以他的速度更快);IE9以上支持;如果页面的图片很多的话,从用户访问到onload触发可能需要较长的时间,交互效果就不能实现,必然影响用户体验,此时用DOMContentLoaded
事件比较合适;- 注意:
(1)、load
等页面内容全部加载完毕,包含页面dom元素、图片、flash、css等等;
(2)、DOMContentLoaded
是dom加载完毕,不包含图片、flash、css等就可以执行,加载速度比load
更快一些;
2、调整窗口大小事件
window.onresize=function(){};
window.addEventListener('resize',function(){});
window.onresize
是调整窗口大小加载事件,当触发时就调用的处理函数;- 注意:
(1)、只要窗口大小发生像素变化,就会触发这个事件;
(2)、我们经常利用这个事件完成响应式布局。window.innerWidth
当前屏幕的宽度;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>调整窗口大小事件</title><style>div {width: 200px;height: 100px;background-color: pink;}</style>
</head><body><script>window.addEventListener('load', function () { var div = document.querySelector('div')window.addEventListener('resize', function () {console.log(window.innerWidth);if (window.innerWidth <= 800) {div.style.display = 'none'} else {div.style.display = 'block'}})})</script><div></div>
</body></html>
定时器
- window对象提供了两种定时器:
setTimeout()
和setInterval()
setTimeout()
定时器
window.setTimeout(调用函数,[延迟的毫秒数])
这个window在调用的时候可以省略;setTimeout()
方法用于设置一个定时器,该定时器在定时器到期后执行调用函数;这个延时时间单位是毫秒,但是可以省略,如果省略默认的是0;- 这个调用函数可以直接写函数,还可以写函数名;还有一个写法
'函数名()'
function callback(){console.log(11)
}
setTimeout(callback,300)
setTimeout('callback()',300)//不提倡使用
- 页面中可以有很多定时器,我们经常给定时器加标识符(名字);
setTimeout()
这个调用函数我们也称为【回调函数 callback】;普通函数是按照代码顺序直接调用的,而这个函数,需要等待时间,时间到了才去调用这个函数,因此称为回调函数;
停止setTimeout()
定时器的window.clearTimeout(timeout ID)
window.clearTimeout(timeout ID)
取消了先前通过调用setTimeout()
建立的定时器;- window可以省略;
- 括号里面的参数就是定时器的标识符;
setInterval('回调函数',间隔的毫秒数)
定时器
setInterval()
方法重复调用一个函数,每隔这个时间,就去调用一次回调函数;
注意:
(1)、setTimeout()
延时时间到了,就去调用这个回调函数,只调用一次,就结束了这个定时器;
(2)、setInterval()
每隔这个延时时间,就去调用这个回调函数,会调用很多次,重复调用这个函数;
案例:倒计时案例
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>倒计时案例</title><style>div {width: 150px;height: 50px;color: aliceblue;display: flex;justify-content: space-around;}.hour,.minute,.second {width: 40px;height: 40px;line-height: 40px;text-align: center;background-color: black;}</style>
</head><body><div><span class="hour">1</span><span class="minute">2</span><span class="second">3</span></div><script>// 1、获取元素var hour = document.querySelector('.hour');var minute = document.querySelector('.minute');var second = document.querySelector('.second');/*注意:第一次执行也是间隔毫秒数,因此刚刷新页面会有空白;最好采取封装函数的方式,这样可以先调动一次这个函数,防止刚开始刷新页面有空白问题;*/countDown()// 2、开启定时器setInterval(countDown, 1000);var inputTime = +new Date('2023-7-6 11:00:00');//返回的是用户输入时间总的毫秒数function countDown() {var nowTime = +new Date(); //返回的是当前时间总的毫秒数 var times = (inputTime - nowTime) / 1000;//times是剩余时间总的秒数 var h = parseInt(times / 60 / 60 % 24);//小时//h = h < 10 ? '0' + h : h;console.log(h);hour.innerHTML = h;//把剩余的小时给,小时黑色盒子var m = parseInt(times / 60 % 60);m = m < 10 ? '0' + m : m;minute.innerHTML = m;var s = parseInt(times % 60);s = s < 10 ? '0' + s : s;second.innerHTML = s;}</script>
</body></html>
clearInterval
清除定时器
window.clearInterval(intervalID)
clearInterval
方法取消了先前通过调用setInterval()
建立的定时器;- 注意:
window
可以省略;里面的参数就是定时器的标识符;
<body><button class="begin">开启</button><button class="stop">停止</button><script>var begin = document.querySelector('.begin');var stop = document.querySelector('.stop');var timer = null //全局变量,null是一个空对象,如果不赋初始值容易报undefined错;(注意:将timer定义为全局变量,使下面的函数内部都能访问)begin.addEventListener('click', function () {timer = setInterval(function () {console.log('你好哇');}, 1000)})stop.addEventListener('click', function () {clearInterval(timer)})</script>
</body>
案例:发送短信案例(点击按钮之后,该按钮60秒之内不能再次点击,防止重复发送短信)
<body><!-- 点击按钮之后,该按钮60秒之内不能再次点击,防止重复发送短信 -->手机号:<input type="number"> <button>发送</button><script>var btn = document.querySelector('button');var time = 3; //定义剩下的秒数btn.addEventListener('click', function () {btn.disabled = true;var timer = setInterval(function () {if (time == 0) {// 清除定时器和复原按钮clearInterval(timer)btn.disabled = false;btn.innerHTML = '发送';time = 3; //这个3需要重新开始} else {btn.innerHTML = '还剩下' + time + '秒';time--;}}, 1000)})</script>
</body>
this
指向问题
this
的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this
到底指向谁,一般情况下this
的最终指向的是那个调用它的对象;- 1、全局作用域 或者 普通函数中this指向 【全局对象 window(浏览器顶级对象 window)】(注意定时器里面的this指向 window);
console.log(this);
function fn() {console.log(this);
}
fn() //其实是 window.fn() 调用,省略了window
- 2、方法调用中谁调用this指向谁;
var o = {sayHi: function () {console.log(this); //this指向的是 o 这个对象 {sayHi: ƒ} }
}
o.sayHi()
- 3、构造函数中this指向构造函数实例;
function Fun(){console.log(this);//this 指向的是fun 实例对象 Fun {}
}
var fun=new Fun();
JS执行队列
- JS是单线程。JavaScript 语言的一大特点就是【单线程】,也就是说,同一个时间只能做一件事。这是因为JavaScript 这门脚本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作DOM而诞生的。比如我们对某个DOM元素进行添加和删除操作,不能同时进行,应该先进行添加,之后再删除;单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是:如果JS执行的时间过长,这样就会造成页面渲染不连贯,导致页面渲染加载阻塞。
- 为了解决这个问题,利用多核CPU的计算能力,HTML5 提出 Web Worker 标准,允许JavaScript 脚本创建多个线程。于是,JS中出现了同步和异步。
同步和异步
- 同步:前一个任务结束后再执行后一个任务,程序的执行顺序和任务的排列顺序是一致的、同步的。
- 异步:在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,还可以去处理其他事情;
- 它们的本质区别:这条流水线上各个流程的执行顺序不同;
- 同步任务:同步任务都在主线程执行,形成一个【执行栈】。
- 异步任务:JS的异步是通过【回调函数】实现的。一般而言,异步任务有以下三种类型:
(1)、普通事件,如:click
resize
等;
(2)、资源加载,如:load
error
等;
(3)、定时器,包括:setInterval
setTimeout
等;
异步任务相关【回调函数】添加到【任务队列】中(任务队列也称为【消息队列】) - JS执行机制:
(1)、先执行执行栈中的同步任务;
(2)、遇到异步任务时,将异步任务(回调函数)放入任务队列中;
(3)、一旦执行栈中所有同步任务执行完毕,系统就会按次序读取 任务队列 中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行;
- 由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环(event loop)。
location
对象
window
对象给我们提供了一个location
属性用于获取或设置窗体的URL
,并且可以用于解析URL
,因为这个属性返回的是一个对象,所以我们将这个属性也称为location
对象;URL
:统一资源定位符(Uniform Resource Locator
)是互联网上标准的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。
location
对象的属性
- 重点记住:
href
和search
<body><button>点击</button><script>var btn=document.querySelector('button');btn.addEventListener('click',function(){console.log(window.location.href);//此处的window一般省略不写location.href='https://www.baidu.com/' //点击跳转页面})</script>
</body>
案例:5秒钟之后自动跳转页面
<body><button>点击</button><div></div><script>var btn = document.querySelector('button');var div = document.querySelector('div');// btn.addEventListener('click',function(){//console.log(window.location.href);//此处的window可以省略// location.href='https://www.baidu.com/'// })var time = 5;function fun() {if (time == 0) {location.href = 'https://www.baidu.com/'} else {div.innerHTML = '你将在' + time + '秒钟之后跳转到首页'time--}}fun() setInterval(fun, 1000)</script>
</body>
案例:获取URL参数数据(主要练习数据在不同页面中的传递)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>登录页</title>
</head><body><form action="index.html">用户名:<input type="text" name="uname"><input type="submit" value="登录"></form>
</body></html>
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>首页</title>
</head><body><h3>首页</h3><div></div><script>console.log(location.search);// ?uname=输入的用户名// 1、先去掉? substr('起始的位置',截取几个字符)var params = location.search.substr(1);//从下标为1的字符开始截取,截取到最后一位console.log(params); //uname=输入的用户名// 2、利用 = 把字符串分割为数组 split('=')var arr = params.split('=')console.log(arr);//['uname', '输入的用户名']var div=document.querySelector('div');// 3、把数据写入div中div.innerHTML=arr[1]+'欢迎你'</script>
</body></html>
location
常见方法
navigator
对象
navigator
对象包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent
,该属性可以返回由客户机发送服务器的user-agent
头部的值。
history
对象
window
对象给我们提供了一个history
对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL。
history
对象一般在实际开发中比较少用,但是会在一些OA办公系统中见到;
PC端网页特效
元素偏移量offset
系列
offsetLeft
和offsetTop
获取元素偏移
offset
翻译过来就是偏移量,我们使用offset
系列相关属性可以动态的得到该元素的位置(偏移)、大小等;- 获得元素距离带有定位父元素的位置;
- 获得元素自身的大小(宽度高度);
- 注意:返回的数值都不带单位;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>offset系列属性</title><style>body,html {margin: 0;padding: 0;}.father {width: 200px;height: 200px;background-color: pink;margin: 150px;}.son {width: 100px;height: 100px;background-color: purple;margin-left: 45px;}</style>
</head><body><div class="father"><div class="son"></div></div><script>// offset系列var father = document.querySelector('.father');var son = document.querySelector('.son');// 可以得到元素的 偏移 位置 返回的不带单位的数值 (记得设置body的margin为0)console.log(father.offsetTop);//150 (margin: 100px;)console.log(father.offsetLeft);//150 (margin: 100px;)// 它以带有定位的父元素为准,如果没有父亲或者父亲没有定位,则以 body 为准;console.log(son.offsetLeft);// 195 (父元素的 margin 值 + 子元素的 margin 值) // 可以得到元素的 大小 宽度 和 高度</script>
</body></html>
offsetWidth
和offsetHeight
获取元素大小
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>offset系列属性</title><style>body,html {margin: 0;padding: 0;} .w{width: 200px;height: 200px;background-color: skyblue;margin: 0 auto 200px;}</style>
</head><body><div class="w"></div><script> // 可以得到元素的大小 宽度 和 高度(是包含 border + padding + width)console.log(w.offsetWidth);//200 (因为盒子的宽高是200 200)console.log(w.offsetHeight);//200</script>
</body></html>
offsetParent
返回带有定位的父亲,否则返回的是body
// 返回带有定位的父亲,否则返回的是body
console.log(son.offsetParent);//如果son的父元素开了定位,就返回其父元素;没有开定位,就返回body
console.log(son.parentNode);//返回父亲,是最近一级的父亲,不管父亲有没有定位
offset
与style
的区别
案例:获取鼠标在盒子内的坐标
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>获取鼠标在盒子内的坐标</title><style>.box {width: 200px;height: 200px;background-color: pink;}</style>
</head><body><!-- 案例分析:1、我们在盒子内点击,想要得到鼠标距离盒子左右的距离;2、首先得到鼠标在页面中的坐标(e.pageX,e.pageY);3、其次得到盒子在页面中的距离(box.offsetLeft,box.offsetTop);4、用鼠标距离页面的坐标减去盒子在页面中的距离,得到 鼠标在盒子内的坐标;5、补充:如果想要移动一下鼠标,就要获取最新的坐标,使用鼠标移动事件 mousemove ;--><div class="box"></div><script>var box = document.querySelector('.box');box.addEventListener('mousemove', function (e) {console.log(e.pageX);console.log(e.pageY);var x = e.pageX - this.offsetLeft;var y = e.pageY - this.offsetTop;this.innerHTML = 'x坐标是' + x + 'y坐标是' + y})</script>
</body></html>
案例:模态框拖拽
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>模态框拖拽</title><style>h6,a {padding: 0;margin: 0;}.login {display: none;width: 512px;height: 280px;position: fixed;border: #ebebeb solid 1px;left: 50%;top: 50%;background: #ffffff;box-shadow: 0px 0px 20px #ddd;z-index: 9999;transform: translate(-50%, -50%);}.login-title {width: 100%;margin: 10px 0px 0px 0px;text-align: center;line-height: 40px;height: 40px;font-size: 18px;position: relative;cursor: move;}.login-input-content {margin-top: 20px;}.login-button {width: 50%;margin: 30px auto 0px auto;line-height: 40px;font-size: 14px;border: #ebebeb 1px solid;text-align: center;}.login-bg {display: none;width: 100%;height: 100%;position: fixed;top: 0px;left: 0px;background: rgba(0, 0, 0, .3);}a {text-decoration: none;color: #000000;}.login-button a {display: block;}.login-input input .list-input {float: left;line-height: 35px;height: 35px;width: 350px;border: #ebebeb 1px solid;text-indent: 5px;}.login-input {overflow: hidden;margin: 0px 0px 20px 0px;}.login-input label {float: left;width: 90px;padding-right: 10px;text-align: right;line-height: 35px;height: 35px;font-size: 14px;}.login-title span {position: absolute;font-size: 12px;right: -20px;top: -30px;background: #ffffff;border: #ebebeb solid 1px;width: 40px;height: 40px;border-radius: 20px;}</style>
</head><body><!-- 案例分析:弹出框,我们也称为模态框1、点击弹出层,会弹出模态框,并且显示灰色半透明的遮挡层;2、点击关闭按钮,可以关闭模态框,并且同时关闭灰色半透明遮挡层;3、鼠标放到模态框最上面一行,可以按住鼠标拖拽模态框在页面中移动;4、鼠标松开,可以停止拖动模态框移动;5、在页面中拖拽的原理:鼠标按下并且移动,之后松开鼠标;6、触发事件是 鼠标按下:mousedown,鼠标移动:mousemove,鼠标松开:mouseup;7、拖拽过程:鼠标移动过程中,获得最新的值赋给模态框的 left 和 top 值,这样模态框可以跟着鼠标走了;8、鼠标按下触发的事件源是 最上面一行,就是 id 为 title;9、鼠标的坐标 减去 鼠标在盒子内的坐标,才是模态框真正的位置;10、鼠标按下,我们要得到鼠标在盒子内的坐标;11、鼠标移动,就让模态框的坐标 设置为:鼠标坐标减去盒子坐标即可,注意:移动事件写到按下事件里面;--><div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div><div id="login" class="login"><div id="title" class="login-title">登录会员<span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span></div><div class="login-input-content"><div class="login-input"><label for="">用户名:</label><input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="username"></div><div class="login-input"><label for="">登录密码:</label><input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="password"></div></div><div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit"></a></div></div><!-- 遮盖层 --><div id="bg" class="login-bg"></div><script>// 1、获取元素var login = document.querySelector('.login');var mask = document.querySelector('.login-bg');var link = document.querySelector('#link');var closeBtn = document.querySelector('#closeBtn');var title = document.querySelector('#title');// 2、点击弹出层这个链接 link,让 mask 和 login 显示出来;link.addEventListener('click', function () {mask.style.display = 'block';login.style.display = 'block';})// 3、点击 closeBtn 就隐藏 mask 和 login;closeBtn.addEventListener('click', function () {mask.style.display = 'none';login.style.display = 'none';})// 4、开始拖拽// (1)、当我们鼠标按下,就获得鼠标在盒子内的坐标;title.addEventListener('mousedown', function (e) {console.log('111');var x = e.pageX - login.offsetLeft;var y = e.pageY - login.offsetTop;// (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值document.addEventListener('mousemove', move)function move(e) {login.style.left = e.pageX - x + 'px';login.style.top = e.pageY - y + 'px';}// (3) 鼠标弹起,就让鼠标移动事件移除document.addEventListener('mouseup', function () {document.removeEventListener('mousemove', move);})})</script>
</body></html>
案例:仿京东放大镜效果
/*案例分析:1、鼠标经过小图片盒子,黄色的遮挡层 和 大图片盒子显示,离开隐藏2个盒子功能;2、把鼠标坐标给遮挡层不合适,因为遮挡层坐标以父盒子为准;3、首先是获得鼠标在盒子的坐标;4、之后把数值给遮挡层作为 left 和 top 值;5、遮挡层不能超出小图片盒子的范围;6、如果小于0,就把坐标设置为0;7、如果大于遮挡层最大的移动距离,就把坐标设置为最大的移动距离;8、遮挡层的最大移动距离:小图片盒子宽度 减去 遮挡层盒子宽度;
*/
// 入口函数,让当页面上的布局加载完再加载动画效果
window.addEventListener('load', function () {var preview_img = document.querySelector('.preview_img');var mask = this.document.querySelector('.mask');var big = this.document.querySelector('.big');var bigImg = this.document.querySelector('.bigImg');// 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)、减去盒子高度300的一半 是 150,就是我们 mask 的最终 left 和 top 了;此处 mask 的 left 和 top 不写死,防止盒子宽度发生变化;// (3)、我们 mask 移动的距离var maskX = x - mask.offsetWidth / 2;var maskY = y - mask.offsetHeight / 2;// (4)、如果x坐标小于了0,就让他停在0的位置;// 遮挡层的最大移动距离(正方形,宽高相等);var maskMax = preview_img.offsetWidth - mask.offsetWidth;if (maskX <= 0) {maskX = 0} else if (maskX >= maskMax) {maskX = maskMax}if (maskY <= 0) {maskY = 0} else if (maskY >= maskMax) {maskY = maskMax}mask.style.left = maskX + 'px';mask.style.top = maskY + 'px';// 大图片的移动距离,遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离// 大图片最大移动距离var bigMax = bigImg.offsetWidth - big.offsetWidth;// 大图片的移动距离 X Y(注意:需要给图片加上定位,否则无法实现移动)var bigX = maskX * bigMax / maskMax;var bigY = maskY * bigMax / maskMax;bigImg.style.left = -bigX + 'px';bigImg.style.top = -bigY + 'px';})
})
元素可视区client
系列
client
翻译过来就是客户端,我们使用client
系列的相关属性来获取元素可视区的相关信息。通过client
系列的相关属性可以动态的得到该元素的边框大小、元素大小等;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>元素可视区client系列</title><style>div {width: 200px;height: 200px;background-color: pink;border: 10px solid red; /* 不包含 border */padding: 10px; /* 包含 padding */}</style>
</head><body><div></div><script>//client 宽度 和 我们 offsetWidth 最大的区别就是 不包含边框;var div = document.querySelector('div');console.log(div.clientWidth);//220 包含padding </script>
</body></html>
案例:淘宝flexible.js
源码分析
立即执行函数
- 立即执行函数:不需要调用,立马能够自己执行的函数;
- 也可以传递多个参数进来;
- 如果有多个立即执行函数,结尾要用分号分隔开;
- 立即执行函数最大的作用就是,独立创建了一个作用域;里面所有的变量都是局部变量,不会有命名冲突的情况;
<script>//2、立即执行函数写法// 写法一:(function () { })();// 写法二:(function () { }());(function(){console.log(2);})(); //第二个小括号可以看作是调用函数(function(a){console.log(a);//1})(1) ;(function (a, b) {console.log(a + b);//1var num = 10;//num是一个局部变量})(1, 2); //3</script>
pageshow
和 load
事件分析
- 下面3种情况都会刷新页面都会触发
load
事件:
(1)、a
标签的超链接;
(2)、F5或者刷新按钮(强制刷新);
(3)、前进、后退按钮; - 但是,火狐中有个特点,有个“往返缓存”,这个缓存中不仅保存着页面数据,还保存了
DOM
和JavaScript
的状态;实际上是将整个页面都保存在了内存里;所以,此时后退按钮不能刷新页面; - 此时可以使用
pageshow
事件来触发,这个事件在页面显示时触发,无论页面是否来自缓存。在重新加载页面中,pageshow
会在load
事件触发后触发;根据事件对象中的persisted
来判断是否是缓存中的页面触发的pageshow
事件,注意这个事件给window
添加;
(function flexible(window, document) {// 获取的html 的根元素var docEl = document.documentElement// dpr 物理像素比var dpr = window.devicePixelRatio || 1// adjust body font size 设置我们body 的字体大小function setBodyFontSize() {// 如果页面中有body 这个元素 就设置body的字体大小if (document.body) {document.body.style.fontSize = (12 * dpr) + 'px'} else {// 如果页面中没有body 这个元素,则等着 我们页面主要的DOM元素加载完毕再去设置body// 的字体大小document.addEventListener('DOMContentLoaded', setBodyFontSize)}}setBodyFontSize();// set 1rem = viewWidth / 10 设置我们html 元素的文字大小function setRemUnit() {var rem = docEl.clientWidth / 10 //将屏幕大小划分成10等份docEl.style.fontSize = rem + 'px'}setRemUnit()// reset rem unit on page resize 当我们页面尺寸大小发生变化的时候,要重新设置下rem 的大小window.addEventListener('resize', setRemUnit)// pageshow 是我们重新加载页面触发的事件window.addEventListener('pageshow', function(e) {// e.persisted 返回的是true 就是说如果这个页面是从缓存取过来的页面,也需要从新计算一下rem 的大小if (e.persisted) {setRemUnit()}})// detect 0.5px supports 有些移动端的浏览器不支持0.5像素的写法if (dpr >= 2) {var fakeBody = document.createElement('body')var testElement = document.createElement('div')testElement.style.border = '.5px solid transparent'fakeBody.appendChild(testElement)docEl.appendChild(fakeBody)if (testElement.offsetHeight === 1) {docEl.classList.add('hairlines')}docEl.removeChild(fakeBody)}
}(window, document))
元素滚动scroll
系列
scroll
翻译过来就是滚动,我们使用scroll
系列的相关属性可以动态的得到该元素的大小、滚动距离等等;scroll
是自身实际内容的大小;如一个div
内内容比较多,超出盒子高度,返回的是实际内容的大小;
页面被卷去的头部
- 如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。滚动条在滚动时会触发
onscroll
事件。
案例:仿淘宝固定右侧侧边栏
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>仿淘宝固定右侧侧边栏</title><style>.slider-bar {position: absolute;left: 50%;top: 300px;margin-left: 600px;width: 45px;height: 130px;background-color: pink;}.w {width: 1200px;margin: 10px auto;}.header {height: 150px;background-color: purple;}.banner {height: 250px;background-color: skyblue;}.main {height: 1000px;background-color: yellowgreen;}span {display: none;position: absolute;bottom: 0;}</style>
</head><body><!-- 案例分析:1、原先侧边栏是绝对定位;2、当页面滚动到一定位置,侧边栏改为固定定位;3、页面继续滚动,会让返回顶部显示出来;4、需要用到页面滚动事件 scroll,因为是页面滚动,所以事件源是 document;5、滚动到某个位置,就是判断页面被卷去的上部值;6、页面被卷去的头部,可以通过 window.pageYOffset 获得;如果是被卷去的左侧 window.pageXOffset;7、元素被卷去的头部是:element.scrollTop;如果是页面被卷去的头部则是:window.pageYOffset;--><div class="slider-bar"><span class="goBack">返回顶部</span></div><div class="header w">头部区域</div><div class="banner w">banner区域</div><div class="main w">主体部分</div><script>// 1、获取元素var sliderbar = document.querySelector('.slider-bar');var banner = document.querySelector('.banner');console.log(banner.offsetTop);// banner.offsetTop 就是被卷去头部的大小,一定要写到滚动的外面;var bannerTop = banner.offsetTop;//当我们侧边栏固定定位之后应该变化的数值; var sliderbarTop = sliderbar.offsetTop - bannerTop;var main = document.querySelector('.main');var goBack = document.querySelector('.goBack');var mainTop = main.offsetTop;// 2、页面滚动事件 scrolldocument.addEventListener('scroll', function () {// 3、当页面被卷去的头部大于等于了 172 时,侧边栏就要改为固定定位;if (window.pageYOffset >= bannerTop) {sliderbar.style.position = 'fixed';sliderbar.style.top = sliderbarTop + 'px';} else {sliderbar.style.position = 'absolute';sliderbar.style.top = '300px';}// 4、当页面滚动到main盒子,就显示 goBack 模块;if (window.pageYOffset >= bannerTop) {goBack.style.display = 'block';} else {goBack.style.display = 'none';}})</script>
</body></html>
三大系列总结
offset
系列经常用于获得元素位置offsetLeft
offsetTop
;client
经常用于获取元素大小clientWidth
clientHeight
;scroll
经常用于获取滚动距离scrollTop
scrollLeft
;- 注意:页面滚动的距离通过
window.pageXOffset
获得;
mouseenter
和mouseover
的区别
- 当鼠标移动到元素上时,就会触发
mouseenter
事件; - 类似
mouseover
,它们两者之间的差别是: mouseover
鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter
只会经过自身盒子触发;- 之所以这样,就是因为
mouseenter
不会冒泡; - 跟
mouseenter
搭配mouseleave
同样不会冒泡;
动画函数封装
动画实现原理
- 核心原理:通过定时器
setInterval()
不断移动盒子位置;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>动画原理</title><style>div {position: absolute;left: 0;width: 100px;height: 100px;background-color: pink;}</style>
</head><body><!-- 实现步骤:(1)、获得盒子当前位置;(2)、让盒子在当前位置加上1个移动距离;(3)、利用定时器不断重复这个操作;(4)、加一个结束定时器的条件;(5)、注意此元素需要添加定位,才能使用`element.style.left`;--><div></div><script>var div = document.querySelector('div')var timer = setInterval(function () {if (div.offsetLeft >= 400) {// 停止定时器clearInterval(timer)}div.style.left = div.offsetLeft + 1 + 'px';}, 30)</script>
</body></html>
动画函数简单封装
- 注意:函数需要传递2个参数,【动画对象】和【移动到的距离】;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>动画原理</title><style>div {position: absolute; /* 一定要加定位,否则动画不生效 */ left: 0;width: 100px;height: 100px;background-color: pink;}</style>
</head><body><!-- 实现步骤:(1)、获得盒子当前位置;(2)、让盒子在当前位置加上1个移动距离;(3)、利用定时器不断重复这个操作;(4)、加一个结束定时器的条件;(5)、注意此元素需要添加定位,才能使用`element.style.left`;--><div></div><script>// 简单动画函数封装,obj 目标对象;target 目标位置;function animate(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');animate(div, 300);</script>
</body></html>
动画函数给不同元素记录不同定时器
- 如果多个元素都使用这个动画函数,每次都要
var
声明定时器,我们可以给不同的元素使用不同的定时器(自己专门用自己的定时器); - 核心原理:利用js是一门动态语言,可以很方便的给当前对象添加属性;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>动画原理</title><style>div {position: absolute;/* 一定要加定位,否则动画不生效 */ top: 50px; left: 0;width: 100px;height: 100px;background-color: pink;}</style>
</head><body><!-- 实现步骤:(1)、获得盒子当前位置;(2)、让盒子在当前位置加上1个移动距离;(3)、利用定时器不断重复这个操作;(4)、加一个结束定时器的条件;(5)、注意此元素需要添加定位,才能使用`element.style.left`;--><div></div><button>点击开始行走</button><script>// var obj = {};// obj.name = 'andy';// 简单动画函数封装,obj 目标对象;target 目标位置;function animate(obj, target) {// 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器;// 解决方案就是:让元素只有一个定时器执行;// 先清除以前的定时器,只保留当前的一个定时器执行;clearInterval(obj.timer);//var timer = setInterval(function () { //优化之前的写法obj.timer = setInterval(function () { //优化后:不用var声明变量也就不用去内存中重新开辟空间了;给不同的元素指定了不同的定时器if (obj.offsetLeft >= target) {// 停止定时器clearInterval(timer);} else {obj.style.left = obj.offsetLeft + 1 + 'px';}}, 30)}var div = document.querySelector('div');var btn = document.querySelector('button');// 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器;// 解决方案就是:让元素只有一个定时器执行; 先清除以前的定时器,只保留当前的一个定时器执行;btn.addEventListener('click', function () {animate(div, 300);})</script>
</body></html>
缓动效果原理
- 缓动动画就是让元素运动速度有所变化,最常见的就是让速度慢慢停下来;
- 思路:
(1)、让盒子每次移动的距离慢慢变小,速度就会慢慢落下来;
(2)、核心算法:(目标值 - 现在的位置) / 10 作为每次移动的距离(即步长);
(3)、停止的条件是:让当前盒子位置等于目标位置就停止定时器;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>缓动动画</title><style>div {/* 一定要加定位,否则动画不生效 */position: absolute;top: 50px;left: 0;width: 100px;height: 100px;background-color: pink;}</style>
</head><body><div></div><button>点击开始行走</button><!-- 思路:(1)、让盒子每次移动的距离慢慢变小,速度就会慢慢落下来;(2)、核心算法:(目标值 - 现在的位置) / 10 作为每次移动的距离(即步长);(3)、停止的条件是:让当前盒子位置等于目标位置就停止定时器;--><script>function animate(obj, target) {clearInterval(obj.timer);obj.timer = setInterval(function () {// 步长值写到定时器的里面var step = (target - obj.offsetLeft) / 10;if (obj.offsetLeft == target) {clearInterval(timer);} else {// 把每次加1 这个步长值改为一个慢慢变小的值,步长公式:(目标值 - 现在的位置) / 10obj.style.left = obj.offsetLeft + step + 'px';}}, 15)}var div = document.querySelector('div');var btn = document.querySelector('button');btn.addEventListener('click', function () {animate(div, 500);})//匀速动画:盒子当前的位置 + 固定的值// 缓动动画:盒子当前的位置 + 变化的值 【(目标值 - 现在的位置) / 10】</script>
</body></html>
缓动动画多个目标值之间移动
- 可以让动画函数从800移动到500;
- 当我们点击按钮时,判断步长是正直还是负值;
1、如果是正值,则步长往大了取整;
2、如果是负值,则步长向小了取整;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>缓动动画</title><style>div {/* 一定要加定位,否则动画不生效 */position: absolute;top: 80px;left: 0;width: 100px;height: 100px;background-color: pink;}</style>
</head><body><div></div><button class="btn500">点击开始行走500</button><button class="btn800">点击开始行走800</button><!-- 思路:(1)、让盒子每次移动的距离慢慢变小,速度就会慢慢落下来;(2)、核心算法:(目标值 - 现在的位置) / 10 作为每次移动的距离(即步长);(3)、停止的条件是:让当前盒子位置等于目标位置就停止定时器;(4)、注意步长值需要取整;--><script>function animate(obj, target) {clearInterval(obj.timer);obj.timer = setInterval(function () {// 步长值写到定时器的里面;把步长值改为整数,不要出现小数问题;//var step = Math.ceil((target - obj.offsetLeft) / 10);var step = (target - obj.offsetLeft) / 10;step = step > 0 ? Math.ceil(step) : Math.floor(step);if (obj.offsetLeft == target) {clearInterval( obj.timer);} else {// 把每次加1 这个步长值改为一个慢慢变小的值,步长公式:(目标值 - 现在的位置) / 10obj.style.left = obj.offsetLeft + step + 'px';}}, 15)}var div = document.querySelector('div');var btn500 = document.querySelector('.btn500');var btn800 = document.querySelector('.btn800');btn500.addEventListener('click', function () {animate(div, 500);})btn800.addEventListener('click', function () {animate(div, 800);})//匀速动画:盒子当前的位置 + 固定的值;//缓动动画:盒子当前的位置 + 变化的值 【(目标值 - 现在的位置) / 10】;</script>
</body></html>
缓动动画添加回调函数
- 回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调;
- 回调函数写到定时器结束里面;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>缓动动画</title><style>div {/* 一定要加定位,否则动画不生效 */position: absolute;top: 80px;left: 0;width: 100px;height: 100px;background-color: pink;}</style>
</head><body><div></div><button class="btn500">点击开始行走500</button><button class="btn800">点击开始行走800</button><!-- 思路:(1)、让盒子每次移动的距离慢慢变小,速度就会慢慢落下来;(2)、核心算法:(目标值 - 现在的位置) / 10 作为每次移动的距离(即步长);(3)、停止的条件是:让当前盒子位置等于目标位置就停止定时器;(4)、注意步长值需要取整;--><script>function animate(obj, target, callback) {console.log(callback); // callback = function(){} 调用的时候 callback()clearInterval(obj.timer);obj.timer = setInterval(function () {// 步长值写到定时器的里面;把步长值改为整数,不要出现小数问题;//var step = Math.ceil((target - obj.offsetLeft) / 10);var step = (target - obj.offsetLeft) / 10;step = step > 0 ? Math.ceil(step) : Math.floor(step);if (obj.offsetLeft == target) {clearInterval(obj.timer);// 回调函数写到定时器结束里面if (callback) {// 调用函数callback();}} else {// 把每次加1 这个步长值改为一个慢慢变小的值,步长公式:(目标值 - 现在的位置) / 10obj.style.left = obj.offsetLeft + step + 'px';}}, 15)}var div = document.querySelector('div');var btn500 = document.querySelector('.btn500');var btn800 = document.querySelector('.btn800');btn500.addEventListener('click', function () {animate(div, 500);})btn800.addEventListener('click', function () {animate(div, 800, function () {div.style.backgroundColor = 'red';});})//匀速动画:盒子当前的位置 + 固定的值;//缓动动画:盒子当前的位置 + 变化的值 【(目标值 - 现在的位置) / 10】;</script>
</body></html>
动画函数的使用
- 动画函数封装到单独js文件里面:因为以后经常使用这个动画函数,可以单独封装到一个js文件里面,使用的时候引用这个js文件即可;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>引用animate动画函数</title><style>.sliderbar {position: fixed;right: 0;bottom: 100px;width: 40px;height: 40px;text-align: center;line-height: 40px;cursor: pointer;color: #fff;}.con {position: absolute;left: 0;top: 0;width: 200px;height: 40px;background-color: purple;z-index: -1;}</style><script src="54.animate.js"></script>
</head><body><div class="sliderbar"><span>←</span><div class="con">问题反馈</div></div><script>/*1、当我们鼠标经过 sliderbar ,就会让 con 这个盒子滑动到左侧;2、当我们鼠标离开 sliderbar,就会让 con 这个盒子滑动到右侧;*/var sliderbar = document.querySelector('.sliderbar');var con = document.querySelector('.con');sliderbar.addEventListener('mouseenter', function () {animate(con, -160, function () {// 当动画执行完毕,就把 ← 改为 →sliderbar.children[0].innerHTML = '→';});})sliderbar.addEventListener('mouseleave', function () {animate(con, 0, function () {// 当动画执行完毕,就把 ← 改为 →sliderbar.children[0].innerHTML = '←';});})</script>
</body></html>
网页轮播图
- 轮播图也称为焦点图;
- 功能需求:
(1)、鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮;
(2)、点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理;
(3)、图片播放的同时,下面小圆圈模块跟随一起变化;
(4)、点击小圆圈,可以播放相应图片;
(5)、鼠标不经过轮播图,轮播图也会自动播放图片;
(6)、鼠标经过轮播图模块,自动播放停止; - 动态生成小圆圈:
(1)、核心思路:小圆圈的个数要跟图片张数一致;
(2)、所以首先先得到ul里面图片的张数(图片放入li里面,所以就是li的个数);
(3)、利用循环动态生成小圆圈(这个小圆圈要放入ol里面);
(4)、创建节点createElement('li')
;
(5)、插入节点ol.appendChild(li)
; - 小圆圈的排他思想:
(1)、点击当前小圆圈,就添加current
类;
(2)、其余的小圆圈,就移除current
类;
(3)、注意:我们在刚才生成小圆圈的同时,就可以直接绑定这个点击事件了; - 点击小圆圈滚动图片:
(1)、此时用到animate.js
动画函数,将js
文件引入。(注意:因为index.js
依赖animate.js
,所以,引入时animate.js
要写到index.js
上面);
(2)、使用动画函数的前提,该元素必须有定位;
(3)、注意是ul
移动,而不是li
;
(4)、滚动图片的核心算法:点击某个小圆圈,就让图片滚动 【小圆圈的索引号 x 图片的宽度】作为ul
移动距离;
(5)、此时需要知道小圆圈的索引号:我们可以在生成小圆圈的时候,给他设置一个自定义属性,点击的时候获取这个自定义属性即可; - 点击右侧按钮一次,就让图片滚动一次:
(1)、声明一个变量num
,点击一次,自增1,让这个变量乘以图片宽度,就是ul的滚动距离; - 图片无缝滚动原理:
(1)、把ul
第一个li
复制一份,放到ul
的最后面;
(2)、当图片滚动到克隆的最后一张图片时,让ul
快速的、不做动画的跳到最左侧,即left=0
;
(3)、同时num
赋值为0,可以从新开始滚动图片了; - 克隆第一张图片:
(1)、克隆ul
第一个li
,cloneNode()
加true
就是深克隆,复制里面的子节点;false
浅克隆;
(2)、添加到ul
最后面appendChild
; - 点击右侧按钮,小圆圈跟随变化:
(1)、最简单的做法是再声明一个变量circle
,每次点击自增1;注意:左侧按钮也需要这个变量,因此要声明全局变量;
(2)、但是,图片有5张,我们小圆圈只有4个少一个,必须加一个判断条件;
(3)、如果circle == 4
,就重新复原为0; - 自动播放功能:
(1)、添加一个定时器;
(2)、自动播放轮播图,实际就类似于点击了右侧按钮;
(3)、此时我们使用【手动调用】右侧按钮点击事件arrow_r.click()
;
(4)、鼠标经过focus
就停止定时器;
(5)、鼠标离开focus
就开启定时器;
window.addEventListener('load', function () {// 1、获取元素var arrow_l = this.document.querySelector('.arrow-l');var arrow_r = this.document.querySelector('.arrow-r');var focus = this.document.querySelector('.focus');var focusWidth = focus.offsetWidth;// 2、鼠标经过 focus,就显示隐藏左右按钮; focus.addEventListener('mouseenter', function () {arrow_l.style.display = 'block';arrow_r.style.display = 'block';clearInterval(timer);timer = null;//清除定时器bianl})focus.addEventListener('mouseleave', function () {arrow_l.style.display = 'none';arrow_r.style.display = 'none';timer = setInterval(function () {// 手动调用点击事件arrow_r.click();}, 2000)})// 3、动态生成小圆圈,有几张图,我就生成几个小圆圈;var ul = focus.querySelector('ul'); // 获取 focus 里面的 ul;var ol = focus.querySelector('.circle');// console.log(ul.children.length);for (var i = 0; i < ul.children.length; i++) {// 创建一个小 livar li = document.createElement('li');// 记录当前小圆圈的索引号,通过自定义属性来做;li.setAttribute('index', i);// 把小li插入到ol里面ol.appendChild(li);// 4、小圆圈的排他思想 我们可以直接在生成小圆圈的同时直接绑定点击事件li.addEventListener('click', function () {// 干掉所有人 把所有的小li 清除 current 类名for (var i = 0; i < ol.children.length; i++) {ol.children[i].className = '';}// 留下我自己 当前的小li 设置 current 类名this.className = 'current';// 5、点击小圆圈移动图片,当然移动的是ul// ul的移动距离 = 小圆圈的索引号 x 图片的宽度 注意是负值// 当我们点击了某个li,就拿到当前小li的索引号var index = this.getAttribute('index');//当我们点击了某个小li,就拿到当前小li的索引号给 num num = index;//当我们点击了某个小li,就拿到当前小li的索引号给 clrcle clrcle = index;console.log('index:' + index);console.log('num:' + num);console.log('circle:' + circle);animate(ul, -index * focusWidth);})}// 把ol里面的第一个小li设置类名为current;ol.children[0].className = 'current';// 6、克隆第一张图片(li)放到ul最后面;(在生成小圆圈的后面克隆的,所以页面上还是只有4个小圆圈)var first = ul.children[0].cloneNode(true);ul.appendChild(first);// 7、点击右侧按钮,图片滚动一张var num = 0;var circle = 0; //circle 用来控制小圆圈的播放// 右侧按钮arrow_r.addEventListener('click', function () {// 如果走到了最后复制的一张图片,此时,我们的ul要快速复原 left改为0;if (num == ul.children.length - 1) {//图片的长度减一ul.style.left = 0;num = 0;}num++;console.log('num:' + num);animate(ul, -num * focusWidth);// 8、点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放;circle++;console.log('circle:' + circle);// 如果 circle==4,说明走到最后我们克隆的这张图片了,我们就复原;if (circle == ol.children.length) {circle = 0;}// 调用函数circleChange();})// 9、左侧按钮arrow_l.addEventListener('click', function () {// 如果走到了最后复制的一张图片,此时,我们的ul要快速复原 left改为0;if (num == 0) {//图片的长度减一num = ul.children.length - 1;ul.style.left = -num * focusWidth + 'px';}num--;console.log('num:' + num);animate(ul, -num * focusWidth);// 8、点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放;circle--;console.log('circle:' + circle);// 如果 circle<0,说明第一张图片,则小圆圈要改为第4个小圆圈;// if (circle < 0) {// circle = ol.children.length - 1;// }circle = circle < 0 ? ol.children.length - 1 : circle;// 调用函数circleChange();})function circleChange() {// 先清除其余小圆圈的current类名for (var i = 0; i < ol.children.length; i++) {ol.children[i].className = '';}// 留下当前的小圆圈的current类名ol.children[circle].className = 'current';}// 10、自动播放轮播图var timer = setInterval(function () {// 手动调用点击事件arrow_r.click();}, 1000)
})
节流阀以及逻辑中断应用
节流阀
- 防止轮播图按钮连续点击造成播放过快;
- 节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发;
- 核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数;
(1)、开始设置一个变量var flag=true;
(2)、if(flag){flag=false;do something}
关闭水龙头;
(3)、利用回调函数,动画执行完毕,flag=true
打开水龙头;
function animate(obj, target, callback) {// console.log(callback); callback = function() {} 调用的时候 callback()// 先清除以前的定时器,只保留当前的一个定时器执行clearInterval(obj.timer);obj.timer = setInterval(function() {// 步长值写到定时器的里面// 把我们步长值改为整数 不要出现小数的问题// var step = Math.ceil((target - obj.offsetLeft) / 10);var step = (target - obj.offsetLeft) / 10;step = step > 0 ? Math.ceil(step) : Math.floor(step);if (obj.offsetLeft == target) {// 停止动画 本质是停止定时器clearInterval(obj.timer);// 回调函数写到定时器结束里面// if (callback) {// // 调用函数// callback();// }callback && callback();//逻辑中断应用}// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10obj.style.left = obj.offsetLeft + step + 'px';}, 15);
}
案例:返回顶部
- 滚动窗口至文档中的特定位置,
window.scroll(x,y)
; - 注意:里面的x, y 不跟单位,直接写数字即可;
- 带有动画的返回顶部:此时可以继续使用我们封装的动画函数;只需要把所有的left相关的值改为跟页面垂直滚动距离相关就可以了;页面滚动了多少,可以通过
window.pageYOffset
得到; - 最后是页面滚动,使用
window.scroll(x,y)
;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>仿淘宝固定右侧侧边栏</title><style>.slider-bar {position: absolute;left: 50%;top: 300px;margin-left: 600px;width: 45px;height: 130px;background-color: pink;}.w {width: 1200px;margin: 10px auto;}.header {height: 150px;background-color: purple;}.banner {height: 250px;background-color: skyblue;}.main {height: 1000px;background-color: yellowgreen;}span {display: none;position: absolute;bottom: 0;}</style>
</head><body><!-- 案例分析:1、原先侧边栏是绝对定位;2、当页面滚动到一定位置,侧边栏改为固定定位;3、页面继续滚动,会让返回顶部显示出来;4、需要用到页面滚动事件 scroll,因为是页面滚动,所以事件源是 document;5、滚动到某个位置,就是判断页面被卷去的上部值;6、页面被卷去的头部,可以通过 window.pageYOffset 获得;如果是被卷去的左侧 window.pageXOffset;7、元素被卷去的头部是:element.scrollTop;如果是页面被卷去的头部则是:window.pageYOffset;--><div class="slider-bar"><span class="goBack">返回顶部</span></div><div class="header w">头部区域</div><div class="banner w">banner区域</div><div class="main w">主体部分</div><script>// 1、获取元素var sliderbar = document.querySelector('.slider-bar');var banner = document.querySelector('.banner');console.log(banner.offsetTop);// banner.offsetTop 就是被卷去头部的大小,一定要写到滚动的外面;var bannerTop = banner.offsetTop;//当我们侧边栏固定定位之后应该变化的数值; var sliderbarTop = sliderbar.offsetTop - bannerTop;var main = document.querySelector('.main');var goBack = document.querySelector('.goBack');var mainTop = main.offsetTop;// 2、页面滚动事件 scrolldocument.addEventListener('scroll', function () {// 3、当页面被卷去的头部大于等于了 172 时,侧边栏就要改为固定定位;if (window.pageYOffset >= bannerTop) {sliderbar.style.position = 'fixed';sliderbar.style.top = sliderbarTop + 'px';} else {sliderbar.style.position = 'absolute';sliderbar.style.top = '300px';}// 4、当页面滚动到main盒子,就显示 goBack 模块;if (window.pageYOffset >= bannerTop) {goBack.style.display = 'block';} else {goBack.style.display = 'none';}})// 当我们点击了返回顶部模块,就让窗口滚动到页面的最上方;goBack.addEventListener('click', function () {// window.scroll(x, y); 里面的x, y 不跟单位,直接写数字即可;//window.scroll(0, 0); // 滚动的太快//缓慢滚动到顶部 //因为是窗口滚动,所以对象是window;因为是滚动到页面的最顶端,所以target是0;animate(window, 0);})// 动画函数function animate(obj, target, callback) {console.log(callback); // callback = function(){} 调用的时候 callback()clearInterval(obj.timer);obj.timer = setInterval(function () {// 步长值写到定时器的里面;把步长值改为整数,不要出现小数问题;//var step = Math.ceil((target - obj.offsetLeft) / 10);var step = (target - window.pageYOffset) / 10;step = step > 0 ? Math.ceil(step) : Math.floor(step);if (window.pageYOffset == target) {clearInterval(obj.timer);// 回调函数写到定时器结束里面if (callback) {// 调用函数callback();}} else {window.scroll(0, window.pageYOffset + step)}}, 15)}</script>
</body></html>
案例:筋斗云案例
- 鼠标经过某个小li,筋斗云跟着到当前小li位置;
- 鼠标离开这个小li,筋斗云复原为原来的位置;
- 鼠标点击了某个小li,筋斗云就会留在点击这个小li的位置;
- 案例分析:
(1)、利用动画函数做动画效果;
(2)、原先筋斗云的起始位置是0;
(3)、鼠标经过某个li,把当前小li的offsetLeft
位置作为目标值即可;
(4)、鼠标离开某个小li,就把目标值设为0;
(5)、如果点击了某个小li,就把li当前的位置存起来,作为筋斗云的起始位置;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>筋斗云导航栏案例</title><style>* {margin: 0;padding: 0}ul {list-style: none;}body {background-color: black;}.c-nav {width: 900px;height: 42px;background: #fff url(images/rss.png) no-repeat right center;margin: 100px auto;border-radius: 5px;position: relative;}.c-nav ul {position: absolute;}.c-nav li {float: left;width: 83px;text-align: center;line-height: 42px;}.c-nav li a {color: #333;text-decoration: none;display: inline-block;height: 42px;}.c-nav li a:hover {color: white;}.cloud {position: absolute;left: 0;top: 0;width: 83px;height: 42px;background: url(images/cloud.gif) no-repeat;}</style><script src="./animate.js"></script><script>window.addEventListener('load', function () {// 1、获取元素var cloud = document.querySelector('.cloud');var c_nav = document.querySelector('.c-nav');var lis = c_nav.querySelectorAll('li');// 给所有的小li绑定事件// 这个current作为筋斗云的起始位置var current = 0;for (var i = 0; i < lis.length; i++) {// (1)、鼠标经过把当前小li的位置作为目标值;lis[i].addEventListener('mouseenter', function () {animate(cloud, this.offsetLeft);});// (2)、鼠标离开就回到起始的位置;(第一次鼠标离开回到0的位置)lis[i].addEventListener('mouseleave', function () {animate(cloud, current);});// (3)、当鼠标点击就把当前位置作为目标值;lis[i].addEventListener('click', function () {current = this.offsetLeft;});}})</script>
</head><body><!-- 案例分析:(1)、利用动画函数做动画效果;(2)、原先筋斗云的起始位置是0;(3)、鼠标经过某个li,把当前小li的`offsetLeft`位置作为目标值即可;(4)、鼠标离开某个小li,就把目标值设为0;--><div id="c_nav" class="c-nav"><span class="cloud"></span><ul><li class="current"><a href="#">首页新闻</a></li><li><a href="#">师资力量</a></li><li><a href="#">活动策划</a></li><li><a href="#">企业文化</a></li><li><a href="#">招聘信息</a></li><li><a href="#">公司简介</a></li><li><a href="#">我是佩奇</a></li><li><a href="#">啥是佩奇</a></li></ul></div>
</body></html>
移动端网页特效
触屏事件
- 移动端浏览器兼容性较好,我们不需要考虑以前
js
的兼容性问题,可以放心的使用原生js
书写效果,但是移动端也有自己独特的地方,比如:触屏事件touch
(也称触摸事件),Android
和IOS
都有; touch
对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>移动端touch触摸事件</title><style>div {width: 100px;height: 100px;background-color: pink;}</style>
</head><body><div></div><script>var div = document.querySelector('div');div.addEventListener('touchstart', function () {console.log('111');})</script>
</body></html>
触摸事件对象TouchEvent
touchstart
touchmove
touchend
三个事件都会各自有事件对象;TouchEvent
是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少等等;
e.targetTouches[0]
就可以得到正在触摸dom元素的第一个手指的相关信息,比如:手指的坐标等等;
移动端拖动元素
touchstart
touchmove
touchend
可以实现拖动元素;- 但是,拖动元素需要当前手指的坐标值,我们可以使用
targetTouches[0]
里面的pageX
和pageY
; - 移动端拖动的原理:手指移动中,计算出手指移动的距离。然后用盒子原来的位置 + 手指移动的距离;
- 手指移动的距离:手指滑动中的位置 减去 手指刚开始触摸的位置;
- 拖动元素三步曲:
(1)、触摸元素touchstart
:获取手指初始坐标,同时获得盒子原来的位置;
(2)、移动手指touchmove
:计算手指的滑动距离,并且移动盒子;
(3)、离开手指:touchend
;
注意:手指移动也会触发滚动屏幕,所以这里要阻止默认的屏幕滚动e.preventDefault()
;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>移动端touch触摸事件</title><style>div {width: 100px;height: 100px;background-color: pink;position: absolute;top: 0;left: 0;}</style>
</head><body><div></div><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) {// 计算手指的移动距离,手指移动之后的坐标减去手指初始的坐标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';e.preventDefault();//阻止屏幕滚动的默认行为})</script>
</body></html>
案例:移动端轮播图
- 案例分析:
(1)、自动播放功能;
(2)、开启定时器;
(3)、移动端移动,可以使用translate
移动;
(4)、想要图片优雅的移动,添加过渡效果;
(5)、自动播放功能–无缝滚动:注意:我们判断条件是要等到图片滚动完毕再去判断,就是过渡完成后判断;此时,需要添加检测过渡完成事件transitionend
;
(6)、判断条件:如果索引号等于3,说明走到最后一张图片,此时索引号要复原为0;
(7)、如果索引号小于0,说明是倒着走,索引号等于2;此时图片,去掉过渡效果,然后移动;
补充:classList
属性:
- 是HTML5新增的一个属性,返回元素的类名,但是ie10以上版本支持;
- 该属性用于在元素中添加,移除及切换CSS类。有以下方法:
(1)、添加类:element.classList.add('类名')
(2)、移除类:element.classList.remove('类名')
(3)、切换类(自动判断有没有某个类名,有就将其去掉,没有就将其加上):element.classList.toggle('类名')
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>classList的使用</title><style>.bg {background-color: black;}</style>
</head><body><div class="one two"></div><button>开关灯</button><script>// classList返回元素的类名var div = document.querySelector('div');//console.log(div.classList);// 1、添加类名,是在后面追加类名,不会覆盖以前的类名;div.classList.add('three');//注意:three前面不需要加点//console.log(div.classList);// 2、删除类名div.classList.remove('three');//console.log(div.classList);// 3、切换类名(自动判断有没有某个类名,有就将其去掉,没有就将其加上)var btn = document.querySelector('button');btn.addEventListener('click', function () {document.body.classList.toggle('bg');})</script>
</body></html>
window.addEventListener('load', function () {// 1、获取元素var focus = document.querySelector('.focus');var ul = focus.children[0];// 获得focus的宽度var w = focus.offsetWidth;var ol = focus.children[1];// 2、利用定时器自动轮播图片var index = 0;var timer = setInterval(function () {index++;var translatex = -index * w;ul.style.transition = 'all .3s';ul.style.transform = 'translateX(' + translatex + 'px)';}, 2000)// 等着我们过渡完成之后,再去判断,监听过渡完成的事件 transitionend;// 判断条件:如果索引号等于3,说明走到最后一张图片,此时索引号要复原为0;ul.addEventListener('transitionend', function () {// 无缝滚动if (index >= 3) {index = 0;// 去掉过渡效果,这样让我们的ul快速的跳到目标位置;ul.style.transform = 'none';// 利用最新的索引号乘以宽度 去滚动图片var translatex = -index * w;ul.style.transform = 'translateX(' + translatex + 'px)';} else if (index < 0) {index = 2;ul.style.transition = 'none';var translatex = -index * w;ul.style.transform = 'translateX(' + translatex + 'px)';}// 3、小圆点跟随变化效果: //(3)、但是,是等着过渡结束之后变化,所以这个写到 transitionend 事件里面; //(1)、把ol里面li带有current类名的选出来去掉类名 (remove);ol.querySelector('.current').classList.remove('current');// (2)、让当前索引号的小li加上 current (add);ol.children[index].classList.add('current');})// 4、手指滑动轮播图:本质就是ul跟随手指移动,简单说就是移动端拖动元素;// (1)、触摸元素 touchstart:获取手指初始坐标;var startX = 0;var moveX = 0;//后面我们会使用这个移动距离所以要定义一个全局变量;var flag = false;ul.addEventListener('touchstart', function (e) {startX = e.targetTouches[0].pageX;// 手指触摸的时候就停止定时器clearInterval(timer);});// (2)、移动手指 touchmove:计算手指的滑动距离,并且移动盒子;ul.addEventListener('touchmove', function (e) {// 计算移动距离moveX = e.targetTouches[0].pageX - startX;// 移动盒子:盒子原来的位置 + 手指移动的距离var translatex = -index * w + moveX;// 手指拖动的时候,不需要动画效果所以要取消过渡效果ul.style.transition = 'none';ul.style.transform = 'translateX(' + translatex + 'px)';flag = true;//如果用户手指移动过我们再去判断,否则不做判断效果;e.preventDefault();//阻止滚动屏幕的行为;});//离开手指touchend:根据移动距离去判断是回弹还是播放上一张下一张;ul.addEventListener('touchend', function (e) {//(1)、如果移动距离大于50像素,我们就播放上一张或者下一张;if (flag) {if (Math.abs(moveX) > 50) { //Math.abs() 取绝对值// 如果是右滑就是,播放上一张 moveX 是正值if (moveX > 0) {index--;} else {// 如果是左滑就是,播放下一张 moveX 是负值index++;}var translatex = -index * w;ul.style.transition = 'all .3s';ul.style.transform = 'translateX(' + translatex + 'px)';} else {// (2)、如果移动距离小于50像素,我们就回弹;var translatex = -index * w;ul.style.transition = 'all .1s';ul.style.transform = 'translateX(' + translatex + 'px)';}}// 手指离开重新开启定时器clearInterval(timer);timer = setInterval(function () {index++;var translatex = -index * w;ul.style.transition = 'all .3s';ul.style.transform = 'translateX(' + translatex + 'px)';}, 2000)})
})
案例:返回顶部
- 当页面滚动到某个地方,就显示,否则隐藏;点击可以返回顶部;
- 事件:
scroll
页面滚动事件; - 如果被卷去的头部(
window.pageYOffset
)大于某个数值; - 点击返回顶部,
window.scroll(0,0)
;
window.addEventListener('load', function () {// 1、获取元素var focus = document.querySelector('.focus');var ul = focus.children[0];// 获得focus的宽度var w = focus.offsetWidth;var ol = focus.children[1];// 2、利用定时器自动轮播图片var index = 0;var timer = setInterval(function () {index++;var translatex = -index * w;ul.style.transition = 'all .3s';ul.style.transform = 'translateX(' + translatex + 'px)';}, 2000)// 等着我们过渡完成之后,再去判断,监听过渡完成的事件 transitionend;// 判断条件:如果索引号等于3,说明走到最后一张图片,此时索引号要复原为0;ul.addEventListener('transitionend', function () {// 无缝滚动if (index >= 3) {index = 0;// 去掉过渡效果,这样让我们的ul快速的跳到目标位置;ul.style.transform = 'none';// 利用最新的索引号乘以宽度 去滚动图片var translatex = -index * w;ul.style.transform = 'translateX(' + translatex + 'px)';} else if (index < 0) {index = 2;ul.style.transition = 'none';var translatex = -index * w;ul.style.transform = 'translateX(' + translatex + 'px)';}// 3、小圆点跟随变化效果: //(3)、但是,是等着过渡结束之后变化,所以这个写到 transitionend 事件里面; //(1)、把ol里面li带有current类名的选出来去掉类名 (remove);ol.querySelector('.current').classList.remove('current');// (2)、让当前索引号的小li加上 current (add);ol.children[index].classList.add('current');})// 4、手指滑动轮播图:本质就是ul跟随手指移动,简单说就是移动端拖动元素;// (1)、触摸元素 touchstart:获取手指初始坐标;var startX = 0;var moveX = 0;//后面我们会使用这个移动距离所以要定义一个全局变量;var flag = false;ul.addEventListener('touchstart', function (e) {startX = e.targetTouches[0].pageX;// 手指触摸的时候就停止定时器clearInterval(timer);});// (2)、移动手指 touchmove:计算手指的滑动距离,并且移动盒子;ul.addEventListener('touchmove', function (e) {// 计算移动距离moveX = e.targetTouches[0].pageX - startX;// 移动盒子:盒子原来的位置 + 手指移动的距离var translatex = -index * w + moveX;// 手指拖动的时候,不需要动画效果所以要取消过渡效果ul.style.transition = 'none';ul.style.transform = 'translateX(' + translatex + 'px)';flag = true;//如果用户手指移动过我们再去判断,否则不做判断效果;e.preventDefault();//阻止滚动屏幕的行为;});//离开手指touchend:根据移动距离去判断是回弹还是播放上一张下一张;ul.addEventListener('touchend', function (e) {//(1)、如果移动距离大于50像素,我们就播放上一张或者下一张;if (flag) {if (Math.abs(moveX) > 50) { //Math.abs() 取绝对值// 如果是右滑就是,播放上一张 moveX 是正值if (moveX > 0) {index--;} else {// 如果是左滑就是,播放下一张 moveX 是负值index++;}var translatex = -index * w;ul.style.transition = 'all .3s';ul.style.transform = 'translateX(' + translatex + 'px)';} else {// (2)、如果移动距离小于50像素,我们就回弹;var translatex = -index * w;ul.style.transition = 'all .1s';ul.style.transform = 'translateX(' + translatex + 'px)';}}// 手指离开重新开启定时器clearInterval(timer);timer = setInterval(function () {index++;var translatex = -index * w;ul.style.transition = 'all .3s';ul.style.transform = 'translateX(' + translatex + 'px)';}, 2000)})// 返回顶部模块var goBack = document.querySelector('.goBack');var nav = document.querySelector('nav');window.addEventListener('scroll', function () {if (window.pageYOffset >= nav.offsetTop) {goBack.style.display = 'block';} else {goBack.style.display = 'none';}})goBack.addEventListener('click', function () {window.scroll(0, 0);})
})
click
延时解决方案
- 移动端
click
事件会有300ms的延时,原因是移动端屏幕双击会缩放(double tap to zoom
)页面; - 解决方案:
(1)、禁止缩放。浏览器禁用默认的双击缩放行为并且去掉300ms的点击延迟;<meta name="viewport" content="user-scalable=no">
(2)、利用touch
事件自己封装这个事件解决300ms延迟;(该函数缺点:一次只能给一个元素使用)
原理就是:
a、当我们手指触摸屏幕,记录当前触摸时间;
b、当我们手指离开屏幕,用离开的时间减去触摸的时间;
c、如果时间小于150ms,并且没有滑动过屏幕,那么我们就定义为点击;
(3)、使用插件。fastclick
插件解决300ms延迟;
什么是插件?fastclick
、Swiper
、superslide
(https://www.superslide2.com)、iscroll
(https://github.com/cubiq/iscroll)、移动端视频插件zy.media.js
- 移动端要求的是快速开发,所以我们经常会借助于一些插件来帮我们完成操作,那么什么是插件呢 ?
- JS插件就是JS文件。它遵循一定规范编写,方便程序展示效果,拥有特定功能且方便调用。如轮播图和瀑布流插件;
- 特点:它一般是为了解决某个问题而专门存在,其功能单一,并且比较小。我们以前写的
animate.js
也算是一个最简单的插件; fastclick
插件的使用:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>fastclick插件使用</title><style>div {width: 50px;height: 50px;background-color: aqua;}</style><script src="fastclick.js"></script>
</head><body><div></div><script>// 从官网github复制而来if ('addEventListener' in document) {document.addEventListener('DOMContentLoaded', function () {FastClick.attach(document.body);}, false);}</script>
</body></html>
- 移动端视频插件
zy.media.js
;(https://github.com/ireaderlab/zyMedia) - H5给我们提供了
video
标签,但是浏览器的支持情况不同。不同的视频格式文件,我们可以通过source
解决;但是,外观样式、还有暂停、播放、全屏等功能我们只能自己写代码解决。这个时候我们可以使用插件方式来制作。
移动端常用开发框架
- 框架:顾名思义就是一套架构,它会基于自身的特点向用户提供一套较为完整的解决方案。框架的控制权在框架本身,使用者要按照框架所规定的某种规范进行开发。
- 插件一般是为了解决某个问题而专门存在,其功能单一,并且比较小;
- 前端常用的框架有:
Bootstrap
Vue
Angular
React
等。既能开发PC端,也能开发移动端; - 前端常用的移动端插件有:
swiper
iscroll
superslide
; - 框架:大而全,一整套解决方案;小而专一,某个功能的解决方案;
本地存储
- 本地存储特性:
(1)、数据存储在用户浏览器中;
(2)、设置、读取方便、甚至页面刷新不丢失数据;
(3)、容量较大,sessionStorage
约5M,localStorage
约20M;
(4)、只能存储字符串,可以将对象JSON.stringify()
编码后存储;
window.sessionStorage
- 生命周期为关闭浏览器窗口;
- 在同一个窗口(页面)下数据可以共享;
- 以键值对的形式存储使用;
- 存储数据:
sessionStorage.setItem(key,value)
; - 获取数据:
sessionStorage.getItem(key)
; - 删除数据:
sessionStorage.removeItem(key)
; - 删除所有数据:
sessionStorage.clear()
;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>本地存储之sessionStorage</title>
</head><body><input type="text"><button class="set">存储数据</button><button class="get">获取数据</button><button class="remove">删除数据</button><button class="del">清空所有数据</button><script>var ipt = document.querySelector('input');var set = document.querySelector('.set');var get = document.querySelector('.get');set.addEventListener('click', function () {// 当我们点击了之后,就可以把表单里面的值存储起来var val = ipt.value;sessionStorage.setItem('uname', val);})get.addEventListener('click', function () {// 当我们点击了之后,就可以把表单里面存储的值获取过来console.log(sessionStorage.getItem('uname'));})</script>
</body></html>
window.localStorage
- 生命周期永久生效,除非手动删除,否则关闭页面也会存在;
- 可以多窗口(页面)共享(同一浏览器可以共享);
- 以键值对的形式存储使用;
- 存储数据:
localStorage.setItem(key,value)
; - 获取数据:
localStorage.getItem(key)
; - 删除数据:
localStorage.removeItem(key)
; - 删除所有数据:
localStorage.clear()
;
案例:记住用户名
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>记住用户名案例</title>
</head><body><!--如果勾选记住用户名,下次用户打开浏览器,就在文本框里面自动显示上次登录的用户名;案例分析:1、把数据存起来,用到本地存储;2、关闭页面,也可以显示用户名,所以用到localSorage;3、打开页面,先判断是否有这个用户名,如果有,就在表单里面显示用户名,并且勾选复选框;4、当复选框发生改变的时候 change 事件;5、如果勾选就存储,否则就移除;--><input type="text" id="username"> <input type="checkbox" name="" id="remember"> 记住用户名<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>
</body></html>
- 存储时转化成字符串,获取时转化成对象;
<script>var todolist = [{title: '我今天吃八个馒头',done: false}, {title: '我今天学习jq',done: false}, ];// localStorage.setItem("todo", todolist);// 1. 本地存储里面只能存储字符串的数据格式 把我们的数组对象转换为字符串格式 JSON.stringify()localStorage.setItem("todo", JSON.stringify(todolist));var data = localStorage.getItem("todo");// console.log(typeof data);// console.log(data[0].title);// 2. 获取本地存储的数据 我们需要把里面的字符串数据转换为 对象格式 JSON.parse()data = JSON.parse(data);console.log(data);console.log(data[0].title);</script>