目录

1.关闭广告

2.图片展示

3.鼠标的移入移出事件

4.商品展示

5.表单校验

6.焦点事件

7.闭包

8.索引同步

9.排他思想

10.Tab选项卡-面向对象

11.全选-反选

12.Date 时间对象

13.Date 时间对象-计算时间差值

14.秒杀效果

15.时钟效果

16.长图效果

17.匀速动画

18.缓动动画

19.轮播图

20.无限轮播图

21.自动轮播图

22.匀速动画-加强版

23.缓速动画-加强版

24.联动动画-关闭弹窗

25.添加事件的三种方式

26.事件对象

27.事件执行的三个阶段

28.事件位置

29.正则表达式

30.日期格式化-高级版


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="data:images/close.jpg" alt=""><img src="data: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="data:images/ad1.jpg" alt=""><ul><li><img src="data:images/ad1.jpg" alt=""></li><li><img src="data:images/ad2.jpg" alt=""></li><li><img src="data:images/ad3.jpg" alt=""></li><li><img src="data:images/ad4.jpg" alt=""></li><li><img src="data: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, 移入事件 建议使用 onmouseenteroDiv.onmouseenter = function () {console.log("鼠标移入事件");};

(2).鼠标移出事件

  • onmouseout
  • onmouseleave     (推荐使用)
        // 2.鼠标移出事件// oDiv.onmouseout = function () {//     console.log("鼠标移出事件");// };// 注意点: 对于初学者来说, 为了避免未知的一些BUG, 移出事件 建议使用 onmouseleaveoDiv.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="data:images/pic1.jpg" alt=""><ul><li><img src="data:images/pic1.jpg" alt=""></li><li><img src="data:images/pic2.jpg" alt=""></li><li><img src="data:images/pic3.jpg" alt=""></li><li><img src="data:images/pic4.jpg" alt=""></li><li><img src="data: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)   // 每一张小图片imagebigImage.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);   // 3test();
    // 可以同步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 2function test() {console.log(i);      // 3}}test();// console.log(i);           // 3// 这里的i是局部变量for(let i=0; i<3; i++){// console.log(i);     // 0 1 2function 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]();    // 3var list = [];// 这里的i是局部变量// 注意点: 由于i是局部变量, 所以每次执行完循环体,都会重新定义一个i变量for(let i = 0; i < 3; i++){     // 0 1 2 3var fn = function test() {console.log(i);         // 3};// 将函数添加到列表中list.push(fn);}// console.log(i);      // 3// console.log(list);list[0]();    // 0list[1]();    // 1list[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);   // itemitem.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);   // 默认为falseitem.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:10function 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:00setTime(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方式无法获取,所以需要单独设置一个0let curposition = parseInt(ele.style.marginLeft) || 0;// let curposition = parseInt(getComputedStyle(oDiv).marginLeft);// 4.2 设置步长//   0  -  500 = -500     13//   500 -  200 = 300    -13let 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="data:images/ad1.jpg"></li><li><img src="data:images/ad2.jpg"></li><li><img src="data:images/ad3.jpg"></li></ul><p><span class="left">&lt</span><span class="right">&gt</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置为 0if(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置为 长度-1if(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    -13let 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="data:images/ad1.jpg"></li><li><img src="data:images/ad2.jpg"></li><li><img src="data:images/ad3.jpg"></li><!--  在最后一张图片添加第一张图片! --><li><img src="data:images/ad1.jpg"></li></ul><p><span class="left">&lt</span><span class="right">&gt</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置为 0if(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置为 长度-1if(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    -13let 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    -13let 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变量置为falseflag = 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="data:images/top.jpg"></div><div class="bottom"><img src="data: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="data: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:37console.log(res2);      // 21-06-14 20:16:37console.log(res3);      // 2021-6-14 20:16:37console.log(res4);      // 2021-06-14console.log(res5);      // 20:16:37// 定义日期格式化函数function dateFormart(fmt, date) {// 1.处理年份// 1.1 通过正则表达式提取fmt字符串中的yyyylet 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 sslet fmtStr = fmt.match(reg);// console.log(fmtStr);if(fmtStr){fmtStr = fmtStr[0];// 3. 将 MM dd hh mm ss 替换为 当前时间的 月 日 时 分 秒// 3.1 如果fmt字符串是一位:比如 Mif(fmtStr.length === 1){fmt = fmt.replace(fmtStr,obj[key]);}// 3.2 如果fmt字符串是两位:比如 MMelse{// 给获取到的当前月份前面添加00let 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;}

JavaScript基础--DOM部分02--李南江相关推荐

  1. JavaScript基础 -- DOM

    JavaScript基础 -- DOM DOM 1.什么是DOM? 2.事件 3.文档的加载 3.DOM查询 4.DOM查询的其他方法 5.DOM增删改 6.使用DOM操作CSS 7.读取元素的样式 ...

  2. Javaweb学习笔记——(三)——————JavaScript基础DOM基础

    day03 1.js的String对象 **创建String对象 ***var str = "abc"; **方法和属性(文档) ***属性 lenth:字符串的长度 ***方法 ...

  3. JavaScript基础DOM操作--在线英文发音

    一.案例需求 在线英文发音–点击英语单词完成在线英文发音 二.涉及的知识点 DOM事件,本案例主要用的是点击事件 DOM节点操作运用,节点查找操作,节点属性操作 利用document.getEleme ...

  4. JavaScript基础: DOM中操作属性以及自定义属性

    上一篇聊了一些常用的事件以及演示其如何使用,演示的时候发现一件事情,那就是DOM操作不单是得到元素,还可以修改元素的属性.现在开始如何操作其属性. 普通自带的属性 这些属性是某些标签自带的属性比如sr ...

  5. 网页开发基础,HTML、CSS技术、JavaScript基础

    一.学习目标 1.HTML技术 2.CSS技术 3.JavaScript基础 二.重要知识点 1.HTML技术 超文本标记语言(英语:HyperText Markup Language,简称:HTML ...

  6. < JavaScript基础知识 之 思维导图 >

    文章目录 前言 一.Javascript变量 二.Javascript运算符 三.Javascript数组 四.Javascript流程语句 五.Javascript字符串函数 六.Javascrip ...

  7. JavaScript基础13-day15【DOM增删改、DOM添加删除记录、操作内联样式、获取元素的样式、DOM Element 对象、滚动条练习、事件对象、div跟随鼠标移动、事件冒泡】

    学习地址: 谷粒学院--尚硅谷 哔哩哔哩网站--尚硅谷最新版JavaScript基础全套教程完整版(140集实战教学,JS从入门到精通) JavaScript基础.高级学习笔记汇总表[尚硅谷最新版Ja ...

  8. JavaScript基础11-day13【正则表达式(量词、语法、转义字符、元字符)、DOM(节点、事件)、图片切换】

    学习地址: 谷粒学院--尚硅谷 哔哩哔哩网站--尚硅谷最新版JavaScript基础全套教程完整版(140集实战教学,JS从入门到精通) JavaScript基础.高级学习笔记汇总表[尚硅谷最新版Ja ...

  9. JavaScript 基础知识 - DOM篇(二)

    7. 节点操作 7.1 节点的属性 节点分类: 标签节点 文本节点 属性节点 注释节点 节点常用的属性: nodeType:节点的类型 nodeName:节点名称 nodeValue:节点值 常见的节 ...

  10. javaweb(02) JavaScript基础知识

    javaweb(02): JavaScript基础知识 JavaScript简介 为什么出现JavaScript Javascript是什么 JavaScript和Java的关系? 就像卡巴斯基和巴基 ...

最新文章

  1. Mysql Explain 详解
  2. boost::hana::detail::unpack_flatten用法的测试程序
  3. 解构里面再次解构_解构后的咖啡:焙炒,研磨和分层,以获得更浓的意式浓缩咖啡
  4. 计蒜客 逃生+动态规划
  5. 【渝粤题库】广东开放大学 经济学基础 形成性考核
  6. WebClient与WebRequest差异
  7. vscode写python爬虫_如何在vscode中调试python scrapy爬虫
  8. matlab利用双目图像视差进行三维重建
  9. IE7的web标准之道——5:(修正)上去了!终于上去了!
  10. Maven使用{PDF报表时导入坐标报错,解决·Cannot resolve com.lowagie:itext:2.1.7.js6
  11. 万能音视频转换器:Permute 3 for mac
  12. 单位个人计算机 数据备份,个人所得税软件数据备份,您必须知道的5件事
  13. 解决outlook 中邮件中,点击链接提示(您的组织策略阻止我们为您完成此操作)解决方案
  14. mysql 查询当前时间是星期几
  15. 文本学习-《背影》-朱自清
  16. 解决软件安装的2203报错
  17. EV录制文件损坏-修复方法
  18. hive:建库建表、表分区、内部表外部表、数据导入导出
  19. Windows远程桌面 无法进行复制粘贴的问题解决方法
  20. 学习算法笔记(12)

热门文章

  1. jquery设置禁止浏览器刷新
  2. ab test -- 实验效果不显著的改善方法 -- CUPED
  3. 2019年python爬虫-我破解了中文裁判网数据挖掘-反爬技术哪些事情
  4. [实战]200类鸟类细粒度图像分类
  5. hget如何获取多个value_Redis(五):hash/hset/hget 命令源码解析
  6. CTE 递归查询全解
  7. SSO单点登录基本概念实现思路以及小的实例详解
  8. 第2章第5节:文本框的使用:复制和移动文本框 [PowerPoint精美幻灯片实战教程]
  9. html文字段落加边框线,html边框样式 怎么用html给文字加边框的?
  10. 2022-04-行为经济学-光华管理学院-孟涓涓