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>
相关文章:

JavaScript教程(二)
BOM浏览器对象模型 什么是BOM BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window;BOM由一系列相关的对象构成,并且每个对象都提供了很多方…...

设计模式之代理模式
代理模式的定义是:为其他对象提供一种代理以控制对这个对象的访问。 因为代理类与服务类实现同样的接口,所以代理类能代替服务类提供给客户端。当客户端使用代理类时,代理类能对请求进行处理(例如增加访问控制、缓存请求结果、隐…...

初识MySQL
💕与其抱怨生活的不公,不如积极行动改变它。💕 🐼作者:不能再留遗憾了🐼 🎆专栏:MySQL学习🎆 🚗本文章主要内容:简单了解什么是MySQL、MySQL的发展…...

内网渗透(八十五)之ADCS证书服务攻击
ADCS证书服务攻击 漏洞背景 2021年6月17日,国外安全研究员 Will Schroeder 和 Lee Christensen 共同发布了针对ADCS(Active Directory Certificate Service, 活动目录证书服务)的攻击手法。同年8月5日,在Black Hat 2021上 Will Schroeder 和 Lee CHristensen 对该攻击手法进…...

通过python封装1688图片搜索商品数据接口,拍立淘API接口
1688图片搜索API封装接口是一个可以帮助用户快速使用1688图片搜索API的接口封装库。该接口封装库可以帮助用户快速引入1688图片搜索API,并提供各种参数配置和封装的API调用方法,以方便用户快速实现自己的图片搜索需求。 该接口封装库将1688图片搜索API的…...

HashMap的源码分析(基于JDK1.8)
HashMap的源码分析(基于JDK1.8) Java中的HashMap是一种常用的数据结构,它是基于哈希表的数据结构,可以用来存储键值对。在HashMap中,每个键值对被称作一个Entry,每个Entry包含一个键和一个值。HashMap的实…...

算法能力-数据安全复合治理框架和模型解读(5)
数据治理,数据安全治理行业在发展,在实践,所以很多东西是实践出来的,哪有什么神仙理论指导,即使有也是一家之说,但为了提高企业投产比,必要的认知是必须的,落地数据安全治理科技水平差异直接决定产品和项目是否可持续性,当前和未来更需要专业和有效创新。数据安全治理…...

java从入门到起飞——基础概念
目录 背景注释和关键字注释关键字 常量变量数据类型计算存储单元数据类型分类 标识符小驼峰命名法(方法、变量)大驼峰命名法(类) 类型转换自动类型转换强制类型转换 计算机中的数据存储总结 背景 学编程这么长时间了,重…...

C语言判断队列满or空
1 静态数组队列 循环队列通常使用数组来实现,判别循环队列是否满或空,可以借助两个变量front和rear。 判空:当front和rear相等时,队列为空。 判满:当(front 1) % n rear时,队列为满,其中n为…...

系统中级集成项目管理工程师(中项)好考吗?
软考系统集成项目管理工程师是一项非常重要的考试,对于从事信息技术和管理方面的人员来说,这是一个非常有用的证书。 对于零基础的考生来说,软考系统集成项目管理工程师是否好考,主要取决于他们的学习态度和学习方法。 一般而言…...

【Java多线程进阶】CAS机制
前言 CAS指的是Compare-And-Swap(比较与交换),它是一种多线程同步的技术,常用于实现无锁算法,从而提高多线程程序的性能和扩展性。本篇文章具体讲解如何使用 CAS 的机制以及 CAS 机制带来的问题。 目录 1. 什么是CAS&…...

flex布局总结
flex布局总结 总结自:https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html 内容: flex意思是-弹性布局,可以为盒型模型提供极大的灵活性,设置为flex布局后,子元素的fload clear vertical会失效 概念&#x…...

2023 Idea 热部署 JRebel 插件激活方法
2023 Idea 热部署 JRebel 插件激活方法 1. 下载源代码 进入下面 github 地址 clone 代码到本地 https://github.com/Byron4j/JrebelLicenseServerforJava 2. 编译和打包 cd /Users/daixiaohu/Desktop/JrebelLicenseServerforJavamvn clean package3. 运行项目 cd target/jav…...

Java (韩老师课程)第三章
变量的介绍 * 变量是程序的基本组成单位 * 变量相当于内存中一个数据存储空间的表示 * 变量在该区域有自己的名称和类型 * 变量必须先声明,后使用,即顺序 * 变量在该区域的数据/值可以在同一类型内不断变化 * 变量在同一个作用域中不能重…...

【P38】JMeter 随机控制器(Random Controller)
文章目录 一、随机控制器(Random Controller)参数说明二、测试计划设计2.1、测试计划一2.2、测试计划二2.3、勾选忽略子控制器块 一、随机控制器(Random Controller)参数说明 可以让控制器内部的逻辑随机执行一个,一般…...

API电商 ERP 数据管理
没有 API,应用之间的通信将会被扼杀;软件开发者将不断重写并执行相同功能的软件;创新的脚步将会放缓。 API 随处可见。大到一个软件系统,小到几行程序,只要具备了一定的特征,都可以被称作 API。那么&#…...

【SQLAlchemy】第四篇——事务
可以把事务理解为一系列操作的集合:这些操作要么全部执行,要么一个也不执行——这样就可以保证数据的一致性和可靠性。在执行更新和删除操作时,尤其要注意利用事务的这个特征。 SQLAlchemy中提供了许多方法来利用事务。 1、如何确保操作生效…...

浅谈QMap中erase与remove的区别
QMap中erase与remove的区别 QMap中erase与remove的区别分别使用erase和remove删除元素使用erase删除元素使用remove删除元素代码讲解 QMap中erase与remove的区别 在实践中发现erase删除元素之后,其迭代器自动指向下一个元素,而remove删除元素之后迭代器…...

FastThreadLocal 原理解析
FastThreadLocal 每个 FastThread 包含一个 FastThreadLocalMap,每个 FastThreadLocalThread 中的多个 FastThreadLocal 占用不同的索引。每个 InternalThreadLocalMap 的第一个元素保存了所有的 ThreadLocal 对象。之后的元素保存了每个 ThreadLocal 对应的 value …...

设计模式B站学习(一)(java)
这里写目录标题 一、设计模式概述1.1 软件设计模式的产生背景1.2 软件设计模式的概念1.3 学习设计模式的必要性1.4 设计模式分类 二、UML图2.1 类图概述2.2 类图的作用2.3 类图表示法2.3.1 类图表示方法2.3.2 类与类之间关系的表示方法2.3.2.1 关联关系2.3.2.2 聚合关系2.3.2.3…...

Pandas如何轻松按位置删除多重索引列?
在Pandas处理DataFrame数据的过程中,我们常常需要删除某些不需要的列。那么,如何高效地按位置删除Pandas DataFrame的多重索引列呢? 今天分享在Pandas中按位置删除多重索引列的具体方法: 第一步:获取所有列标签 使用df.columns获取DataFrame的所有列标…...

第五十七天学习记录:C语言进阶:结构体链表的自学
先展示一段代码: #define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> #include <stdlib.h>// 定义链表节点结构体 typedef struct Node {int value;struct Node* next; } Node;int main() {// 创建链表头指针Node* head (Node*)malloc(sizeof(Node…...

【一次调频】考虑储能电池参与一次调频技术经济模型的容量配置方法(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

ICV报告: 智能座舱SoC全球市场规模预计2025年突破50亿美元
在智能化、互联化车辆需求不断增加的推动下,汽车行业正在经历一场范式转变。这一转变的前沿之一是智能座舱SoC。本市场研究报告对智能座舱SoC市场进行了全面的分析,包括其应用领域、当前状况和主要行业参与者。 智能座舱SoC指的是现代汽车智能座舱系统的…...

在can协议的基础下编写DBC文件,然后使用该DBC文件下发can协议到底盘完整流程
目录 前言一、VectorCANdb下载及安装二、DBC文件的编写1.新建dbc文件2.建立dbc2.1根据CAN协议设置以下的signals2.2设置报文2.3建立报文与信号的关系2.4建立节点 三、编写程序使用UDP通信下发can协议1.查看can口、电脑ip以及端口号2.编写测试程序 前言 最近完成了一个项目&…...

工业传感器有哪些?
工业传感器是指能在工业制造过程能将感受的力、热、光、磁、声、湿、电、环境等被测量转换成电信号输出的器件与装置,在各种化工、机械、汽车等工业场景上都有应用。 工业传感器有哪些? 工业传感器由于不同的特性也被分为多种不同的类别,主要…...

Docker应用部署之Nginx
部署nginx 要求:在docker容器中部署nginx,并通过外部机器访问nginx 步骤: 1.搜索nginx镜像 docker search nginx 2.拉取nginx镜像 docker pull nginx 3.创建容器 #在root目录下创建nginx目录用于存放nginx项目 mkdir ~/nginx cd ~/ng…...

TerminalWorks TSPrint/TSScan/TSWebCam Crack
/ 远程桌面打印软件,TerminalWorks TSPrint Server/Client 从远程服务器打印到本地打印机的 简单方法 TSPrint 为您提供了一个简单的远程桌面打印软件,以及使 Windows 终端服务操作更容易的附加工具。有选择地启用或禁用功能,以便您可以完全…...

如何使用Springboot实现文件上传和下载,并为其添加实时进度条的功能
文件上传和下载是Web开发中非常基础的功能,但在实际开发中,我们经常需要实时显示文件上传或下载的进度。这篇文章将介绍如何使用Springboot实现文件上传和下载,并为其添加实时进度条的功能。 文件上传 添加Maven依赖项 首先,我…...

安装并新建windows下wxwroks7.0 bootrom工程
双击steup.exe 直接next 直接next 选择typical,然后next I accept 安装完成finish 现在双击Workbench 4,新建vxworks7.0工程,会出现下面的情况,因为没有licence 安装licence,将zwrsLicense-vx7-perm.lic粘贴到安装目…...