当前位置: 首页 > news >正文

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 对象的属性

在这里插入图片描述

  • 重点记住:hrefsearch
<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 系列

offsetLeftoffsetTop获取元素偏移

  • 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>

offsetWidthoffsetHeight获取元素大小

<!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);//返回父亲,是最近一级的父亲,不管父亲有没有定位

offsetstyle的区别

-

案例:获取鼠标在盒子内的坐标

<!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>
pageshowload 事件分析
  • 下面3种情况都会刷新页面都会触发load 事件:
    (1)、a 标签的超链接;
    (2)、F5或者刷新按钮(强制刷新);
    (3)、前进、后退按钮;
  • 但是,火狐中有个特点,有个“往返缓存”,这个缓存中不仅保存着页面数据,还保存了DOMJavaScript的状态;实际上是将整个页面都保存在了内存里;所以,此时后退按钮不能刷新页面;
  • 此时可以使用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获得;

mouseentermouseover的区别

  • 当鼠标移动到元素上时,就会触发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第一个licloneNode()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(也称触摸事件),AndroidIOS都有;
  • 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]里面的pageXpageY
  • 移动端拖动的原理:手指移动中,计算出手指移动的距离。然后用盒子原来的位置 + 手指移动的距离;
  • 手指移动的距离:手指滑动中的位置 减去 手指刚开始触摸的位置;
  • 拖动元素三步曲:
    (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延迟;
什么是插件?fastclickSwipersuperslide(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&#xff08;Browser Object Model&#xff09;即浏览器对象模型&#xff0c;它提供了独立于内容而与浏览器窗口进行交互的对象&#xff0c;其核心对象是 window&#xff1b;BOM由一系列相关的对象构成&#xff0c;并且每个对象都提供了很多方…...

设计模式之代理模式

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

初识MySQL

&#x1f495;与其抱怨生活的不公&#xff0c;不如积极行动改变它。&#x1f495; &#x1f43c;作者&#xff1a;不能再留遗憾了&#x1f43c; &#x1f386;专栏&#xff1a;MySQL学习&#x1f386; &#x1f697;本文章主要内容&#xff1a;简单了解什么是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&#xff0c;并提供各种参数配置和封装的API调用方法&#xff0c;以方便用户快速实现自己的图片搜索需求。 该接口封装库将1688图片搜索API的…...

HashMap的源码分析(基于JDK1.8)

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

算法能力-数据安全复合治理框架和模型解读(5)

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

java从入门到起飞——基础概念

目录 背景注释和关键字注释关键字 常量变量数据类型计算存储单元数据类型分类 标识符小驼峰命名法&#xff08;方法、变量&#xff09;大驼峰命名法&#xff08;类&#xff09; 类型转换自动类型转换强制类型转换 计算机中的数据存储总结 背景 学编程这么长时间了&#xff0c;重…...

C语言判断队列满or空

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

系统中级集成项目管理工程师(中项)好考吗?

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

【Java多线程进阶】CAS机制

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

flex布局总结

flex布局总结 总结自&#xff1a;https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html 内容&#xff1a; flex意思是-弹性布局&#xff0c;可以为盒型模型提供极大的灵活性&#xff0c;设置为flex布局后&#xff0c;子元素的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 (韩老师课程)第三章

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

【P38】JMeter 随机控制器(Random Controller)

文章目录 一、随机控制器&#xff08;Random Controller&#xff09;参数说明二、测试计划设计2.1、测试计划一2.2、测试计划二2.3、勾选忽略子控制器块 一、随机控制器&#xff08;Random Controller&#xff09;参数说明 可以让控制器内部的逻辑随机执行一个&#xff0c;一般…...

API电商 ERP 数据管理

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

【SQLAlchemy】第四篇——事务

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

浅谈QMap中erase与remove的区别

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

FastThreadLocal 原理解析

FastThreadLocal 每个 FastThread 包含一个 FastThreadLocalMap&#xff0c;每个 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数据的过程中&#xff0c;我们常常需要删除某些不需要的列。那么&#xff0c;如何高效地按位置删除Pandas DataFrame的多重索引列呢? 今天分享在Pandas中按位置删除多重索引列的具体方法: 第一步:获取所有列标签 使用df.columns获取DataFrame的所有列标…...

第五十七天学习记录:C语言进阶:结构体链表的自学

先展示一段代码&#xff1a; #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代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

ICV报告: 智能座舱SoC全球市场规模预计2025年突破50亿美元

在智能化、互联化车辆需求不断增加的推动下&#xff0c;汽车行业正在经历一场范式转变。这一转变的前沿之一是智能座舱SoC。本市场研究报告对智能座舱SoC市场进行了全面的分析&#xff0c;包括其应用领域、当前状况和主要行业参与者。 智能座舱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.编写测试程序 前言 最近完成了一个项目&…...

工业传感器有哪些?

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

Docker应用部署之Nginx

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

TerminalWorks TSPrint/TSScan/TSWebCam Crack

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

如何使用Springboot实现文件上传和下载,并为其添加实时进度条的功能

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

安装并新建windows下wxwroks7.0 bootrom工程

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