目录
1.关闭广告
<!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>
*{
padding: 0;
margin: 0;
}
div{
/* 设置div的高度与宽度必须比背景图片的尺寸大,这样才能容纳 */
/* width: 300px;
height: 380px; */
/* 默认div的宽高就是img图片的宽高 */
/* border: 1px solid red; */
/* 添加背景图片 */
/* background: url("images/sina-ad.png") no-repeat; */
/* position: absolute;
bottom: 0;
left: 0; */
/* 固定定位:不随着滚动条的滚动而滚动 */
position: fixed;
bottom: 0;
left: 0;
}
div>img:first-child{
/* 绝对定位:就是相对于body浏览器或者某个定位流中的祖先元素来定位 */
position: absolute;
/* top: 0; */
top: -17px;
right: 0;
}
</style>
</head>
<body>
<div>
<img src="images/close.jpg" alt="">
<img src="images/sina-ad.png" alt="">
</div>
<script>
// 1.获取元素
let oImg = document.querySelector("div>img:first-child");
// 2.绑定点击事件
oImg.onclick = function(){
// 获取元素
let oDiv = document.querySelector("div");
// 删除元素
document.body.removeChild(oDiv);
// // 2.1 找到按钮的父元素
// let oDiv = this.parentNode;
// // console.log(oDiv);
// // 2.2 删除广告元素
// oDiv.parentNode.removeChild(oDiv);
};
</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>
*{
padding: 0;
margin: 0;
}
div{
width: 670px;
/* height: 1000px; */
/* border: 1px solid red; */
margin: 100px auto;
}
ul{
list-style: none;
/* border: 1px solid red; */
/* 弹性布局 */
display: flex;
/* 两端对齐,元素之间的间隔都相等 */
justify-content: space-between;
}
/* ul li{
float: left;
margin-right: 14px;
} */
ul>li>img{
width: 120px;
/* 底端对齐 */
vertical-align: bottom;
}
</style>
</head>
<body>
<div>
<img src="images/ad1.jpg" alt="">
<ul>
<li><img src="images/ad1.jpg" alt=""></li>
<li><img src="images/ad2.jpg" alt=""></li>
<li><img src="images/ad3.jpg" alt=""></li>
<li><img src="images/ad4.jpg" alt=""></li>
<li><img src="images/ad5.jpg" alt=""></li>
</ul>
</div>
<script>
let oImg = document.querySelector("div>img");
// 获取列表中存储的所有图片
let oItems = document.querySelectorAll("ul>li>img");
// console.log(oItems); // 数组
// 遍历数组中的每张图片
for(let item of oItems){
// 存在性能问题
// // 绑定点击事件
// item.onclick = function(){
// // 更改大图片img的src地址
// // oImg.src = item.src;
// // console.log(this); // 点击的那张图片img(item)
// oImg.src = this.src;
// }
// 绑定点击事件
item.onclick = change;
}
// 改进
function change() {
oImg.src = this.src;
};
// 不同的对象调用相同的方法,存储在不同的空间,这样很消耗性能
// let obj1 = { name: "zs" };
// let obj2 = { name: "ls" };
// obj1.say = function () {
// console.log("hello");
// }
// obj2.say = function () {
// console.log("hello");
// }
// console.log(obj1.say === obj2.say); // false
// // 改进
// let obj1 = {name:"zs"};
// let obj2 = {name:"ls"};
// function say() {
// console.log("hello");
// }
// obj1.say = say;
// obj2.say = say;
// console.log(obj1.say === obj2.say); // true
</script>
</body>
</html>
3.鼠标的移入移出事件
<style>
*{
margin: 0;
padding: 0;
}
div{
width: 200px;
height: 200px;
background-color: pink;
}
</style>
<div></div>
// 获取元素
let oDiv = document.querySelector("div");
(1).鼠标移入事件
- onmouseover
- onmouseenter (推荐使用)
// 1.鼠标移入事件
// oDiv.onmouseover = function () {
// console.log("鼠标移入事件");
// };
// 注意点: 对于初学者来说, 为了避免未知的一些BUG, 移入事件 建议使用 onmouseenter
oDiv.onmouseenter = function () {
console.log("鼠标移入事件");
};
(2).鼠标移出事件
- onmouseout
- onmouseleave (推荐使用)
// 2.鼠标移出事件
// oDiv.onmouseout = function () {
// console.log("鼠标移出事件");
// };
// 注意点: 对于初学者来说, 为了避免未知的一些BUG, 移出事件 建议使用 onmouseleave
oDiv.onmouseleave = function () {
console.log("鼠标移出事件");
};
(3).鼠标移动事件
- onmousemove
// 3.鼠标移动事件
oDiv.onmousemove = function () {
console.log("鼠标移动事件");
}
4.商品展示
<!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>
*{
padding: 0;
margin: 0;
}
div{
width: 430px;
/* 让div自身居中对齐;第一个参数为margin-top上外边距*/
margin: 100px auto;
border: 1px solid black;
}
ul{
list-style: none;
/* 弹性布局 */
display: flex;
justify-content: space-between;
}
ul>li>img{
width: 80px;
/* 底部对齐 */
vertical-align: bottom;
}
/* 解决鼠标移入时,添加边框后,其他图片被拥挤的问题 */
ul>li{
/* 添加边框,transparent:透明颜色 */
border: 2px solid transparent;
/* */
box-sizing: border-box;
}
.border{
/* 设置边框 */
border: 2px solid skyblue;
}
</style>
</head>
<body>
<div>
<img src="images/pic1.jpg" alt="">
<ul>
<li><img src="images/pic1.jpg" alt=""></li>
<li><img src="images/pic2.jpg" alt=""></li>
<li><img src="images/pic3.jpg" alt=""></li>
<li><img src="images/pic4.jpg" alt=""></li>
<li><img src="images/pic5.jpg" alt=""></li>
</ul>
</div>
<script>
// 1.获取元素
let images = document.querySelectorAll("ul>li>img");
let bigImage = document.querySelector("div>img")
// console.log(images); //数组,保存了所有的小图片
// 2.遍历图片数组
for(let image of images){
// 3.监听鼠标移入事件
image.onmouseenter = function(){
// 3.1 修改大图片的src地址
// bigImage.src = image.src;
// console.log(this) // 每一张小图片image
bigImage.src = this.src;
// 3.2 通过添加类名的方式,添加边框
// 注意点:是给小图片image的父元素li列表添加边框,而不是给小图片本身添加边框!
// image.className = "border";
// console.log(this.parentElement);
this.parentElement.className = "border";
}
// 4.监听鼠标移出事件
image.onmouseleave = function(){
// 将类名置空,取消边框
this.parentElement.className = "";
}
}
</script>
</body>
</html>
5.表单校验
- 需求描述
- 1.账号和密码必须大于等于6位
- 2.如果账号密码的长度不够就改变input输入框的背景颜色
- 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>
</head>
<body>
<!-- action: 点击提交按钮后,跳转到的地址 -->
<form action="http://www.it666.com">
<input type="text" placeholder="请输入账号" class="text">
<input type="password" placeholder="请输入密码" class="passwd">
<input type="submit" value="注册" class="submit">
</form>
<script>
/*
需求:
1.账号和密码必须大于等于6位
2.如果账号密码的长度不够就改变input输入框的背景颜色
3.如果用户输入的账号或者密码不符合需求, 那么就不能提交
*/
// 1.获取元素
let Osubmit = document.querySelector(".submit");
let Otext = document.querySelector(".text");
let Opasswd = document.querySelector(".passwd");
// 2.绑定点击事件
Osubmit.onclick = function(){
// 注意点: 如果想获取input中输入的内容, 必须通过value属性来获取
// console.log(Otext.value);
// 2.1 判断账号是否符合需求
if(Otext.value.length < 6){
// 修改背景颜色
// 注意:background-color(CSS) ---> backgroundColor (JS)
Otext.style.backgroundColor= "red";
return false;
}else{
Otext.style.backgroundColor = "#fff";
}
// 2.2 判断密码是否符合需求
if (Opasswd.value.length < 6) {
Opasswd.style.backgroundColor = "red";
return false;
} else {
Opasswd.style.backgroundColor = "#fff";
}
}
</script>
</body>
</html>
6.焦点事件
<input type="text">
(1).监听input获取焦点事件
- onfocus
oInput.onfocus = function(){
console.log("获取到了焦点");
}
(2).监听input失去焦点事件
- onblur
oInput.onblur = function() {
console.log("失去了焦点");
}
(3).监听input内容改变事件
- onchange
// 注意点: onchange事件只有表单失去焦点的时候, 才能拿到修改之后的数据
oInput.onchange = function(){
console.log(this.value);
}
(4).监听input实时内容改变事件
- oninput
// 可以时时获取到用户修改之后的数据, 只要用户修改了数据就会调用(执行)
// 注意点: oninput事件只有在IE9以及IE9以上的浏览器才能使用
// 在IE9以下, 如果想时时的获取到用户修改之后的数据, 可以通过onpropertychange事件来实现
oInput.oninput = function(){
console.log(this.value);
}
7.闭包
(1).什么是闭包(closure)
- 闭包是一种特殊的函数
(2).如何生成一个闭包
- 当一个内部函数引用了外部函数的数据(变量/函数)时, 那么内部的函数就是闭包;
- 所以只要满足两个条件:"是函数嵌套"、"内部函数引用外部函数数据";
(3).闭包的特点
- 只要闭包还在使用外部函数的数据, 那么外部的数据就一直不会被释放; 也就是说可以延长外部函数数据的生命周期
(4).闭包的注意点
- 当后续不需要使用闭包时候, 一定要手动将闭包设置为null, 否则会出现内存泄漏
function test() {
var i = 666; // 局部变量
} // 只要代码执行到了大括号结束, i这个变量就会自动释放
console.log(i); // Uncaught ReferenceError: i is not defined
function test() {
var i = 888;
// 由于demo函数满足闭包的两个条件, 所以demo函数就是闭包
return function demo() {
console.log(i);
};
}
let fn = test();
fn(); // 888
8.索引同步
- 默认情况下是:顺序结构, 代码会从上至下的执行, 前面的没执行完后面的不能执行
- 默认情况下:通过 var 定义的变量, 只要不是定义在函数中,都是全局变量
// 无法同步
for(var i=0; i<3; i++){
// console.log(i);
function test() {
console.log(i); // 3
}
}
// console.log(i); // 3
test();
// 可以同步
for(var i=0; i<3; i++){ // 0 1 2 3
// console.log(i);
function test() {
console.log(i); // 0 1 2
}
test();
}
for(var i = 0; i < 3; i++){ // 0 1 2 3
// 立即执行函数(等价于以下代码)
(function test(index) {
console.log(index); // 0 1 2
})(i);
// function test(index) { // var index = i;
// console.log(index); // 0 1 2
// }
// test(i);
}
闭包 + 索引同步 练习1:
<body>
<button>我是按钮1</button>
<button>我是按钮2</button>
<button>我是按钮3</button>
<script>
let oButtons = document.querySelectorAll("button");
// for(var i=0; i<oButtons.length; i++){
// oButton = oButtons[i];
// oButton.onclick = function () {
// console.log(i); //此时无论点击哪个按钮,输出都是3
// }
// }
for(var i=0; i<oButtons.length; i++){
oButton = oButtons[i];
(function test(index){ // var index = i;
// console.log(index); // 0 1 2
// 注意点: onclick对应的方法由于满足了闭包的条件, 所以onclick对应的方法也是一个闭包
oButton.onclick = function () {
console.log(index);
}
})(i)
}
</script>
</body>
- 在ES6中,如果在循环中通过 let 定义的变量,那么这个变量是一个局部变量
- for循环中,通过 let 定义的变量,每次执行循环体都会重新定义一个新的,也就是每个循环体都有一个属于自己的变量
- 只要在块级作用域中定义了一个函数,并且这个函数中用到了块级作用域中的数据,那么这个函数就是闭包
// 这里的i是全局变量
for(var i=0; i<3; i++){
// console.log(i); // 0 1 2
function test() {
console.log(i); // 3
}
}
test();
// console.log(i); // 3
// 这里的i是局部变量
for(let i=0; i<3; i++){
// console.log(i); // 0 1 2
function test() {
console.log(i); // 2
}
}
test();
// console.log(i); // Uncaught ReferenceError: i is not defined
// var list = [];
// // 这里的i是全局变量
// for(var i = 0; i < 3; i++){ // 0 1 2 3
// var fn = function test() {
// console.log(i); // 3
// };
// // 将函数添加到列表中
// list.push(fn);
// }
// // console.log(i); // 3
// // console.log(list); // 三个函数
// list[0](); // 3
// list[1](); // 3
// list[2](); // 3
var list = [];
// 这里的i是局部变量
// 注意点: 由于i是局部变量, 所以每次执行完循环体,都会重新定义一个i变量
for(let i = 0; i < 3; i++){ // 0 1 2 3
var fn = function test() {
console.log(i); // 3
};
// 将函数添加到列表中
list.push(fn);
}
// console.log(i); // 3
// console.log(list);
list[0](); // 0
list[1](); // 1
list[2](); // 2
for(let i = 0; i < 3; i++){ // 0 1 2 3
// 注意点: 在ES6中由于{}是块级作用域, 所以只要在块级作用域中定义了一个函数
// 并且这个函数中用到了块级作用域中的数据, 那么这个函数就是闭包
function test() {
console.log(i); // 2
}
}
test(); // 2
闭包 + 索引同步 练习2:
<body>
<button>我是按钮1</button>
<button>我是按钮2</button>
<button>我是按钮3</button>
<script>
// 在ES6中
// 1.for循环中通过let定义的变量是一个局部变量
// 2.for循环中通过let定义的变量每次执行循环体都会重新定义一个新的
// 也就是每个循环体都有一个属于自己的变量
// 3.for循环中如果定义了函数, 这个函数用到了通过let定义的变量, 那么这个函数是一个闭包
// 获取元素
let oButtons = document.querySelectorAll("button");
// 遍历数组元素
for(let i=0; i<oButtons.length; i++){
// 获取button元素
let button = oButtons[i];
// 绑定点击事件
button.onclick = function (){
console.log(i);
}
}
</script>
</body>
9.排他思想
- 什么是排他思想
- 清除其它非选中元素的样式, 只设置当前选中元素样式
<!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>
ul{
width: 300px;
border: 1px solid black;
margin: 200px auto;
}
ul>li{
border: 1px solid pink;
height: 30px;
line-height: 30px;
}
.current{
background-color: pink;
}
</style>
</head>
<body>
<ul>
<li>我是第一个li</li>
<li>我是第二个li</li>
<li>我是第三个li</li>
<li>我是第四个li</li>
<li>我是第五个li</li>
</ul>
<script>
// 1.什么是排它思想 ?
// 清除其它非选中元素的样式, 只设置当前选中元素样式
// 获取元素列表
let oList = document.querySelectorAll("ul>li");
// console.log(oList);
// 保存上一次元素索引
let preIndex = 0
// 方式1:通过 let 定义变量
// 遍历元素列表
for(let i=0; i<oList.length; i++){
// 获取元素
let item = oList[i];
// 绑定点击事件
item.onclick = function (){
// 排它(先清理掉所有元素的样式,再重新设置选中元素样式)
// 但是这样很消耗性能,实质上只需要将上一个元素的样式清空即可
// for(let j = 0; j < oItems.length; j++){
// let li = oItems[j];
// li.className = "";
// }
// 清理上一个元素样式
let preItem = oList[preIndex];
preItem.className = "";
// 设置当前元素样式
this.className = "current";
preIndex = i;
}
}
// 方式2:通过 var 定义变量
// 遍历元素列表
for (var i = 0; i < oList.length; i++) {
// 获取元素
let item = oList[i];
(function (index){
// 绑定点击事件
item.onclick = function () {
// 清理上一个元素样式
let preItem = oList[preIndex];
preItem.className = "";
// 设置当前元素样式
this.className = "current";
preIndex = index;
}
})(i)
}
</script>
</body>
</html>
10.Tab选项卡-面向对象
<!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>Tab选项卡-面向对象</title>
<style>
*{
margin: 0;
padding: 0;
}
#tab{
width: 400px;
height: 300px;
border: 1px solid #000;
margin: 100px auto;
}
#tab_top{
list-style: none;
width: 100%;
height: 50px;
line-height: 50px;
text-align: center;
display: flex;
justify-content: space-between;
}
#tab_top>li{
width: 80px;
height: 100%;
background: skyblue;
border-right: 1px solid #ccc;
}
#tab_top>li:last-child{
border-right: none;
}
#tab_bottom{
width: 100%;
height: 250px;
}
#tab_bottom>.tab-content{
width: 100%;
height: 100%;
display: none;
}
.selected{
background: red !important;
}
</style>
</head>
<body>
<!--
在前端开发中如果id名称是由多个单词组成的, 那么建议使用下划线来连接
在前端开发中如果class名称是由多个单词组成的, 那么建议使用中划线来连接
-->
<div id="tab">
<ul id="tab_top">
<li class="tab-item selected">新闻</li>
<li class="tab-item">视频</li>
<li class="tab-item">音乐</li>
<li class="tab-item">军事</li>
<li class="tab-item">财经</li>
</ul>
<div id="tab_bottom">
<div class="tab-content">新闻的内容</div>
<div class="tab-content">视频的内容</div>
<div class="tab-content">音乐的内容</div>
<div class="tab-content">军事的内容</div>
<div class="tab-content">财经的内容</div>
</div>
</div>
<script>
// 面向过程 //
// // 1.获取元素
// let oItems = document.querySelectorAll("ul>li");
// let oDivs = document.querySelectorAll(".content");
// // 2.保存上一个设置样式的元素索引
// let previousIndex = 0;
// // 3.遍历列表元素
// for (let currentIndex = 0; currentIndex < oItems.length; currentIndex++) {
// let item = oItems[currentIndex];
// // 4.绑定点击事件
// item.onclick = function change() {
// // 4.1 清空上一个元素的样式
// // 修改列表背景颜色
// let preItem = oItems[previousIndex];
// preItem.className = "";
// // 修改div元素的display属性
// let preDiv = oDivs[previousIndex];
// preDiv.style.display = "none";
// // 4.2 设置当前点击元素的样式
// this.className = "current";
// let currentDiv = oDivs[currentIndex];
// currentDiv.style.display = "block";
// // 4.3 保存当前索引
// previousIndex = currentIndex;
// }
// }
// 面向对象 //
// 定义Tab类
class Tab{
// 构造函数
constructor(){
// 将获取的元素定义为Tab类的属性
this.tabItem = document.querySelectorAll(".tab-item");
this.tabContent = document.querySelectorAll(".tab-content");
this.previousIndex = 0;
// 设置默认选中的第一个tabContent的样式
this.tabContent[0].style.display = "block";
}
// 定义添加点击事件(修改对应元素的样式)方法
addClickEvent(){
// 遍历tabItem元素类表
for(let i=0; i<this.tabItem.length; i++){
let item = this.tabItem[i];
// 绑定点击事件
// item.onclick = function(){ // console.log(this); // item
item.onclick = () => {
// console.log(this); // Tab对象
// 1.清空上一个元素样式(排他思想)
let preItem = this.tabItem[this.previousIndex];
// preItem.className = "";
// 因为有两个类名,只需将第二个类名selected置空即可
preTabItem.className = preTabItem.className.replace("selected", "");
let precontent = this.tabContent[this.previousIndex];
precontent.style.display = "none";
// 2.设置当前点击元素样式
let currentItem = this.tabItem[i];
// currentItem.className = "selected";
currentItem.className = preTabItem.className + "selected";
let currentContent = this.tabContent[i];
currentContent.style.display = "block";
// 3.保存当前索引
this.previousIndex = i;
}
}
}
}
let table = new Tab();
table.addClickEvent();
</script>
</body>
</html>
11.全选-反选
<!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;
}
.music{
/* border: 1px solid black; */
/* 水平阴影的位置 垂直阴影的位置 阴影的大小 阴影的颜色*/
box-shadow: 0 0 5px #000;
width: 400px;
margin: 200px auto;
padding-left: 20px;
padding-right: 20px;
box-sizing: border-box;
}
.music>h3{
line-height: 40px;
text-align: center;
border-bottom: 1px solid #ccc;
/* margin-left: 20px;
margin-right: 20px; */
}
.music>ul{
list-style: none;
}
.music>ul>li{
border-bottom: 1px solid #ccc;
/* margin-left: 20px;
margin-right: 20px; */
}
.music>div{
line-height: 40px;
text-align: center;
}
</style>
</head>
<body>
<div class="music">
<h3>歌曲排行榜</h3>
<ul>
<li><input type="checkbox">醒着做梦</li>
<li><input type="checkbox">男人不应该让女人流泪</li>
<li><input type="checkbox">女人不应该让男人太累</li>
<li><input type="checkbox">狂浪</li>
<li><input type="checkbox">生僻字</li>
<li><input type="checkbox">沙漠骆驼</li>
<li><input type="checkbox">最美的期待</li>
<li><input type="checkbox">光年之外</li>
</ul>
<div>
<button id="all_select">全选</button>
<button id="cancel_select">取消全选</button>
<button id="reverse_select">反选</button>
</div>
</div>
<script>
// 1.获取元素
let oItems = document.querySelectorAll("input");
let allSelectButton = document.querySelector("#all_select");
let cancelSelectButton = document.querySelector("#cancel_select");
let reverseSelectButton = document.querySelector("#reverse_select");
// 2.监听全选按钮
allSelectButton.onclick = function(){
oItems.forEach(function (item){
// 在JS中,如果HTML标签的属性名称和取值名称一样时, 那么JS就会返回true
// item.checked = "checked"; // checked="checked" true
// console.log(item.checked); // 默认为false
item.checked = true;
});
}
// 3.监听取消全选按钮
cancelSelectButton.onclick = function () {
oItems.forEach(function (item) {
// item.checked = "";
item.checked = false;
});
}
// 4.监听反选按钮
reverseSelectButton.onclick = function () {
oItems.forEach(function (item) {
item.checked = !item.checked ;
});
}
</script>
</body>
</html>
12.Date 时间对象
(1).获取当前时间
let date = new Date();
console.log(date);
(2).获取当前时间距离世界标准时间(1970年1月1日)的毫秒
-
Date.now()
-
valueOf()
console.log(Date.now());
let date = new Date();
console.log(date.valueOf());
(3).创建指定时间
- 整体传入
- 单独传入(注意点:如果月份是单独传入的,那么会多一个月!)
let date1 = new Date("2021-6-10 15:23:09")
console.log(date1);
// 注意点: 在创建指定时间的时候, 如果月份是单独传入的, 那么会多一个月!
let date2 = new Date(2021, 5, 10, 15, 23, 9);
console.log(date2);
(4).获取指定时间年月日时分秒
-
getFullYear() # 年
-
getMonth() # 月 (注意:通过该方法获取到的月份会少一个月!)
-
getDate() # 日
-
getHours() # 时
-
getMinutes() # 分
-
getSeconds() # 秒
let date = new Date();
console.log(date);
console.log(date.getFullYear());
// 注意点; 通过getMonth方法获取到的月份会少一个月!
console.log(date.getMonth()+1);
console.log(date.getDate());
console.log(date.getHours());
console.log(date.getMinutes());
console.log(date.getSeconds());
(5).时间格式化
- 符合中国人习惯的时间展示方式:2021-6-10 15:39:10
let date = new Date();
// 定义时间格式化函数
// 2021-6-10 15:39:10
function formartDate(date){
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`
}
// 调用时间格式化函数
let res = formartDate(date)
console.log(res);
13.Date 时间对象-计算时间差值
- 需求:计算以下两个时间之间的差值
/*
1秒 = 1000毫秒 1分钟 = 60秒 1小时 = 60分钟 1天 = 24小时
*/
// 需求:计算以下两个时间之间的差值(10天1小时29分40秒)
let curDate = new Date("2020-4-19 22:30:20");
let remDate = new Date("2020-4-30 00:00:00");
// 1.得到两个时间之间的差值(毫秒)
let differTime = remDate - curDate;
// let differTime = remDate.valueOf() - curDate.valueOf();
console.log(differTime);
// 2.得到两个时间之间的差值(秒)
let differSecond = differTime / 1000;
// 3.得到两个时间相差的天数(相差的天数 = 相差的总秒数 / 每一天的秒数)
let day = parseInt(differSecond / (60 * 60 * 24));
console.log(day);
// 4.得到两个时间相差的小时(相差的小时 = 相差的总秒数 / 小时 % 24)
let hour = parseInt(differSecond / (60 * 60) % 24);
console.log(hour);
// 5.得到两个时间相差的分钟(相差的分钟 = 相差的总秒数 / 分钟 % 60)
let minute = parseInt(differSecond / 60 % 60);
console.log(minute);
// 6.得到两个时间相差的秒数(相差的秒数 = 相差的总秒数 % 60)
let second = parseInt(differSecond % 60);
console.log(second);
14.秒杀效果
- 秒杀效果:实质上就是 当前时间 距离 未来时间 的差值
<!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>Document</title>
<link rel="stylesheet" href="fonts/iconfont.css">
<style>
*{
margin: 0;
padding: 0;
}
.box{
width: 190px;
height: 270px;
/* border: 1px solid red; */
background-color: red;
margin: 100px auto;
text-align: center;
color: white;
/* box-sizing: border-box; */
}
.box>h3{
font-size: 26px;
padding-top: 30px;
}
/* 第一个p标签 */
.box>p:nth-of-type(1){
color: rgba(255,255,255,0.5);
margin-top: 5px;
}
.box>i{
font-size: 40px;
display: inline-block;
margin-top: 20px;
margin-bottom: 20px;
}
.box>.time{
/* 弹性定位 */
display: flex;
/* 两端留白,居中对齐 */
/* justify-content: center; */
/* 两端对齐,元素之间的间隔都相等 */
justify-content: space-between;
margin: 10px auto;
border: 1px solid green;
width: 140px;
box-sizing: border-box;
}
.box>.time>div{
width: 40px;
height: 40px;
line-height: 40px;
/* border: 1px solid black; */
background: #333;
font-weight: bold;
position: relative;
}
/* 伪元素::before 可用于在元素内容之前插入一些内容 */
.time>div::before{
content: "";
display: block;
width: 100%;
height: 2px;
background: #d00;
/* 子绝父相 */
position: absolute;
left: 0;
top: 50%;
/* 垂直居中 */
transform: translateY(-50%);
}
</style>
</head>
<body>
<div class="box">
<h3>京东秒杀</h3>
<p>FLASH DEALS</p>
<i class="iconfont icon-lightningbshandian"></i>
<p>本场距离结束还剩</p>
<div class="time">
<div class="hour">00</div>
<div class="minute">00</div>
<div class="second">00</div>
</div>
</div>
<script>
// 秒杀本质:当前时间 距离 未来时间 的差值
// 1.获取元素
let oHour = document.querySelector(".hour");
let oMinute = document.querySelector(".minute");
let oSecond = document.querySelector(".second");
// 2.设置未来时间
let remDate = new Date("2021-6-11 12:00:00");
// 3.定义计算时间差函数
// console.log(getDifferTime(remDate));
function getDifferTime(remDate, curDate=new Date()){
// 1.得到两个时间之间的差值(毫秒)
let differTime = remDate - curDate;
// 2.得到两个时间之间的差值(秒)
let differSecond = differTime / 1000;
// 3.得到两个时间相差的天数(相差的天数 = 相差的总秒数 / 每一天的秒数)
let day = parseInt(differSecond / (60 * 60 * 24));
// 如果不足两位数,则用0补齐!
day = day >=10 ? day : "0" + day;
// 4.得到两个时间相差的小时(相差的小时 = 相差的总秒数 / 小时 % 24)
let hour = parseInt(differSecond / (60 * 60) % 24);
hour = hour >= 10 ? dhoury : "0" + hour;
// 5.得到两个时间相差的分钟(相差的分钟 = 相差的总秒数 / 分钟 % 60)
let minute = parseInt(differSecond / 60 % 60);
minute = minute >= 10 ? minute : "0" + minute;
// 6.得到两个时间相差的秒数(相差的秒数 = 相差的总秒数 % 60)
let second = parseInt(differSecond % 60);
second = second >= 10 ? second : "0" + second;
// 以对象的形式返回
return {
"day": day,
"hour": hour,
"minute": minute,
"second": second
}
}
// 4.定义设置时间函数
function setTime(remDate){
let diffTime = getDifferTime(remDate);
// 将获得的差值设置为对应的div元素
oHour.innerText = diffTime.hour;
oMinute.innerText = diffTime.minute;
oSecond.innerText = diffTime.second;
}
// 需要先调用一次,否则进入后会看到初始时间是 00:00:00
setTime(remDate);
// 5.设置定时器,每秒重新设置一次时间
setInterval(() => {
setTime(remDate);
}, 1000);
</script>
</body>
</html>
15.时钟效果
<!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>Document</title>
<style>
*{
padding: 0;
margin: 0;
}
.clock{
/* 必须设置宽度和高度,且大于背景图片的尺寸,这样图片才能完全显示出来 */
width: 300px;
height: 600px;
margin: 100px auto;
background-image: url(images/clock.png);
position: relative;
/* border: 1px solid red; */
}
.clock>.box{
width: 120px;
height: 120px;
/* background-color: pink; */
/* 子绝父相 */
position: absolute;
bottom: 220px;
/* 左边距为宽度的50%,即盒子的左边框距离父元素盒子150px */
left: 50%;
/* 但是盒子本身又有120的宽度,所以还需要右移盒子本身宽度的50%,即60px */
/* transform: translateX(-60px); */
transform: translateX(-50%);
/* 在绝对定位中 margin: 0 auto; 让盒子本身垂直居中对齐 会失效 */
/* margin: 0 auto; */
}
.hour, .minute, .second{
width: 6px;
height: 120px;
/* 子绝父相 */
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.clock>.box>.hour{
background-image: url(images/hour.png);
}
.clock>.box>.minute{
background-image: url(images/minute.png);
}
.clock>.box>.second{
background-image: url(images/second.png);
}
</style>
</head>
<body>
<div class="clock">
<div class="box">
<div class="hour"></div>
<div class="minute"></div>
<div class="second"></div>
</div>
</div>
<script>
// 1.获取元素
let oHour = document.querySelector(".hour");
let oMinute = document.querySelector(".minute");
let oSecond = document.querySelector(".second");
// 2.定义设置时间函数
function setTime(){
// 2.1 获取当前时间
let currentTime = new Date();
// 2.2 设置 transform 旋转度数 属性
// 360 度 / 12 小时 = 30 度 (一个小时旋转30度)
oHour.style.transform = `rotate(${currentTime.getHours() * 30}deg)`;
// 360 度 / 12 * 5 分钟 / 6 度 (一个分钟旋转6度)
oMinute.style.transform = `rotate(${currentTime.getMinutes() * 6}deg)`;
// 360 度 / 60 秒 = 6 度 (一个秒钟旋转6度)
oSecond.style.transform = `rotate(${currentTime.getSeconds() * 6}deg)`;
}
console.log(new Date());
setTime();
// 3.设置定时器,每隔1秒钟重新设置时间
setInterval(() => {
setTime();
}, 1000);
</script>
</body>
</html>
16.长图效果
17.匀速动画
<!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;
}
.box {
width: 100px;
height: 100px;
background: red;
}
.line1, .line2 {
width: 500px;
height: 20px;
background: blue;
}
.line2 {
width: 200px;
background: purple;
}
</style>
</head>
<body>
<button id="start1">开始到500</button>
<button id="start2">开始到200</button>
<button id="end">结束</button>
<div class="box"></div>
<div class="line1"></div>
<div class="line2"></div>
<script>
// 1.获取元素
let startBtn1 = document.querySelector("#start1");
let startBtn2 = document.querySelector("#start2");
let endBtn = document.querySelector("#end");
let oDiv = document.querySelector(".box");
// // 2.绑定点击事件
// let timer1 = null;
// startBtn1.onclick = function(){
// // 当再次点击按钮时,关闭上一次的定时器!
// clearInterval(timer1);
// // 3.记录终点位置
// let target = 500;
// // 4.设置定时器
// timer1 = setInterval(() => {
// // 4.1 获取当前元素位置
// // 初始位置是由css设置的,oDiv.style.marginLeft方式无法获取,所以需要单独设置一个0
// let curposition = parseInt(oDiv.style.marginLeft) || 0;
// // let curposition = parseInt(getComputedStyle(oDiv).marginLeft);
// // 4.2 设置步长
// let step = 11;
// // 4.3 计算新的位置
// curposition += step;
// console.log(target - curposition, step);
// // 4.4 判断是否超过终点位置
// // if(curposition >= target){
// if (Math.abs(target - curposition) <= Math.abs(step)) {
// clearInterval(timer1);
// // 当target/step步长为小数时,默认偏移量就会多出一点,所以当它大于500后,需要手动复位到最大偏移量即可,
// curposition = target;
// }
// // 4.5 重新设置元素的位置
// oDiv.style.marginLeft = curposition + "px";
// }, 100);
// }
// let timer2 = null;
// startBtn2.onclick = function () {
// // 当再次点击按钮时,关闭上一次的定时器!
// clearInterval(timer2);
// // 3.记录终点位置
// let target = 200;
// // 4.设置定时器
// timer2 = setInterval(() => {
// // 4.1 获取当前元素位置
// // 初始位置是由css设置的,oDiv.style.marginLeft方式无法获取,所以需要单独设置一个0
// let curposition = parseInt(oDiv.style.marginLeft) || 0;
// // let curposition = parseInt(getComputedStyle(oDiv).marginLeft);
// // 4.2 设置步长
// let step = -11;
// // 4.3 计算新的位置
// curposition += step;
// // 4.4 判断是否超过终点位置
// console.log(Math.abs(target - curposition), Math.abs(step));
// // if(begin >= target){
// if (Math.abs(target - curposition) <= Math.abs(step)) {
// clearInterval(timer2);
// // 当target/step步长为小数时,默认偏移量就会多出一点,所以当它大于500后,需要手动复位到最大偏移量即可,
// curposition = target;
// }
// // 4.5 重新设置元素的位置
// oDiv.style.marginLeft = curposition + "px";
// }, 100);
// }
// endBtn.onclick = function () {
// clearInterval(timer1);
// clearInterval(timer2);
// }
let timer = null;
// 两个按钮绑定的事件只是 target终点位置 与 step步长 不同而已
startBtn1.onclick = function (){
linearAnimation(oDiv, 500);
}
startBtn2.onclick = function () {
linearAnimation(oDiv, 200);
}
endBtn.onclick = function () {
clearInterval(timer);
}
// 将匀速移动封装为一个函数!
function linearAnimation(ele, target) {
// 当再次点击按钮时,关闭上一次的定时器!
clearInterval(timer);
// 4.设置定时器
timer = setInterval(() => {
// 4.1 获取当前元素位置
// 初始位置是由css设置的,oDiv.style.marginLeft方式无法获取,所以需要单独设置一个0
let curposition = parseInt(ele.style.marginLeft) || 0;
// let curposition = parseInt(getComputedStyle(oDiv).marginLeft);
// 4.2 设置步长
// 0 - 500 = -500 13
// 500 - 200 = 300 -13
let step = (curposition - target) > 0 ? -13 : 13;
// 4.3 计算新的位置
curposition += step;
console.log(target - curposition, step);
// 4.4 判断是否超过终点位置
// if(curposition >= target){
if (Math.abs(target - curposition) <= Math.abs(step)) {
clearInterval(timer);
// 当target/step步长为小数时,默认偏移量就会多出一点,所以当它大于500后,需要手动复位到最大偏移量即可,
curposition = target;
}
// 4.5 重新设置元素的位置
oDiv.style.marginLeft = curposition + "px";
}, 100);
}
</script>
</body>
</html>
18.缓动动画
19.轮播图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>轮播图</title>
<style>
*{
padding: 0;
margin: 0;
}
.box{
width: 670px;
height: 300px;
border: 1px solid skyblue;
margin: 100px auto;
position: relative;
overflow: hidden;
}
ul{
list-style: none;
display: flex;
}
p{
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
/*border: 1px solid yellowgreen;*/
/* 一定要设置宽度 */
width: 100%;
/* 弹性定位 */
display: flex;
/* 两端对齐,中间空隙相等*/
justify-content: space-between;
}
p>span{
width: 30px;
height: 60px;
background: rgba(0,0,0,0.5);
font-size: 40px;
color: #fff;
text-align: center;
line-height: 60px;
}
</style>
</head>
<body>
<div class="box">
<ul>
<li><img src="images/ad1.jpg"></li>
<li><img src="images/ad2.jpg"></li>
<li><img src="images/ad3.jpg"></li>
</ul>
<p>
<span class="left"><</span>
<span class="right">></span>
</p>
</div>
<script>
// 1.获取元素
let oLeft = document.querySelector(".left");
let oRight = document.querySelector(".right");
let oUl = document.querySelector("ul");
let oItems = document.querySelectorAll("ul>li");
let imgWidth = parseFloat(getComputedStyle(oItems[0]).width);
// 2.绑定点击事件
let currentIndex = 0;
oRight.onclick = function () {
currentIndex++;
// 当滑动到最后一张图片,就将currentIndex置为 0
if(currentIndex > oItems.length-1){
currentIndex = 0;
}
// oUl.style.marginLeft = -(imgWidth * currentIndex) + "px";
// 调用动画函数
// linearAnimation(oUl, -(imgWidth * currentIndex));
easeAnimation(oUl, -(imgWidth * currentIndex));
};
oLeft.onclick = function () {
currentIndex--;
// 当滑动到第一张图片,就将currentIndex置为 长度-1
if(currentIndex < 0){
currentIndex = oItems.length-1;
}
// oUl.style.marginLeft = -(imgWidth * currentIndex) + "px";
// 调用动画函数
// linearAnimation(oUl, -(imgWidth * currentIndex));
easeAnimation(oUl, -(imgWidth * currentIndex));
};
let timerId = null;
// 匀速动画
function linearAnimation(ele, target) {
clearInterval(timerId);
timerId = setInterval(function () {
// 1.拿到元素当前的位置
let begin = parseInt(ele.style.marginLeft) || 0;
// 2.定义变量记录步长
// 0 - 500 = -500 13
// 500 - 200 = 300 -13
let step = (begin - target) > 0 ? -13 : 13;
// 3.计算新的位置
begin += step;
console.log(Math.abs(target - begin), Math.abs(step));
if(Math.abs(target - begin) <= Math.abs(step)){
clearInterval(timerId);
begin = target;
}
// 4.重新设置元素的位置
ele.style.marginLeft = begin + "px";
}, 100);
}
// 缓速动画
function easeAnimation(ele, target) {
clearInterval(timerId);
timerId = setInterval(function () {
// 1.拿到元素当前的位置
let begin = parseInt(ele.style.marginLeft) || 0;
// 2.定义变量记录步长
// 公式: (结束位置 - 开始位置) * 缓动系数(0 ~1)
let step = (target - begin) * 0.3;
console.log(step);
// 3.计算新的位置
begin += step;
if (Math.abs(Math.floor(step)) <= 1) {
clearInterval(timerId);
begin = target;
}
// 4.重新设置元素的位置
ele.style.marginLeft = begin + "px";
}, 100);
}
// 存在的问题:按下oRight,图片列表会整体左移,当移动到最后一张图片时,再按键时会发现不会平滑的向左移动
// 同理可知,按下oLeft,图片列表会整体右移,当移动到第一张图片时,再按键时会发现不会平滑的向右移动
</script>
</body>
</html>
20.无限轮播图
思路:在最后一张图片后面再添加第一张图片,当移动到最后一张/第一张时,快速跳转至第一张/最后一张即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>无限轮播图</title>
<style>
*{
padding: 0;
margin: 0;
}
.box{
width: 670px;
height: 300px;
border: 1px solid skyblue;
margin: 100px auto;
position: relative;
overflow: hidden;
}
ul{
list-style: none;
display: flex;
}
p{
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
/*border: 1px solid yellowgreen;*/
/* 一定要设置宽度 */
width: 100%;
/* 弹性定位 */
display: flex;
/* 两端对齐,中间空隙相等*/
justify-content: space-between;
}
p>span{
width: 30px;
height: 60px;
background: rgba(0,0,0,0.5);
font-size: 40px;
color: #fff;
text-align: center;
line-height: 60px;
}
</style>
</head>
<body>
<div class="box">
<ul>
<li><img src="images/ad1.jpg"></li>
<li><img src="images/ad2.jpg"></li>
<li><img src="images/ad3.jpg"></li>
<!-- 在最后一张图片添加第一张图片! -->
<li><img src="images/ad1.jpg"></li>
</ul>
<p>
<span class="left"><</span>
<span class="right">></span>
</p>
</div>
<script>
// 1.获取元素
let oLeft = document.querySelector(".left");
let oRight = document.querySelector(".right");
let oUl = document.querySelector("ul");
let oItems = document.querySelectorAll("ul>li");
let imgWidth = parseFloat(getComputedStyle(oItems[0]).width);
// 2.绑定点击事件
let currentIndex = 0;
oRight.onclick = function () {
currentIndex++;
// 当滑动到最后一张图片,就将currentIndex置为 0
if(currentIndex > oItems.length-1){
currentIndex = 0;
// 快速的跳转到第一张 !
oUl.style.marginLeft = -currentIndex * imgWidth + "px";
currentIndex++;
}
// oUl.style.marginLeft = -(imgWidth * currentIndex) + "px";
// 调用动画函数
// linearAnimation(oUl, -(imgWidth * currentIndex));
easeAnimation(oUl, -(imgWidth * currentIndex));
};
oLeft.onclick = function () {
currentIndex--;
// 当滑动到第一张图片,就将currentIndex置为 长度-1
if(currentIndex < 0){
currentIndex = oItems.length-1;
// 快速的跳转到最后一张 !
oUl.style.marginLeft = -(imgWidth * currentIndex) + "px";
currentIndex--;
}
// oUl.style.marginLeft = -(imgWidth * currentIndex) + "px";
// 调用动画函数
// linearAnimation(oUl, -(imgWidth * currentIndex));
easeAnimation(oUl, -(imgWidth * currentIndex));
};
let timerId = null;
// 匀速动画
function linearAnimation(ele, target) {
clearInterval(timerId);
timerId = setInterval(function () {
// 1.拿到元素当前的位置
let begin = parseInt(ele.style.marginLeft) || 0;
// 2.定义变量记录步长
// 0 - 500 = -500 13
// 500 - 200 = 300 -13
let step = (begin - target) > 0 ? -13 : 13;
// 3.计算新的位置
begin += step;
console.log(Math.abs(target - begin), Math.abs(step));
if(Math.abs(target - begin) <= Math.abs(step)){
clearInterval(timerId);
begin = target;
}
// 4.重新设置元素的位置
ele.style.marginLeft = begin + "px";
}, 100);
}
// 缓速动画
function easeAnimation(ele, target) {
clearInterval(timerId);
timerId = setInterval(function () {
// 1.拿到元素当前的位置
let begin = parseInt(ele.style.marginLeft) || 0;
// 2.定义变量记录步长
// 公式: (结束位置 - 开始位置) * 缓动系数(0 ~1)
let step = (target - begin) * 0.3;
console.log(step);
// 3.计算新的位置
begin += step;
if (Math.abs(Math.floor(step)) <= 1) {
clearInterval(timerId);
begin = target;
}
// 4.重新设置元素的位置
ele.style.marginLeft = begin + "px";
}, 100);
}
</script>
</body>
</html>
21.自动轮播图
// 1.设置定时器
let id = setInterval(function () {
// 调用点击事件函数
oLeft.onclick();
},2000);
// 2.监听鼠标移入事件
oBox.onmouseenter = function(){
// 关闭定时器
clearInterval(id);
};
// 3.监听鼠标移出事件
oBox.onmouseleave = function(){
// 重新开启定时器
id = setInterval(function () {
oLeft.onclick();
},2000);
};
22.匀速动画-加强版
<!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;
}
.box {
width: 100px;
height: 100px;
background: red;
}
.line1,
.line2 {
width: 500px;
height: 20px;
background: blue;
}
.line2 {
width: 200px;
background: purple;
}
</style>
</head>
<body>
<button id="start1">开始到500</button>
<button id="start2">开始到200</button>
<button id="end">结束</button>
<div class="box"></div>
<div class="line1"></div>
<div class="line2"></div>
<script>
// 1.获取元素
let startBtn1 = document.querySelector("#start1");
let startBtn2 = document.querySelector("#start2");
let endBtn = document.querySelector("#end");
let oDiv = document.querySelector(".box");
let timer = null;
// 3.绑定点击事件(两个按钮绑定的事件只是 target终点位置 与 step步长 不同而已)
startBtn1.onclick = function () {
// linearAnimation(oDiv, "width", 500);
// linearAnimation(oDiv, "marginLeft", 500);
// linearAnimation(oDiv, "marginTop", 500);
// linearAnimation(oDiv, {"marginTop": 500, "marginLeft": 300}, function(){
// alert("动画执行完毕之后,执行的其他操作");
// });
linearAnimation(oDiv, { "marginTop": 500, "marginLeft": 300 });
}
startBtn2.onclick = function () {
// linearAnimation(oDiv, "width", 200);
// linearAnimation(oDiv, "marginLeft", 500);
// linearAnimation(oDiv, "marginTop", 500);
}
endBtn.onclick = function () {
clearInterval(timer);
}
// 2.将匀速动画封装为一个函数!
// 改进点1:如果想让动画水平(marginLeft)、垂直(marginTop)移动或者让高度(width)执行动画,每次都需要修改函数内部封装好的代码,这样很不方便
// 优化:直接给函数再添加一个attr参数,用于指定执行动画元素的属性,此时直接修改调用函数的参数即可实现水平、垂直、宽度动画
// function linearAnimation(ele, attr, target) {
// 需求: 多个属性 同时 执行动画
function linearAnimation(ele, obj, fn) {
// 当再次点击按钮时,关闭上一次的定时器!
clearInterval(timer);
// 设置定时器
timer = setInterval(() => {
// 用于标记是否 所有属性 都执行完了动画
let flag = true;
for (let key in obj) {
let attr = key;
let target = obj[key];
// 2.1 获取当前元素位置
// 初始位置是由css设置的,oDiv.style.marginLeft方式无法获取,所以需要单独设置一个0
// let begin = parseInt(ele.style.marginLeft) || 0; // 水平向右移动
// let begin = parseInt(getComputedStyle(oDiv).marginLeft);
// let begin = parseInt(ele.style.marginTop) || 0; // 垂直向下移动
// let begin = parseInt(getComputedStyle(oDiv).width); // 从当前宽度开始执行动画
let style = getComputedStyle(ele);
// let begin = parseInt(style.width);
// let begin = parseInt(style["width"]);
let begin = parseInt(style[attr]);
// 2.2 设置步长
// 0 - 500 = -500 13
// 500 - 200 = 300 -13
let step = (begin - target) > 0 ? -13 : 13;
// 2.3 计算新的位置
begin += step;
// console.log(target - begin, step);
// 2.4 判断是否超过终点位置
// if(begin >= target){
// if (Math.abs(target - begin) <= Math.abs(step)) {
// clearInterval(timer);
// // 当target/step步长为小数时,默认偏移量就会多出一点,所以当它大于500后,需要手动复位到最大偏移量即可,
// begin = target;
// }
if (Math.abs(target - begin) > Math.abs(step)) {
// 如果动画没有执行完就将flag变量置为false
flag = false;
}
else{
// 当target/step步长为小数时,默认偏移量就会多出一点,所以当它大于500后,需要手动复位到最大偏移量即可,
begin = target;
}
// 2.5 重新设置元素的位置
// ele.style.marginLeft = begin + "px";
// ele.style.marginTop = begin + "px";
// ele.style.width = begin + "px";
// ele.style["width"] = begin + "px";
ele.style[attr] = begin + "px";
}
if(flag){
// 当所有属性的动画都执行完了,再关闭定时器
clearInterval(timer);
// fn();
// 当动画执行完毕后,如果传递了fn函数则,执行fn函数
// if(fn){
// fn();
// }
// fn为真,则执行fn()
fn && fn();
}
}, 100);
}
</script>
</body>
</html>
23.缓速动画-加强版
// 缓速动画函数
function easeAnimation(ele, obj, fn) {
clearInterval(ele.timerId);
ele.timerId = setInterval(function () {
let flag = true;
for (let key in obj) {
let target = obj[key];
// 1.拿到元素当前的位置
let style = getComputedStyle(ele);
let begin = parseInt(style[key]) || 0;
// 2.定义变量记录步长
// 公式: (结束位置 - 开始位置) * 缓动系数(0 ~1)
let step = (target - begin) * 0.3;
// 3.计算新的位置
begin += step;
if (Math.abs(Math.floor(step)) > 1) {
flag = false;
} else {
begin = target;
}
// 4.重新设置元素的位置
ele.style[key] = begin + "px";
}
if (flag) {
clearInterval(ele.timerId);
fn && fn();
}
}, 100);
}
24.联动动画-关闭弹窗
<!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;
}
.box{
position: fixed;
right: 0;
bottom: 0;
}
.top{
width: 320px;
height: 302px;
overflow: hidden;
}
.bottom{
width: 320px;
height: 102px;
overflow: hidden;
}
span{
display: inline-block;
width: 30px;
height: 30px;
/* background-color: red; */
position: absolute;
right: 0;
top: 0;
}
</style>
</head>
<body>
<div class="box">
<div class="top">
<img src="images/top.jpg">
</div>
<div class="bottom">
<img src="images/bottom.jpg">
</div>
<span></span>
</div>
<!-- 引入js文件(封装了匀速动画、缓速动画函数) -->
<script src="js/animation2.js"></script>
<script>
// 1.获取元素
let oBoxDiv = document.querySelector(".box");
let oTopDiv = document.querySelector(".top");
let oBottomDiv = document.querySelector(".bottom");
let oCloseBtn = document.querySelector("span");
// 2.绑定点击事件
oCloseBtn.onclick = function(){
// 调用 匀速动画 函数 or 缓速动画 函数
// 参数解释:
// ele: 需要执行动画的元素
// obj: {key: value} key:执行动画的属性 value:动画结束时的属性取值
// fn: 动画执行完毕之后,需要执行的操作
// linearAnimation(oTopDiv, { "height": 0 }, function(){
easeAnimation(oTopDiv, { "height": 0 }, function () {
// 问题:动画执行的方向不对,因为box的right一直都是0,如果是让oBottomDiv执行动画,那么它会从右至左的移动
// linearAnimation(oBottomDiv, { "width": 0 }, function() {
// 改进:直接让整个盒子oBoxDiv的宽度执行动画即可
easeAnimation(oBoxDiv, { "width": 0 }, function () {
// 删除oBoxDiv元素
oBoxDiv.parentNode.removeChild(oBoxDiv);
});
});
}
</script>
</body>
</html>
25.添加事件的三种方式
- 方式1:通过 onxxx 的方式来添加
- 注意点:由于是给属性赋值, 所以后赋值的会覆盖先赋值的
oButton.onclick = function() {
alert("666");
}
oButton.onclick = function () {
alert("777");
}
- 方式2:通过 addEventListener 方法添加
- 注意点
- 1.事件名称不需要添加 on
- 2.后添加的不会覆盖先添加的
- 3.只支持最新的浏览器 IE9
oButton.addEventListener("click", function(){
alert("666");
})
oButton.addEventListener("click", function () {
alert("777");
})
- 方式3:通过 attachEvent 方法添加
- 注意点
- 1.事件名称必须加上on
- 2.后添加的不会覆盖先添加的
- 3.只支持低版本的浏览器
oButton.attachEvent("onclick", function () {
alert("666");
});
oButton.attachEvent("onclick", function () {
alert("777");
});
为了提高浏览器的兼容性,自定义一个函数
addEvent(oButton, "click", function(){
alert("666");
})
// 为了提高浏览器的兼容性,自定义一个函数
function addEvent(ele, name, fn) {
// 如果是低版本的浏览器,则ele.attachEvent存在,就使用attachEvent方法
if (ele.attachEvent) {
ele.attachEvent("on" + name, fn);
}
// 高版本的浏览器,就使用addEventListener方法
else {
ele.addEventListener(name, fn);
}
}
26.事件对象
(1).什么是事件对象
- 事件对象就是一个系统自动创建的一个对象
- 当注册(绑定)的事件被触发的时候, 系统就会自动创建事件对象
(2).事件对象的注意点
- 在高级版本的浏览器中, 会自动将事件对象传递给回调函数
- 在低级版本的浏览器中, 不会自动将事件对象传递给回调函数
- 在低级版本的浏览器中, 需要通过 window.event 来获取事件对象
<button id="btn">我是按钮</button>
<a href="http://www.it666.com">知播渔教育</a>
<script>
let oBtn = document.querySelector("#btn");
oBtn.onclick = function(event){
// alert("666");
// console.log(event);
// 当触发点击事件时,系统就会自动创建事件对象
// console.log(typeof event); // object
// 提高 浏览器兼容性 的写法
event = event || window.event;
console.log(event);
}
let oA = document.querySelector("a");
oA.onclick = function (event) {
alert("666");
// 阻止默认行为(阻止a链接的页面跳转)
// 方式1:
return false; // 推荐
// 方式2:
// event.preventDefault(); // 只支持高级版本的浏览器
// event.returnValue = false; // 只支持低版本IE9以下的浏览器
}
</script>
27.事件执行的三个阶段
(1).事件执行的三个阶段
- 1.1.捕获阶段 (从外向内的传递事件)
- 1.2.当前目标阶段 (执行回调函数)
- 1.3.冒泡的阶段 (从内向外的传递事件/抛出事件)
(2).注意点
- 三个阶段,只有两个会被同时执行, 要么捕获和当前, 要么当前和冒泡
(3).为什么要么只能是捕获和当前, 要么只能是当前和冒泡
- 这是JS处理事件的历史问题, 早期各大浏览器厂商为占领市场, 以及对事件的理解不同, 后续W3C为了兼容, 将两种方式都纳入标准
<style>
* {
margin: 0;
padding: 0;
}
.father {
width: 300px;
height: 300px;
background: red;
}
.son {
width: 150px;
height: 150px;
background: blue;
}
</style>
<div class="father">
<div class="son"></div>
</div>
捕获:(点击子元素)
let oFDiv = document.querySelector(".father");
let oSDiv = document.querySelector(".son");
// true 捕获
oFDiv.addEventListener("click", function () {
console.log("father");
}, true);
oSDiv.addEventListener("click", function () {
console.log("son");
}, true);
冒泡:(点击子元素)
// false 冒泡
// oFDiv.addEventListener("click", function () {
// console.log("father");
// }, false);
// oSDiv.addEventListener("click", function () {
// console.log("son");
// }, false);
// 冒泡
oFDiv.onclick = function () {
console.log("father");
}
oSDiv.onclick = function () {
console.log("son");
}
事件冒泡-列表选项:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件冒泡-列表选项</title>
<style>
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
width: 300px;
margin: 100px auto;
border: 1px solid #000;
}
.selected {
background: red;
}
</style>
</head>
<body>
<ul>
<li class="selected">我是第1个li</li>
<li>我是第2个li</li>
<li>我是第3个li</li>
<li>我是第4个li</li>
<li>我是第5个li</li>
</ul>
<script>
// 方式1:
// let oList = document.querySelectorAll("ul>li");
// // 首先将第一个li设置为currentItem
// let currentItem = oList[0];
// for(let item of oList){
// item.onclick = fn;
// }
// function fn() {
// // 清空上一个元素的背景颜色 (排他思想)
// currentItem.className = "";
// // 设置当前点击元素的背景颜色
// this.className = "selected";
// // 保存当前元素
// currentItem = this;
// }
// 方式2:事件冒泡
let oUl = document.querySelector("ul");
// 1.获取第一个li元素,保存到oLi变量中
let oLi = document.querySelector(".selected");
oUl.onclick = function(event){
// 兼容性写法
event = event || window.event;
// 2.清空上一个元素的背景颜色 (排他思想)
oLi.className = "";
// 3.设置当前点击元素的背景颜色
// console.log(event.target); // 被点击li元素
let item = event.target;
item.className = "selected";
// 4.保存当前元素
oLi = item;
}
</script>
</body>
</html>
阻止事件冒泡:
<style>
* {
margin: 0;
padding: 0;
}
.father {
width: 300px;
height: 300px;
background: red;
}
.son {
width: 150px;
height: 150px;
background: blue;
}
</style>
<div class="father">
<div class="son"></div>
</div>
<script>
// 1.拿到需要操作的元素
var oFDiv = document.getElementById("father");
var oSDiv = document.getElementById("son");
// 2.注册(绑定)监听事件
oFDiv.onclick = function () {
console.log("father");
}
// 默认就是事件冒泡
// oSDiv.onclick = function () {
// console.log("son");
// }
// 阻止事件冒泡
oSDiv.onclick = function (event) {
// 1.获取事件对象
event = event || window.event;
// event.stopPropagation(); // 只支持高级浏览器
// event.cancelBubble = true; // 只支持低级浏览器
// 2.提高 兼容性 的写法
if (event.cancelBubble) {
event.cancelBubble = true;
} else {
event.stopPropagation();
}
console.log("son");
}
</script>
移入移出事件的区别:
- 1.onmouseover 和 onmouseenter 的区别
- onmouseover 移入到子元素, 父元素的移入事件也会被触发
- onmouseenter 移入到子元素, 父元素的移入事件不会被触发
- 2.onmouseout 和 onmouseleave 的区别
- onmouseout 移出到子元素, 父元素的移入事件也会被触发
- onmouseleave 移出到子元素, 父元素的移入事件不会被触发
<style>
* {
margin: 0;
padding: 0;
}
.father {
width: 300px;
height: 300px;
background: red;
}
.son {
width: 150px;
height: 150px;
background: blue;
}
</style>
<div class="father">
<div class="son"></div>
</div>
let oFDiv = document.querySelector(".father");
let oSDiv = document.querySelector(".son");
// oFDiv.onmouseover = function () {
// console.log("father");
// }
// oSDiv.onmouseover = function () {
// console.log("son");
// }
// oFDiv.onmouseenter = function () {
// console.log("father");
// }
// oSDiv.onmouseenter = function () {
// console.log("son");
// }
// oFDiv.onmouseout = function () {
// console.log("father");
// }
// oSDiv.onmouseout = function () {
// console.log("son");
// }
oFDiv.onmouseleave = function () {
console.log("father");
}
oSDiv.onmouseleave = function () {
console.log("son");
}
28.事件位置
- offsetX / offsetY:事件触发相对于 当前元素 自身的位置
- clientX / clientY:事件触发相对于 浏览器 可视区域 的位置
- 注意点:可视区域是不包括滚动出去的范围的
- pageX / pageY:事件触发相对于 整个网页 的位置
- 注意点:整个网页包括滚动出去的范围的
- screenX / screenY:事件触发相对于 屏幕(显示器) 的位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件位置获取</title>
<style>
* {
margin: 0;
padding: 0;
}
div {
width: 100px;
height: 100px;
background: red;
margin-left: 100px;
margin-top: 800px;
}
</style>
</head>
<body>
<div id="box"></div>
<script>
var oDiv = document.getElementById("box");
oDiv.onclick = function (event) {
// 获取event事件对象
event = event || window.event;
// console.log("offsetX", event.offsetX);
// console.log("offsetY", event.offsetY);
// console.log("clientX", event.clientX);
// console.log("clientY", event.clientY);
// console.log("----------------------");
// console.log("pageX", event.pageX);
// console.log("pageY", event.pageY);
console.log(event.screenX);
console.log(event.screenY);
}
</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>
*{
margin: 0;
padding: 0;
}
html, body{
width: 100%;
height: 100%;
overflow: hidden;
}
</style>>
</head>
<body>
<img src="images/pig.gif">
<script>
let oImg = document.querySelector("img");
// 1.获取oImg元素的初始样式
let style = getComputedStyle(oImg);
document.body.onmousemove = function(event){
// 2.获取事件
event = event || window.event;
// 3.重新设置图片的左外边距与上外边距
// 此时小猪佩奇确实在跟着鼠标移动,但是鼠标在佩奇的左上角
// oImg.style.marginLeft = event.clientX + "px";
// oImg.style.marginTop = event.clientY + "px";
// 想让鼠标在佩奇的正中心,只需将图片的左外边距再左移佩奇宽度的一半,且将图片的上外边距再上移佩奇高度的一半即可
// clientX / clientY: 事件触发相对于 浏览器 可视区域 的位置
oImg.style.marginLeft = event.clientX - parseFloat(style.width)/2 + "px";
oImg.style.marginTop = event.clientY - parseFloat(style.height)/2 + "px";
// oImg.style.marginLeft = event.pageX - parseFloat(style.width) / 2 + "px";
// oImg.style.marginTop = event.pageY - parseFloat(style.height) / 2 + "px";
}
</script>
</body>
</html>
29.正则表达式
(1).什么是正则表达式?
- 正则表达式就是对字符串操作的一种逻辑公式
(2).正则表达式的作用?
- 2.1 在字符串"查找"是否包含指定子串
- 2.2 从字符串中"提取"指定子串
- 2.3 对字符串中指定的内容进行"替换"
在学习正则表达式之前使用的方法:
// 1.字符串查找
let str = "123abc456";
let index = str.indexOf("abc");
let index = str.lastIndexOf("abc");
let flag = str.includes("abc");
// 2.字符串提取
let str = "123abc456";
let startIndex = str.indexOf("a");
console.log(str.substr(startIndex, "abc".length));
// 3.字符串替换
let str = "123abc456";
str.replace("abc", "it666");
1.通过正则表达式,匹配 / 查找字符
- 需求:查找字符串中是否包含某个字符
- 1.1 查找字符串中是否包含a/A
let str = "123abc456";
// 1.1 创建一个正则表达式对象,并指定匹配的规则
// 注意点: 默认情况下在正则表达式中是区分大小写的,i:不区分大小写
let reg = new RegExp("A", "i");
// 1.2 利用test方法匹配字符串
let res = reg.test(str);
console.log(res); // true
- 1.2 查找str字符串中是否包含日期
let str = "abc2020-1-11def";
// 2.1 通过构造函数创建正则表达式对象
// \d:匹配数字,第一个\表示转移,即\\表示一个\
// d{4}:匹配4个数字 d{1,2}:匹配1到2个数字
// let reg = new RegExp("\\d{4}-\\d{1,2}-\\d{1,2}");
// 2.2 通过字面量来创建正则表达式对象
let reg = /\d{4}-\d{1,2}-\d{1,2}/;
let res = reg.test(str);
console.log(res); // true
2.通过正则表达式,提取符合规则的字符串
let str = "abc2020-1-11def2019-11-11fdjsklf";
// 注意点:默认情况下在正则表达式中一旦匹配就会停止查找,g:全局匹配
let reg = /\d{4}-\d{1,2}-\d{1,2}/g;
let res = str.match(reg);
console.log(res);
console.log(res[0]);
console.log(res[1]);
3.通过正则表达式,替换符合规则的字符串
let str = "abc2020-1-11def2019-11-11fdjsklf";
let reg = /\d{4}-\d{1,2}-\d{1,2}/g;
// replace:替换字符串
let newStr = str.replace(reg, "it666");
console.log(str);
console.log(newStr);
常用正则表达式合集:
验证数字:^[0-9]*$
验证n位的数字:^\d{n}$
验证至少n位数字:^\d{n,}$
验证m-n位的数字:^\d{m,n}$
验证零和非零开头的数字:^(0|[1-9][0-9]*)$
验证有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
验证有1-3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
验证非零的正整数:^\+?[1-9][0-9]*$
验证非零的负整数:^\-[1-9][0-9]*$
验证非负整数(正整数 + 0) ^\d+$
验证非正整数(负整数 + 0) ^((-\d+)|(0+))$
验证长度为3的字符:^.{3}$
验证由26个英文字母组成的字符串:^[A-Za-z]+$
验证由26个大写英文字母组成的字符串:^[A-Z]+$
验证由26个小写英文字母组成的字符串:^[a-z]+$
验证由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
验证由数字、26个英文字母或者下划线组成的字符串:^\w+$
验证用户密码: ^[a-zA-Z]\w{5,17}$ 正确格式为:以字母开头,长度在6-18之间,只能包含字符、数字和下划线。
验证是否含有 ^%&',;=?$\" 等字符:[^%&',;=?$\x22]+
验证汉字:^[\u4e00-\u9fa5],{0,}$
验证Email地址:^\w+[-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
验证InternetURL:^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ ;^[a-zA-z]+://(w+(-w+)*)(.(w+(-w+)*))*(?S*)?$
验证电话号码:^(\d3,4|\d{3,4}-)?\d{7,8}$:--正确格式为:XXXX-XXXXXXX,XXXX-XXXXXXXX,XXX-XXXXXXX,XXX-XXXXXXXX,XXXXXXX,XXXXXXXX。
验证身份证号(15位或18位数字):^\d{15}|\d{}18$
验证一年的12个月:^(0?[1-9]|1[0-2])$ 正确格式为:“01”-“09”和“1”“12”
验证一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$ 正确格式为:01、09和1、31。
整数:^-?\d+$
非负浮点数(正浮点数 + 0):^\d+(\.\d+)?$
正浮点数: ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
非正浮点数(负浮点数 + 0): ^((-\d+(\.\d+)?)|(0+(\.0+)?))$
负浮点数: ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数: ^(-?\d+)(\.\d+)?$
30.日期格式化-高级版
// 获取当前时间
let crtTime = new Date();
console.log(crtTime); // Mon Jun 14 2021 20:16:37 GMT+0800 (中国标准时间)
/*
y 年 M 月 d 日
h 时 m 分 s 秒
*/
// 调用函数
let res1 = dateFormart("yyyy-MM-dd hh:mm:ss", crtTime);
let res2 = dateFormart("yy-MM-dd hh:mm:ss", crtTime);
let res3 = dateFormart("yyyy-M-dd hh:mm:ss", crtTime);
let res4 = dateFormart("yyyy-MM-dd ", crtTime);
let res5 = dateFormart("hh:mm:ss", crtTime);
console.log(res1); // 2021-06-14 20:16:37
console.log(res2); // 21-06-14 20:16:37
console.log(res3); // 2021-6-14 20:16:37
console.log(res4); // 2021-06-14
console.log(res5); // 20:16:37
// 定义日期格式化函数
function dateFormart(fmt, date) {
// 1.处理年份
// 1.1 通过正则表达式提取fmt字符串中的yyyy
let yearStr = fmt.match(/y+/);
if(yearStr){
yearStr = yearStr[0];
// console.log(yearStr);
// 1.2 获取当前时间的年份
// let yearNum = date.getFullYear();
// 如果fmt字符串是 yyyy,yyy,yy,y 四种情况
let yearNum = date.getFullYear() + "";
// 则使用substr方法:从4-yearStr.length开始截取
yearNum = yearNum.substr(4-yearStr.length); // 2021
// 1.3 将yyyy替换为当前时间的年份,并赋值给fmt字符串
fmt = fmt.replace(yearStr, yearNum);
// console.log(fmt);
}
// 2.处理其他时间(月 日 时 分 秒)
// 2.1 定义对象
// key:正则表达式(可以通过该正则表达式,获取fmt字符串中的 MM dd hh mm ss)
// value:当前时间的 月 日 时 分 秒
let obj = {
"M+": date.getMonth() + 1,
"d+": date.getDate(),
"h+": date.getHours(),
"m+": date.getMinutes(),
"s+": date.getSeconds()
};
// 2.2 遍历对象
for(let key in obj){
// 1. 通过构造函数,创建正则表达式对象
let reg = new RegExp(`${key}`);
// console.log(reg);
// 2. 提取fmt字符串中的 MM dd hh mm ss
let fmtStr = fmt.match(reg);
// console.log(fmtStr);
if(fmtStr){
fmtStr = fmtStr[0];
// 3. 将 MM dd hh mm ss 替换为 当前时间的 月 日 时 分 秒
// 3.1 如果fmt字符串是一位:比如 M
if(fmtStr.length === 1){
fmt = fmt.replace(fmtStr,obj[key]);
}
// 3.2 如果fmt字符串是两位:比如 MM
else{
// 给获取到的当前月份前面添加00
let numStr = "00" + obj[key];
// "00" + 4 = "004"
// "00" + 12 = "0012"
let strNum = obj[key] + "";
// 不管当前月份是4月(一位数)还是12月(两位数)都从strNum.length开始截取
numStr = numStr.substr(strNum.length);
fmt = fmt.replace(fmtStr, numStr);
}
}
}
return fmt;
}