JavaScript教程(一)

计算机语言

机器语言、汇编语言和高级语言

  • 计算机语言指用于人与计算机之间通讯的语言,它是人与计算机之间传递信息的媒介;
  • 计算机语言的种类非常多,总的来说可以分成【机器语言】、【汇编语言】和【高级语言】三大类;
  • 实际上计算机最终所执行的都是【机器语言】,它是由“0”和“1”组成的二进制数,二进制是计算机语言的基础;
    在这里插入图片描述
  • 编程语言是用来控制计算机的一系列指令,它有固定的格式和词汇(不同编程语言的格式和词汇不一样),必须遵守;
  • 如今通用的编程语言有两种形式:【汇编语言】和【高级语言】;
  • 【高级语言】主要是相对于低级语言而言的,它并不是特指某一种具体的语言,而是包括了很多编程语言,常用的有:C语言、C++、Java、C#、Python、PHP、Go语言、Objective、Swift等;
  • 【翻译器】:高级语言所编制的程序不能直接被计算机识别,必须经过转换才能被执行,为此,我们需要一个翻译器;翻译器可以将我们所编写的源代码转换为机器语言,这也被称为二进制化。记住1和0;
    在这里插入图片描述

【编程语言】和【标记语言】的区别?

  • 【编程语言】有很强的逻辑和行为能力。在编程语言里,会看到很多if else 、for、while等具有逻辑性和行为能力的指令,这是主动的;
  • 【标记语言】(html)不用于向计算机发出指令,常用于格式化和链接。标记语言的存在是用来被读取的,它是被动的;

计算机基础

计算机组成

在这里插入图片描述
在这里插入图片描述

数据存储

  • 计算机内部使用二进制0和1来表示数据;
  • 所有数据,包括文件、图片等最终都是以二进制数据(0和1)的形式存放在硬盘中的;
  • 所有程序,包括操作系统,本质都是各种数据,也以二进制数据的形式放在硬盘中。平时我们所说的安装软件,其实就是把程序文件复制到硬盘中;
  • 硬盘、内存都是保存的二进制数据;

数据存储单位

在这里插入图片描述

程序运行

在这里插入图片描述

初识JavaScript

JavaScript简介

  • 发明者:布兰登 艾奇
  • JavaScript是一种运行在客户端的脚本语言(script是脚本的意思);
  • 脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行;
  • 现在也可以基于Node.js技术进行服务器端编程;
    在这里插入图片描述
    在这里插入图片描述

浏览器执行JS简介

  • 浏览器分成两部分:【渲染引擎】和【JS引擎】;
  • 【渲染引擎】:用来解析HTML与CSS,俗称【内核】,比如:chrome浏览器的blink,老版本的webkit;
  • 【JS引擎】:也称为【JS解释器】。用来读取网页中的JavaScript代码,对其处理后运行,比如chrome浏览器的V8;
  • 浏览器本身并不会执行JS代码,而是通过内置JavaScript引擎(解释器)来执行JS代码。JS引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以JavaScript语言归为脚本语言,会逐行解释执行;

JS组成

在这里插入图片描述

ECMAScript

在这里插入图片描述

DOM

在这里插入图片描述

BOM

在这里插入图片描述

JS的输入和输出语句

在这里插入图片描述

变量

什么是变量?

  • 通俗:变量是用于存放数据的容器。我们通过【变量名】获取数据,甚至数据可以修改;

变量在内存中的存储

  • 本质:变量是程序在内存中申请的一块用来存放数据的空间;

变量的使用

  • 变量在使用时分为两步:1、声明变量;2、赋值
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

变量案例-弹出输入的用户名

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>变量案例-弹出用户名</title>
</head><body><script>// 1、输入用户姓名,存储到一个 myName 的变量中var myName = prompt('请输入用户名')// 2、输出这个用户名alert(myName)</script>
</body></html>

变量的语法扩展

  • 更新变量:一个变量被重新赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准;
  • 同时申明多个变量时,只需要写一个 var ,多个变量名之间使用英文逗号隔开;
    在这里插入图片描述
  • 声明变量的特殊情况:
    (1)、只声明不赋值,程序也不知道里面存的是啥,所以结果是 undefined(未定义的);
    (2)、不声明 不赋值 直接使用某个变量,会报错(xxx is not defined);
    (3)、不声明 直接赋值使用:可以正常使用,是一个全局变量;

变量的命名规范

在这里插入图片描述

  • 我们尽量不要使用“name”作为变量名;
    在这里插入图片描述
案例:显示年龄案例
<body><script>var age = prompt("请输入你的年龄");var str = '你今年已经' + age + '岁了';alert(str)</script>
</body>

数据类型

为什么需要数据类型?

在这里插入图片描述

变量的数据类型

在这里插入图片描述

<script>// int num=10;  java// var num; //这里的num 我们是不确定属于哪种数据类型的 var num = 10; //num属于数字型// js 的变量数据类型是只有程序在运行过程中,根据等号右边的值来确定的// js是动态语言 变量的数据类型是可以变化的var x = 10; // x 是数字型x = 'pink'; //x 是字符串
</script>

数据类型的分类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数据类型转换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 注意:代表【空】、【否定的值】会被转换为【false】,如:‘’ 0 NaN null undefined;其余值都会被转换为 true;
隐式转换
  • 【隐式转换】是我们在进行算数运算的时候,JS自动转换了数据类型;
//利用算数运算 - * / 来隐式转换;
<script>console.log('12'-0);//隐式转换为 数字型12console.log('123'-'120');
</script>
案例:计算年龄案例
<body><!-- 此案例要求在页面中弹出一个输入框,我们输入出生年份后,能计算出我们的年龄 --><!-- 案例分析:1、弹出一个输入框(prompt),让用户输入出生年份(用户输入);2、把用户输入的值用变量保存起来,然后用今年的年份减去变量值,结果就是现在的年龄(程序内部处理);3、弹出警示框(alert),把计算的结果输出(输出结果);--><script>var year=prompt("请输入你的出生年份");var age=2022-year;//按道理year取过来的是字符串型,做减法操作这里做了隐式转换;alert('你的年龄是'+age+'岁');</script>
</body>
案例:简单加法器案例
<body><!-- 计算两个数的值,用户输入第一个值后,继续弹出第二个输入框并输入第二个值,最后通过弹出框口显示出两次输入值相加的结果 --><script>var num1 = prompt("请输入第一个值");var num2 = prompt("请输入第二个值");var result = parseFloat(num1) + parseFloat(num2);alert("你的结果是:" + result);</script>
</body>

补充:解释型语言和编译型语言

在这里插入图片描述

运算符(算数运算符、递增和递减运算符、比较运算符、逻辑运算符、赋值运算符)

  • 运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号;JavaScript中常用的运算符有:算数运算符、递增和递减运算符、比较运算符、逻辑运算符、赋值运算符;
    在这里插入图片描述

补充:表达式和返回值

  • 表达式:是由数字、运算符、变量等以能求得数值的有意义排列方法所得的组合;简单理解:是由数字、运算符、变量等组成的式子;【表达式最终都会有一个结果,返回给我们,我们称之为返回值。】

短路运算(逻辑中断)

  • 短路运算的原理:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值;

逻辑与

  • 语法:表达式1 && 表达式2;
  • 如果第一个表达式的值为真,则返回表达式2;
  • 如果第一个表达式的值为假,则返回表达式1;
<body><!-- 1、用我们的布尔值参与的逻辑运算 true && false == false;  --><script>// 3、逻辑与短路运算// 3.1、逻辑与短路运算 如果表达式1结果为真,则返回表达式2;console.log(123 && 456);//456// 3.2、逻辑与短路运算 如果第一个表达式的值为假,则返回表达式1;console.log(0 && 456);//0// 如果有空的或者否定的为假(如:0、''、null、undefined、NaN),其余是真的;// 4、逻辑或短路运算// 4.1、如果表达式1结果为真,则返回的是表达式1;console.log(123 || 456);//123// 4.2、如果表达式1结果为假,则返回的是表达式2;console.log(0 || 456);//456// 案例分析(123为真,直接返回123,后面的 num++ 就不再执行了,所以是结果是0)var num=0;console.log(123 || num++);console.log(num);//0</script>
</body>

赋值运算符

  • 概念:用来把数据赋值给变量的运算符;
    在这里插入图片描述
<script>var num = 10;//num=num+1; num++//num = num + 2; ==> num += 2;num += 2;console.log(num);//12</script>

运算符优先级

在这里插入图片描述

  • 一元运算符里面的逻辑非(!)优先级很高;
  • 逻辑与比逻辑或优先级高;

流程控制(顺序结构、分支结构、循环结构)

  • 在一个程序执行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候,我们要通过控制代码的执行顺序来实现我们要完成的功能;
  • 简单理解:流程控制就是来控制我们的代码按照什么结构顺序来执行;
  • 流程控制主要有三种结构,分别是:顺序结构分支结构循环结构,这三种结构代表三种代码执行的顺序;
    在这里插入图片描述
  • 顺序结构:是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的;
  • 分支结构:由上到下执行代码的过程中,根据不同的条件,执行不同的路径代码(执行代码多选一的过程),从而得到不同的结果;JS语言提供了两种分支结构语句:if语句、switch语句;

流程控制-分支(if分支语句、switch分支语句、三元表达式)

案例:判断平年、闰年案例

<body><!-- 算法:能被4整除且不能整除100的为闰年(如2004年就是闰年,1901年不是闰年)或者能被400整除的就是闰年;--><script>var year=prompt("请输入年份:");if(year % 4 ==0 && year % 100 !== 0 || year % 400 ==0){alert("你输入的年份是闰年");}else{alert("你输入的年份是平年");}</script>
</body>

案例:数字补零

<body><!-- 案例描述:用户输入数字,如果数字小于0,则在前面补零;如果数字大于0,则不需要补。--><script>var time = prompt("请输入一个0~59之间的一个数字");var result = time < 10 ? "0" + time : timealert(result);</script>
</body>

switch语句

  • 当要针对变量设置一系列的特定值的选项时,就可以用switch语句;
  • switch是转换、开关的意思;case小例子或者选项的意思;
  • 语法结构:
switch(表达式){case value1:执行语句1break;case value2:执行语句2break;...default:执行最后的语句;
}
  • 执行思路:利用我们的【表达式的值】和【case后面的选项值】相匹配,如果匹配上,就执行该case里面的语句;如果都没有匹配上,那么执行default里面的语句。
  • 代码验证:
switch(2){case 1:console.log("这是1")break;case 2:console.log("这是2");;break;case 3:console.log("这是3");;break;default:console.log("没有匹配结果");;
}
  • switch注意事项:
    (1)、我们开发时,表达式经常写成变量;
    (2)、我们num的值和case里面的值相匹配的时候是【全等】(必须是值和数据类型一致才可以);
    (3)、break如果当前的case里面没有break,则不会退出switch,而是继续执行下一个case

案例:查询水果案例

<body><script>var fruit = prompt("请输入水果:");switch (fruit) {case '苹果':alert('苹果');break;case '榴莲':alert('榴莲');break;default:alert('没有此水果');}</script>
</body>
  • switch语句和if else if语句的区别:
    (1)、一般情况下,它们两个语句可以相互替换;
    (2)、switch...case语句通常处理case为比较确定值的情况,而if...else...语句更加灵活,常用于范围判断(大于、等于某个范围);
    (3)、switch语句进行条件判断后直接执行到程序的条件语句,效率更高。而if...else...语句有几种条件,就得判断多少次;
    (4)、当分支比较少时,if...else...语句的执行效率比switch语句高;
    (5)、当分支比较多时,switch语句的执行效率比较高,而且结构更清晰;

流程控制-循环(for循环、while循环、do while循环)

  • 循环的目的:在实际问题中,有许多具有规律性的重复操作,因此在程序中要完成这类操作就需要重复执行某些语句;
  • 在JS中,主要有三种类型的循环语句:for循环、while循环、do while循环;
  • 在程序中,一组被重复执行的语句被称为【循环体】,能否继续重复执行,取决于循环的【终止条件】。由循环体及循环的终止条件组成的语句,被称为【循环语句】;
//for语法结构
for(初始化变量;条件表达式;操作表达式){//循环体
}
//初始化变量:就是用var声明的一个普通变量,通常用于作为计数器使用;
//条件表达式:就是用来决定每一次循环是否继续执行,就是终止的条件;
//操作表达式:就是每次循环最后执行的代码,经常用于我们计数器变量进行更新(递增或者递减);
  • for循环可以重复执行不同的代码,因为我们有计数器变量i的存在,i每次循环值都会变化;
//我们想要输出1个人1~100岁
for(var i=1;i<=100;i++){console.log('这个人今年'+i+'岁了');
}
  • for循环重复某些相同操作。for循环因为有了计数器的存在,我们还可以重复的执行某些操作,比如做一些算术运算;

案例:求1~100之间所有整数的累加和

<body><!-- 案例分析:1、需要循环100次,我们需要一个计数器i;2、我们需要一个存储结果的变量sum,但是初始值一定是03、核心算法:1+2+3+4+...sum=sum+i;--><script>var sum=0;//求和的变量for(var i=0;i<=100;i++){sum=sum+i;}console.log(sum);</script>
</body>

案例:for循环案例

 <script>// 1、求1-100之间所有数的平均值;var sum = 0;var average = 0;for (var i = 1; i <= 100; i++) {sum = sum + i;}average = sum / 100;console.log(average);//50.5// 2、求1-100之间所有偶数和奇数的和;var event = 0;var odd = 0;for (var i = 1; i <= 100; i++) {if (i % 2 == 0) {event = event + i;} else {odd = odd + i;}}console.log(event);//2550console.log(odd);//2500// 3、求1-100之间所有能被3整除的数字的和;var result = 0;for (var i = 1; i <= 100; i++) {if (i % 3 == 0) {result = result + i;}}console.log(result);//1683</script>

案例:求学生成绩案例

<body><!-- 要求用户输入班级人数,之后依次输入每个学生的成绩,最后打印出该班级总的成绩以及平均成绩 --><script>var num = prompt('请输入班级总人数:');var sum = 0;var average = 0;for (var i = 1; i <= num; i++) {var score = prompt('请输入第' + i + '个学生成绩');// 因为从prompt取过来的数据是 字符串型的 需要装换为 数字型;sum = sum + parseFloat(score);}average = sum / num;alert('班级总的成绩是' + sum);alert('班级平均分是' + average);</script>
</body>

案例:一行打印5颗星星

<script>var str = '';for (var i = 1; i <= 5; i++) {// console.log('⭐');// 我们采用追加字符串的方式,这样可以打印到控制台上;str = str + '⭐';}console.log(str);</script>
var num = prompt('请输入星星个数');var str = '';for (var i = 0; i < num; i++) {str = str + '⭐';}console.log(str);

双重for循环

  • 循环嵌套是指在一个循环语句中再定义一个循环语句的语法结构,例如在for循环语句中,可以再嵌套一个for循环,这样的for循环语句我们称之为双重for循环;
  • 我们可以把里面的循环看作是外层循环的语句;
  • 外层的循环循环一次,里面的循环执行全部;

案例:打印5行5列星星

 <script>var str = '';for (var i = 1; i <= 5; i++) {for (var j = 1; j <= 5; j++) {str = str + '⭐';}// 如果一行打印完毕5个星星,就要另起一行;(加 \n)str = str + '\n';}console.log(str);</script>

案例:打印n行n列星星

 <script>var row = prompt('请输入行数');var column = prompt('请输入列数');var str = '';for (var i = 1; i <=row; i++) {for (var j = 1; j <= column; j++) {str = str + '⭐';}str = str + '\n';}console.log(str);</script>

案例:打印倒三角案例

<script>var str = '';for (var i = 1; i <= 10; i++) {for (var j = i; j <= 10; j++) {str = str + '⭐';}str = str + '\n';}console.log(str);</script>

while循环

  • 语法结构:while(条件表达式){循环体}
  • 执行思路:当条件表达式结果为true,则执行循环体;否则,退出循环;
  • 代码验证:
var num=1;
while(num<=100){console.log('你好');num++;
}
  • 里面应该也有计数器,初始化变量;
  • 里面应该也有操作表达式,完成计数器的更新,防止死循环;

while循环案例

 <script>// 1、打印人的一生,从1岁到100岁;// var i=1;// while(i<=100){//     console.log('这个人今年'+i+'岁了');//     i++;// }// 2、计算1~100之间所有整数的和;// var i = 1;// var sum = 0;// while (i <= 100) {//     sum = sum + i;//     i++;// }// console.log(sum);// 3、弹出一个提示框,你爱我吗?如果输入我爱你,就提示结束,否则,一直询问;var message = prompt('你爱我吗?');while (message !== '我爱你') {message = prompt('你爱我吗?');}  alert('我也爱你呀'); </script>

dowhile循环

  • dowhile语句其实是while语句的一个变体。该循环会先执行一次代码块,然后对条件表达式进行判断,如果条件为真,就会重复执行循环体,否则退出循环;
  • 语法结构:
do{//循环体
}while(条件表达式)
  • 执行思路:跟while不同的地方在于dowhile先执行一次循环体,再判断条件;如果条件表达式结果为真,则继续执行循环体,否则退出循环;
<script>// 代码验证var i = 1;do {console.log('你好');i++;} while (i <= 100)
</script>
  • dowhile语句至少会执行一次循环体代码;

dowhile案例

 <script>// 1、代码验证// var i = 1;// do {//     console.log('你好');//     i++;// } while (i <= 100)// 2、打印人的一生,从1岁到100岁;// var i = 1;// do {//     console.log('这个人今年'+i+'岁了');//     i++;// } while (i <= 100)// 3、计算1~100之间所有整数的和;// var i = 1;// var sum = 0;// do {//     sum = sum + i;//     i++;// } while (i <= 100)// console.log(sum);// 3、弹出一个提示框,你爱我吗?如果输入我爱你,就提示结束,否则,一直询问;        do {var message = prompt('你爱我吗?');} while (message !== '我爱你')alert('我也爱你呀');</script>

循环小结

  • JS中循环有forwhiledowhile
  • 三个循环很多情况下都可以互相替代使用;
  • 如果是用来计次数,跟数字相关的,三者使用基本相同,但是我们更喜欢用for
  • whiledowhile可以做更复杂的判断条件,比for灵活一些;
  • whiledowhile执行顺序不一样,while先判断,后执行;dowhile先执行一次,再判断执行;
  • whiledowhile执行次数不一样, dowhile至少会执行一次循环体,而while可能一次也不执行;
  • 实际工作中,我们更常用for循环,它的写法更简洁直观;

continuebreak关键字

continue关键字

  • 用于【立即跳出本次循环,继续下一次循环】(本次循环体中continue之后的代码就会少执行一次);

continue关键字案例

 <script>// continue关键字(退出本次,即当前次的循环;继续执行剩余次的循环)// for (var i = 1; i <= 5; i++) {//     if (i === 3) {//         continue; // 只要遇到continue就退出本次循环,直接跳到//     }//     console.log(i);//1 2 4 5// }// 案例:求1~100之间,除了能被7整除之外的整数和;var sum = 0;for (var i = 1; i <= 100; i++) {if (i % 7 == 0) {continue;}// sum = sum + i;sum += i;}console.log(sum);</script>

break关键字

  • break关键字用于立即跳出整个循环(循环结束);
 // break关键字(退出整个循环)for (var i = 1; i <= 5; i++) {if (i == 3) {break;//退出整个循环}console.log(i);// 1 2}

数组

案例:求数组最大值

<script>// 求数组[2,6,1,77,52,25,7]中的最大值;/*案例分析:(1)、声明一个保存最大元素的变量max;(2)、默认最大值可以取数组中的第一个元素;(3)、遍历这个数组,把里面每个数组元素和max相比较;(4)、如果这个数组元素大于max就把这个数组元素存到max里面,否则继续下一轮比较;(5)、最后输出这个max;*/var arr = [2, 6, 1, 77, 52, 25, 7];var max = arr[0];for (var i = 1; i <= arr.length; i++) {if (max < arr[i]) {max = arr[i];}}console.log(max);</script>

数组中新增元素

  • 可以通过修改length长度以及索引号增加数组长度;
    (1)、可以通过修改length长度来实现数组扩容的目的;
  • length属性是可读写的;
    (2)、通过修改数组索引新增数组元素;
  • 可以通过修改数组索引的方式追加数组元素;
 <script>// 1、新增数组元素-修改length长度;var arr = ['red', 'green', 'blue'];console.log(arr.length);arr.length = 5;//我们把数组长度修改为了5,里面应该有5个元素;console.log(arr);// ['red', 'green', 'blue', empty × 2]console.log(arr[3]);//undefinedconsole.log(arr[4]);//undefined// 2、新增数组元素-通过修改数组索引新增数组元素;追加数组元素;// 之前索引号里面没有元素时是追加元素;有元素时是替换元素;var arr1 = ['red', 'blue', 'green'];arr1[3] = 'pink';console.log(arr1);//['red', 'blue', 'green', 'pink']arr1='有点意思';console.log(arr1);//不能直接给数组名赋值,否则会覆盖掉以前的数据;</script>

案例:新建一个数组,里面存放10个整数(1-10)

<script>var arr = [];for (var i = 0; i < 10; i++) {//arr=i; //不要直接给数组名赋值,否则以前的元素都没了;arr[i] = i+1;}console.log(arr);// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
</script>

案例:筛选数组

方法一:

<script>// 将数组[2,0,6,1,77,0,52,0,25,7]中大于等于10的元素选出来,放入新数组;var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];var arr1 = [];var j = 0;for (var i = 0; i <= arr.length; i++) {// 新数组应该从0开始,一次递增;if (arr[i] >= 10) {// arr1[i] = arr[i]; //[empty × 4, 77, empty, 52, empty, 25] 原因:从第四个开始有值,当i=1,2,3时是没有值存进去的;arr1[j] = arr[i];j++; //[77, 52, 25]}}console.log(arr1);</script>

方法二:

 // 筛选数组方法二:var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];var arr1 = [];for (var i = 0; i <= arr.length; i++) {// 新数组应该从0开始,一次递增;if (arr[i] >= 10) {// arr1[i] = arr[i]; //[empty × 4, 77, empty, 52, empty, 25] 原因:从第四个开始有值,当i=1,2,3时是没有值存进去的;arr1[arr1.length] = arr[i];//刚开始 arr1.length 就是0;数组的length会根据数组长度的变化而变化;}}console.log(arr1);

案例:数组去重

<script>// 方法一:var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];var newArr = [];// for (var i = 0; i < arr.length; i++) {//     if (newArr.indexOf(arr[i]) === -1) {//         newArr.push(arr[i]);//     }// }// console.log(newArr);// 方法二:var mySet=new Set(arr);//利用了Set结构不能接收重复数据的特点;for(var val of mySet){newArr.push(val);}console.log(newArr);</script>

案例:翻转数组

<script>// 要求:将数组['red','green','pink','blue',purper]的内容反过来存放;var arr = ['red', 'green', 'pink', 'blue', 'purper'];var newArr = [];for (var i = arr.length - 1; i >= 0; i--) {newArr[newArr.length] = arr[i];}console.log(newArr);</script>

复习:交换两个变量

var num1=10;
var num2=20;
var temp;
temp=num1;
num1=num2;
num2=temp;
console.log(num1,num2);

案例:数组排序(冒泡排序)

  • 冒泡排序是一种算法,把一系列的数据按照一定的顺序进行排列显示(从小到大或从大到小);
 <script>var arr = [5, 4, 3, 2, 1];for (var i = 0; i <= arr.length - 1; i++) {//外层循环管趟数for (var j = 0; j <= arr.length - i - 1; j++) {//里面的循环管每一趟的交换次数;// 内部交换两个变量的值,前一个和后面一个数组元素相比较;if (arr[j] > arr[j + 1]) {var temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}console.log(arr);</script>

函数

函数导读

  • 函数:函数就是封装了一段可以被重复执行调用的代码块;目的就是让大量代码重复使用;
  • 函数使用分为两步:【声明函数】和【调用函数】;
function 函数名(){//函数体
}
函数名()
  • 函数是做某件事情,函数名一般是动词;(sayHi)
  • 函数不调用自己不执行;
  • 注意:声明函数本身并不会执行代码,只有调用函数时才会执行函数体代码;
  • 函数的封装:就是把一个或多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口;

案例:利用函数求1~100的累加和

<script>function getSum() {var sum = 0;for (var i = 1; i <= 100; i++) {sum += i;}console.log(sum);}getSum();</script>

函数的参数

  • 我们可以利用函数的参数实现函数重复不同的代码;
  • 【形参】和【实参】;
function 函数名(形参1,形参2...){}
函数名(实参1,实参2,...);
  • 在声明函数的小括号里面是【形参】;(形式上的参数)
  • 在函数调用的小括号里面是【实参】;(实际的参数)
  • 形参和实参的执行过程:(形参是接收实参的;形参类似于一个变量;)
  • 函数的参数可以有,也可以没有,个数不限;
    在这里插入图片描述

案例:利用函数求任意两个数的和以及累加和

<script>// 1、利用函数求任意两个数的和function getSum(num1, num2) {console.log(num1 + num2);}getSum(1, 3);// 2、利用函数求任意两个数之间的和function getSums(start, end) {var sum = 0;for (var i = start; i <= end; i++) {sum += i;}console.log(sum);}getSums(1, 100);</script>
  • 注意点:
    (1)、多个参数之间用逗号隔开;
    (2)、形参可以看作是不用声明的变量;

函数的形参和实参匹配问题

  • 如果实参的个数和形参的个数一致,则正常输出结果;
  • 如果实参的个数多于形参的个数,会取到形参的个数;
  • 如果实参的个数小于形参的个数,多于的形参定义为undefined,最终的结果就是NaN
  • 形参可以看作是不用声明的变量,num2是一个变量但是没有接受值,结果就是undefined
  • 建议:我们尽量让实参的个数和形参相匹配;
function getSum(num1,num2){console.log(num1+num2);
}
getSum(1,2);
getSum(1,2,3);
getSum(1);//NaN (任何数字 + undefined = NaN )

在这里插入图片描述

函数的返回值return

  • 有时候,我们会希望函数将值返回给调用者,此时通过使用return语句就可以实现;
function 函数名(){return 需要返回的结果;
}函数名();
  • 我们函数只是实现某种功能,最终的结果需要返回给函数的调用者;通过return来实现的;
  • 只要函数遇到return,就把后面的结果返回给函数的调用者;
  • 函数名() = return后面的结果;
function getResult(){return 666;
}
getResult()
console.log(getResult());//666

案例:求任意两个数的和

function getSum(num1,num2){return num1 + num2;
}
console.log(getSum(1,2));

案例:利用函数求两个数的最大值

<script>function getMax(num1, num2) {// if (num1 > num2) {//     return num1;// } else {//     return num2;// }return num1 > num2 ? num1 : num2;}console.log(getMax(6, 2));</script>

案例:利用函数求数组中的最大值

<script>// var arr=[5,2,99,101,67,77];function getArrMax(arr) {// arr 接收一个数组var max = arr[0];for (var i = 1; i <= arr.length; i++) {if (arr[i] > max) {max = arr[i];}}return max;}// console.log(getArrMax([5, 2, 99, 101, 67, 77]));//实参是一个数组送过去  var re = getArrMax([5, 2, 99, 101, 67, 77]);console.log(re);</script>

return终止函数并且只能返回一个值

  • return终止函数,return语句之后的代码不被执行;
function getSum(num1,num2){return num1+num2;alert("我是不会被执行的");//return 后面的的代码不会被执行
}
console.log(getSum(1,2));
  • return只能返回一个值。如果用逗号隔开多个值,以最后一个为准;
function fn(num1,num2){return num1,num2;//返回的结果是最后一个值
}
console.log(fn(1,2));
  • 我们求任意两个数的 加减乘除 结果:
function getResult(num1,num2){return [num1+num2,num1-num2,num1*num2,num1/num2];
}
console.log(fn(1,2));//返回的是一个数组

函数没有return,返回undefined

  • 我们的函数如果有return,则返回的是return后面的值;如果函数没有return,则返回undefined

breakcontinuereturn的区别

在这里插入图片描述

arguments 的使用

当我们不确定有多少个参数传递的时候,可以用arguments 来获取,在JS中,arguments 实际上它是当前函数的一个【内置对象】。所有函数都内置了一个arguments对象,arguments对象中【存储了传递的所有实参】;

<script>function fn() {console.log(arguments); // Arguments(3),arguments是以伪数组的形式来展示的;//我们可以按照数组的方式遍历 Arguments;}fn(1, 2, 3)/*伪数组并不是真正意义上的数组:1、具有数组的 length 属性;2、按照索引的方式进行存储的;3、没有真正数组的一些方法,如:pop()、push() 等;*/
</script>

函数的两种声明方式

<script>// 1、利用函数关键字自定义函数(命名函数)function fn() { }fn()// 2、函数表达式(匿名函数)//注意:函数表达式声明方式跟变量差不多,只不过变量里面存的是值,而函数表达式里面存的是函数;// var 变量名 = function(){}var fun = function () { } // 注意:此处的 fun 是变量名,不是函数名;fun() // 变量名 + ()实现调用;函数表达式也可以进行传递参数;
</script>

arguments 案例:利用函数求任意几个数的最大值

 <script>function getMax() {var max = arguments[0];for (var i = 1; i < arguments.length; i++) {if (arguments[i] > max) {max = arguments[i];}}return max;}console.log(getMax(7, 2, 5, 99, 0, 2346));      </script>

案例:利用函数封装方式,翻转任意一个数组

<script>function getArrReverse(arr) {var newArr = [];for (var i = arr.length - 1; i >= 0; i--) {newArr[newArr.length] = arr[i];}return newArr;}console.log(getArrReverse([1, 2, 3, 4, 5]));     </script>

案例:利用函数封装冒泡排序

<script>function sort(arr) {for (var i = 0; i <= arr.length - 1; i++) {for (var j = 0; j <= arr.length - i - 1; j++) {if (arr[j] > arr[j + 1]) {var temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}return arr;}console.log(sort([5, 7, 3, 2, 0, 8, 1]));</script>

案例:运用函数封装判断闰年

 <script>// 闰年:能被4整除并且不能被100整除;或者能被400整除;// function isRunYear(year){//     if(year % 4 === 0 && year % 100 !=0 || year % 400 === 0){//         return year+'年是闰年';//     }else{//         return year+'年是平年';//     }// }// console.log(isRunYear(2020));function isRunYear(year){// 如果是闰年我们返回true;否则返回false;var flag = false;if(year % 4 === 0 && year % 100 !=0 || year % 400 === 0){flag = true;}return flag;}console.log(isRunYear(2000));</script>

函数可以调用另外一个函数

  • 因为每个函数都是独立的代码块,用于完成特殊任务,因此经常会用到函数相互调用的情况;
function fn1(){console.log(11);fn2();//在fn1函数里面调用了fn2函数;
}
fn1();
function fn2(){console.log(22);
}

一个函数调用另外一个函数案例:用户输入年份,输出当前年份2月份的天数

<script>function backDay(){var year = prompt('请输入年份');if(isRunYear(year)){//调用函数需要加小括号alert('当前年份是闰年,2月份有29天');}else{alert('当前年份是平年,2月份有28天');}}backDay();// 判断是否为闰年的函数function isRunYear(year){// 如果是闰年我们返回true;否则返回false;var flag = false;if(year % 4 === 0 && year % 100 !=0 || year % 400 === 0){flag = true;}return flag;}</script>

Javascript作用域

作用域概述:

通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的【可用性的代码范围】就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字的冲突。
Javascript作用域: 就是代码名字(变量)在某个范围内起作用和效果;目的是为了提高程序的可靠性,更重要的是减少命名冲突;js作用域(es6)之前:全局作用域 局部作用域;
全局作用域: 【整个 script 标签】或者是一个【单独的js文件】
局部作用域(函数作用域): 在函数内部就是局部作用域;这个代码的名字只在函数内部起效果和作用;

变量的作用域:

  • 根据作用域的不同,我们把变量分为【全局变量】和【局部变量】

全局变量:

  • 全局变量:在全局作用域下声明的变量(在函数外部定义的变量),在全局下都可以使用;
  • 全局变量在代码的任何位置都可以使用;
  • 在全局作用域下var声明的变量是【全局变量】;
  • 特殊情况下,在函数内不使用var声明的变量也是全局变量(不建议使用);
  • 注意:如果在函数内部,没有声明直接赋值的变量也属于【全局变量】;

局部变量:

  • 在局部作用域下声明的变量,或者在函数内部定义的变量就是局部变量;
  • 局部变量只能在该函数内部使用;
  • 在函数内部var声明的变量是局部变量;
  • 注意: 函数的形参也可以看做是【局部变量】;
从执行效率来看【全局变量】和【局部变量】:
  • 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源;
  • 局部变量当我们程序执行完毕就会销毁,比较节约内存资源;

块级作用域:

  • 用 {} 包裹

作用域链:

内部函数访问外部函数的变量,采取的是链式查找的方式来决定取哪个值,这种结构我们称为作用域链。(就近原则)

  • 只要是代码,就至少有一个作用域;
  • 写在函数内部的局部作用域;
  • 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;
  • 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称为【作用域链】;

预解析

  • JavaScript代码是由浏览器中的JavaScript解析器(引擎)来执行的。JavaScript解析器在运行JavaScript代码的时候分为两步:【预解析】和【代码执行】。
  • 预解析: js引擎会把js里面所有的 var,还有 function 提升到当前作用域的最前面;
  • 代码执行:按照代码书写的顺序从上往下执行;
  • 预解析分为【变量预解析(变量提升)】和【函数预解析(函数提升)】。
变量提升:
  • 就是把所有的变量声明提升到当前的作用域最前面,不提升赋值操作;
函数提升:
  • 就是把所有的函数声明提升到当前作用域的最前面,不调用函数;
// 1问
console.log(num) // 报错// 2问
console.log(num) // undefined  坑1
var num=10
// 相当于执行了以下代码
var num ;
console.log(num)
num=10// 3问
fn() // 11
function fn(){console.log(11) 
}
fn() // 11// 4问
fun() // 报错 fun is not a function
var fun=function(){ // 函数表达式 调用必须写在函数表达式的下面console.log(22) 
}
fun() // 22
//相当于执行了以下代码
var fun ;
fun();
fun=function(){console.log(22) 
}
  • 注意:
var a=b=c=9;
// 相当于:var a=9;b=9;c=9 区别于【集体声明】
//所以此处的 b 和 c 直接赋值,没有 var 声明,此处的 b 和 c 当全局变量看;// 集体声明(用逗号隔开)
var a=9,b=9,c=9

对象

什么是对象?

  • 在Javascript中,对象是一组无序的相关属性和方法的集合,所有的事务都是对象,例如:字符串、数值、数组、函数等;
  • 对象是由【属性】和【方法】组成的:
    【属性】:事物的特征,在对象中用属性来表示(常用名词);
    【方法】:事物的行为,在对象中用方法来表示(常用动词);

为什么需要对象?

  • 保存一个值时,可以使用变量;保存多个值(一组值)时,可以使用数组。JS中的对象表达结构更清晰,更强大。

创建对象的三种方式

1、利用【字面量】创建对象;
  • 【对象字面量】就是花括号 {} ,里面包含了表达这个具体事物(对象)的属性和方法;
  • 调用属性还有一种方法:对象名[‘属性名’]
2、利用 【new Object】 创建对象;
3、利用【构造函数】创建对象;
  • 我们为什么需要使用构造函数?就是因为我们前面两种创建对象的方式一次只能创建一个对象;我们一次创建一个对象,里面很多的属性和方法是大量相同的,我们只能复制;因此,我们可以利用函数的方法,重复这些相同的代码,我们就把这个函数称为构造函数。又因为这个函数不一样,里面封装的不是普通代码,而是【对象】。
  • 构造函数:就是把我们对象里面一些相同的属性和方法抽象出来,封装到函数里面;
  • 构造函数: 是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
//构造函数的语法格式
function 构造函数名(){this.属性=this.方法=functon(){}
}
new 构造函数名() //调用构造函数
function Star(uname,age,sex){this.name=uname;this.age=age;this.sex=sex;this.sing=function(sang){console.log(sang)}
}
// 调用函数返回的是一个对象
var ldh = new Star('刘德华',18,'男') 
ldh.sing('冰雨');
console.log(typeof ldh)
console.log(ldh.name)
console.log(ldh['sex'])

注意:
1、构造函数名字首字母要大写;
2、我们构造函数不需要return 就可以返回结果;
3、我们调用构造函数,必须使用new;
4、我们只要 new Sar()调用函数,就创建一个对象;
5、我们的属性和方法前面必须添加this

构造函数和对象的区别?

  • 对象:是特指一个具体的事务,例如:刘德华;
  • 构造函数:抽象了对象的公共部分,封装到了函数里面,它泛指某一大类,例如:明星;它类似于Java语言里的类(class);
  • 我们利用构造函数(new关键字)创建对象的过程,也称为对象的【实例化】;

new关键字执行过程(new在执行时会做四件事)

1、new构造函数可以在内存中创建了一个空的对象;
2、this就指向刚才创建的空对象;
3、执行构造函数里面的代码,给这个空对象添加属性和方法;
4、返回这个新对象(所以构造函数里面不需要return);

遍历对象属性:for...in语句用于对【数组】或者【对象的属性】进行【循环】操作;

//for in 遍历对象
// 语法规则:for (变量 in 对象){}for(var k in obj){console.log(k); // k:变量,输出得到的是:属性名console.log(obj[k]); // obj[k] 得到的是:属性值//注意:此处的 k 是一个变量,无需用引号包裹;// 我们使用 for in 时,里面的变量,我们喜欢写 k 或者 key// for in 也可以遍历出对象里面的方法
}

小结:

  • 对象可以让代码结构更清晰;
  • 对象是复杂数据类型 Object
  • 对象的本质:就是一组无序的相关属性和方法的集合;
  • 构造函数泛指某一大类,比如苹果,不管是红色苹果还是绿色苹果,都统称为苹果;
  • 对象实例特指一个事物,比如这个苹果等;
  • for in语句用于对对象的属性进行循环操作;

【变量】【属性】【函数】【方法】的区别

  • 变量:变量和属性的相同点:他们都是用来存储数据的;
  • 变量:单独声明并赋值,使用的时候直接写变量名,单独存在;
  • 属性:在对象里面的不需要声明的,使用的时候必须是 对象.属性;
  • 函数和方法的相同点:都是实现某种功能,做某件事;
  • 函数是单独声明,并且调用的;函数名 + ()调用;单独存在的;
  • 方法在对象里面,调用的时候:对象.方法()调用;

JavaScript内置对象

  • JavaScript中的对象分为3种:自定义对象、内置对象、浏览器对象;
  • 前面两种对象是JS基础内容,属于ECMAScript;第三个浏览器对象属于我们JS独有的;
  • 【内置对象】就是指JS语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法);
  • JavaScript提供了多个内置对象:MathDateArrayString等;
  • https://developer.mozilla.org/zh-CN/
//利用对象封装自己的数学对象,里面有 PI 最大值和最小值  
var myMath={PI:3.141592653,max:function(){var max=arguments[0];for(var i=1;i<arguments.length;i++){if(arguments[i]>max){max=arguments[i]}}return max;},min:function(){var min=arguments[0];for(var i=1;i<arguments.length;i++){if(arguments[i]<min){min=arguments[i]}}return min;}
}
// 猜数字游戏案例
function getRandom(min,max){return Math.floor(Math.random() * (max-min + 1)) + min;
}
var random =getRandom(1,10);
while(true){ //死循环var num = prompt('你来猜?输入1~10之间的一个数字');
}
if(num>random){alert('你猜大了')
}else if(num<random){alert('你猜小了')
}else{alert('猜对了!')break; // 退出整个循环,结束程序
}

日期对象(Date()

  • 日期对象是一个构造函数,必须使用new来调用创建我们的日期对象;
  • 使用Date(),如果没有参数,返回当前系统的当前时间;
  • 参数常用的写法:数字型:2019,10,01或者是字符串型:2019-10-1 8:8:8
//格式化日期年月日星期(星期天返回的是0)
var arr=['星期天','星期一','星期二','星期三','星期四','星期五','星期六']
var date=new Date();
var day=date.getDay();
console.log(arr[day]) 
//封装一个函数返回当前的时分秒,格式:08:08:08
function getTimer(){var time=new Date();var h=time.getHours();h = h<10?'0'+h:hvar m=time.getMinutes()m = m<10?'0'+m:mvar s=time.getSeconds()s = s<10?'0'+s:sreturn h+':'+m+':'+s
}
console.log(getTimer()) 

倒计时案例:
在这里插入图片描述

数组

在这里插入图片描述
在这里插入图片描述

字符串

基本包装类型

  • 对象才有属性和方法;复杂数据类型才有属性和方法;简单数据类型为什么会有length属性呢?
  • 基本包装类型:为了方便操作基本数据类型,JavaScript还提供了三个特殊的引用类型:String、Number 和 Boolean(三种基本包装类型);基本包装类型就是把【简单数据类型】包装成为【复杂数据类型】,这样基本数据类型就有了【属性】和【方法】;
    (1)、把简单数据类型,包装成复杂数据类型;
    (2)、把临时变量的值给str;
    (3)、销毁这个临时变量;
var str = 'andy';
console.log(str.length);
var temp = new Sring('andy');
str = temp;
temp = null;

字符串的不可变

  • 字符串的不可变:指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址改变了,内存中新开辟了一个内存空间;所以不要大量的拼接字符串;
    -
  • 字符串所有的方法,都不会修改字符串本身(字符串是不可变的),操作完成会返回一个新的字符串;
// 案例:查找字符串“abcoefoxyozzopp”中所有o出现的位置以及次数;
/*
核心算法:先查找第一个o出现的位置,然后,只要 indexOf 返回的结果不是 -1,就继续往后查找;因为 indexOf 只能查找到第一个,所以后面的查找一定是当前索引加1,从而继续查找;
*/ 
var str = 'abcoefoxyozzopp'
var index = str.indexOf('o')
var num = 0;
while(index !== -1){console.log(index)num++index = str.indexOf('0',index+1);
}
console.log('o出现的次数是' + num)
//案例:遍历字符串
// charAt(index) 根据位置返回字符
var str= 'andy'
console.log(str.charAt(3))//遍历所有字符串
for(var i=0;i<str.length;i++){console.log(str.charAt(i))
}
// 有一个对象,判断该对象里有没有该属性 对象['属性名']
var o={age:18
}
if(o['age']){console.log('里面有该属性')
}else{console.log('里面没有该属性')
}
// 案例:统计字符串 'abcoefoxyozzopp' 中出现次数最多的字符 
/*
核心算法:利用 charAt() 遍历这个字符串;把每个字符都存储给对象,如果对象没有该属性,就为1,如果存在了就 +1;遍历对象,得到最大值和该字符;
*/
var str = 'abcoefoxyozzopp';
var o ={}
for(var i=0;i<str.length;i++){var charts=str.charAt(i) // charts 是字符串的每一个字符if(o[charts]){ //o[charts]得到的是属性值o[charts]++}else{o[charts]=1}
}
console.log(o)
// 遍历对象,求出出现最多的次数
var max = 0;
var ch = '';//统计出现次数最多的字符
for(var k in o){ //遍历对象用 for in // k 得到的是属性名// o[k] 得到的是属性值if(o[k]>max){max=o[k];ch=k}
}
console.log(max)
console.log(ch)
  • 替换字符:str.replace('被替换的字符','替换为的字符'),只会替换第一个字符;
//案例:有一个字符 'abcoefoxyozzopp' ,要求把里面所有的 o 替换为 *;(该方法可用于实现过滤敏感词等功能)
var str = 'abcoefoxyozzopp';
while(str.indexOf('o') !== -1){str = str.replace('o','*')
}
console.log(str)

JavaScript简单数据类型和复杂数据类型

数据类型内存分配

  • 【简单数据类型】又叫做【基本数据类型】或【值类型】;【复杂类型】又叫做【引用类型】;
    (1)、值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型;(string 、number 、boolean 、 undefined 、null(null 返回的是一个空的对象 Object))
    注意:如果有个变量我们以后打算存储为对象,暂时没想好放啥,这个时候就给 null;
    (2)、引用类型:复杂数据类型,在存储时变量中存储的仅仅是【地址】(引用),因此叫做引用数据类型;通过 new 关键字创建对象(系统对象、自定义对象),比如 Object 、Array 、 Date 等;

堆和栈

  • 堆栈空间分配区别?
    (1)、栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈;简单数据类型存放到栈里面,里面直接开辟一个空间,存放的是值
    (2)、堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收;复杂数据类型存放在堆里面;(复杂数据类型:首先在栈里面存放用【用十六进制表示】的地址,然后这个地址指向堆里面的数据)
    注意:JavaScript中没有堆栈的概念,通过堆栈的方式,可以让大家更容易理解代码的一些执行方式,便于将来学习其他语言;
    -
    在这里插入图片描述

简单类型传参(简单数据类型传参传值,复杂数据类型传参传地址)

  • 函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到外部的变量;
 function fn(a) {a++console.log(a); // 11}var x = 10fn(x)console.log(x);// 10

复杂类型传参

  • 函数的形参也可以看作是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
function Person(name){this.name=name
}function f1(x){//x=pconsole.log(x.name)//2、这里输出什么?刘德华x.name='张学友'console.log(x.name)//3、这里输出什么?张学友
}var p=new Person('刘德华')console.log(p.name)//1、这里输出什么?刘德华f1(p)console.log(p.name)//4、这里输出什么?张学友

Web APIs和JS基础

在这里插入图片描述

  • API:是为我们程序员提供的一个接口,帮助我们实现某种功能,我们会使用就可以了,不必纠结内部如何实现;
  • Web API:是浏览器提供的一套操作【浏览器功能】和【页面元素】的API(BOM和DOM)。主要是针对于浏览器提供的接口,主要针对于浏览器做交互效果;
  • Web API一般都有输入和输出(函数的传参和返回值),Web API很多都是方法(函数)。

Dom

  • 什么是Dom?文档对象模型(Document Object Model,简称Dom),是W3C组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口
  • W3C已经定义了一系列DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式。
  • Dom树:
    在这里插入图片描述
  • 文档:一个页面就是一个文档,DOM中使用document表示。
  • 元素:页面中的所有标签都是元素,DOM中使用element表示。
  • 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示。
  • DOM把以上内容都看做是对象。
  • DOM在我们实际开发中主要用来操作元素的。
  • 获取页面中的元素可以使用以下几种方法:(返回的是一个元素对象)
    (1)、根据ID获取;
    (2)、根据标签名获取;(返回的是获取过来元素对象的集合,以伪数组的形式存储的)(还可以获取某个元素(父元素)内部所有指定标签名的子元素,注意:父元素必须是【单个对象】(必须指明是哪一个元素对象),获取的时候不包括元素自己)
    var ol=document.getElementsByTagName('ol') console.log(ol[0].document.getElementsByTagName('li') )简单做法:给父元素添加ID,通过ID获取父元素,然后获取父元素里面的子元素;
    (3)、通过HTML5新增的方法获取;Document.getElementsByClassName()Document.querySelector('选择器')(根据指定选择器返回第一个元素对象)、Document.querySelectorAll('选择器')(根据指定选择器返回所有元素对象集合)
    (4)、特殊元素获取;
  • console.dir()打印我们返回的元素对象,更好的查看里面的属性和方法;
  • 获取body元素:document.body
  • 获取html元素:document.documentElement

事件

  • JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为;简单理解:触发 — 响应机制;
  • 事件三要素:事件是由三部分组成:事件源、事件类型、事件处理程序,被称为事件三要素
    (1)、事件源:事件被触发的对象;
    (2)、事件类型:如何触发,什么事件。比如:鼠标点击、鼠标经过、键盘按下;
    (3)、事件处理程序:通过一个函数赋值的方式完成;
<button id='btn'>按钮</button>var btn=document.getElementById('btn');
btn.onclick=function(){alert('弹窗')
}

在这里插入图片描述

操作元素

  • JavaScript的DOM操作可以改变网页内容、结构和样式,我们可以利用DOM操作元素来改变元素里面的内容、属性等。注意以下都是属性;

改变元素内容

  • element.innerText从起始位置到终止位置的内容,但它取出html标签,同时空格和换行也会去掉;(不识别html标签)非标准 去除空格和换行
<button>点击改变时间</button>
<div>写死的时间</div>
<p>123</p><script>// 1、获取元素var btn = document.querySelector('button');var div = document.querySelector('div')// 注册事件btn.onclick = function () {// div.innerText = '2022-1-2'div.innerText = getDate()}function getDate() {var date = new Date()var year = date.getFullYear();var month = date.getMonth();var dates = date.getDate();var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']var day = date.getDay();return '今天是:' + year + '年' + month + '月' + dates + '日' + arr[day]}// 我们元素可以不用添加事件var p = document.querySelector('p')p.innerText = getDate()
</script>
  • element.innerHTML起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行;(识别html标签)W3C标准 保留空格和换行
var p = document.querySelector('p')
p.innerHTML = '<strong>今天是:</strong>2022-1-2' //实现给‘今天是’加粗
  • 这两个属性是可读写的,可以获取元素里面的内容。
<p>我是文字<span>123</span>
</p>var p=document.querySelector('p')
console.log(p.innerText)//我是文字 123
console.log(p.innerHTML)//我是文字 <span>123</span>(空格和换行依然保留)

修改元素属性

常用元素的属性操作

  • innerTextinnerHTML改变元素内容;
  • srchref
  • idalttitle
//案例:分时问候案例
<img src="./images/shangwu.jpg" alt="">
<div>上午好</div><script>// 获取元素var img = document.querySelector('img')var div = document.querySelector('div')// 得到当前的小时数var date = new Date();var h = date.getHours();// 判断小时数改变图片和文字信息if (h < 12) {img.src = './images/shangwu.jpg'div.innerHTML = '上午好'} else if (h < 18) {img.src = './images/xiawuhao.jpg'div.innerHTML = '下午好'} else {img.src = './images/wanshanghao.jpg'div.innerHTML = '晚上好'}
</script>

表单元素的属性操作

  • 利用 DOM 可以操作如下表单元素的属性:type value checked selected disabled
  //1、获取元素var btn= document.querySelector('button')var input= document.querySelector('input')//2、注册事件  处理程序btn.onclick=function(){//btn.disabled=true //禁用按钮this.disabled=true //this 指向的是事件函数的调用者}  
//案例:仿京东显示隐藏密码明文案例
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>显示隐藏密码案例</title><style>.box {position: relative;width: 400px;border-bottom: 1px solid #ccc;margin: 100px auto;}.box input {width: 370px;height: 30px;border: 0;outline: none;}.box img {position: absolute;top: 2px;right: 2px;width: 24px;}</style>
</head><body><div class="box"><label for=""><img src="./images/green_close_eye.png" alt="" id="eye"></label><input type="password" name="" id="pwd"></div><script>var eye = document.getElementById('eye')var pwd = document.getElementById('pwd')//方法1: 利用flag变量记录点击var flag = 0eye.onclick = function () {// 点击一次过后,flag一定要变化if (flag == 0) {pwd.type = 'text'eye.src='./images/green_open_eye.png'flag = 1;//赋值操作} else {pwd.type = 'password'eye.src='./images/green_close_eye.png'flag = 0;}}//方法2: 计数器思想记录点击var count = 0;eye.onclick = function () {count++if (count % 2 == 0) {eye.src = "./images/green_close_eye.png"pwd.type = "password"} else {eye.src = "./images/green_open_eye.png"pwd.type = "text"}}</script>
</body></html>

样式属性操作

  • 我们可以通过JS修改元素的大小、颜色、位置等样式;
  • element.style行内样式操作;
  • element.className类名样式操作;
  • 注意:JS里面的样式采取驼峰命名法,比如:fontSize backgroundColor;JS修改style样式操作,产生的是行内样式,CSS权重比较高;
循环精灵图背景
//案例:循环精灵图背景;可以利用for循环设置一组元素的精灵图背景。
<!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;}li {list-style-type: none;}.box {width: 250px;margin: 100px auto;}.box li {float: left;width: 24px;height: 24px;background-color: pink;margin: 15px;background: url(./images/icons.png) no-repeat;}</style>
</head><body><div class="box"><ul><li></li><li></li><li></li><li></li></ul></div><script>// 1、获取所有元素,所有的livar lis = document.querySelectorAll('li')// 2、让索引号 乘以 44 就是每个 li 的背景y坐标,index就是我们的y坐标;for (var i = 0; i < lis.length; i++) {var index = i * 24 //我这张精灵图是24lis[i].style.backgroundPosition = '0-' + index + 'px'//精灵图的y坐标是负的;x坐标永远是0//lis[i].style.backgroundPosition = '0 0' //全部展示第一张图片//lis[i].style.backgroundPosition = '0 -24px' //全部展示第二张图片}</script>
</body></html>
案例:当鼠标点击文本框时,里面的默认文字隐藏;当鼠标离开文本框时,里面的文字显示;
//案例:当鼠标点击文本框时,里面的默认文字隐藏;当鼠标离开文本框时,里面的文字显示;
//`onfocus` `onblur`
<!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>input {color: #999;}</style>
</head><body><input type="text" value="手机"><script>var text = document.querySelector('input')text.onfocus = function () {console.log('得到了焦点');if (this.value === '手机') {this.value = ''}this.style.color = '#333'//获得焦点时把文本框里的文字的颜色变深}text.onblur = function () {console.log('失去了焦点');if (this.value === '') {this.value = '手机'}this.style.color = '#999'//失去焦点时把文本框里的文字的颜色变浅}</script>
</body></html>

样式属性操作:我们可以通过JS修改元素的颜色、大小、位置等样式

  • element.style 行内样式操作;
  • element.className 类名样式操作;
<!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>使用className修改样式属性</title><style>div{width: 50px;height: 50px;background-color: green;}.change{width: 100px;height: 100px;background-color: aqua;margin-top: 100px;}</style>
</head>
<body><div class='fist'>文本</div><script>var test=document.querySelector('div')test.onclick=function(){//我们可以通过 修改元素的 className 更改元素的样式,适合于样式较多或者功能复杂的情况       this.className='change'//点击时给div加上change的类名//如果想要保留原先的类名,我们可以这么做 --->  多类名选择器this.className='fist change'}</script>
</body>
</html>
  • 注意:className 会直接更改元素的类名,会覆盖原先的类名;
  • 如果想要保留原先的类名,我们可以这么做 —> 多类名选择器
案例:密码框验证信息
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>密码框验证信息案例</title><style>div {width: 600px;margin: 100px auto;}.message {display: inline-block;font-size: 12px;color: #999;background: url(./images/reg.jpg) no-repeat left center;padding-left: 20px;}.wrong {color: red;background-image: url(./images/wrong.jpg);//注意:此处不用写no-repeat left center}.right {color: green;background-image: url(./images/right.jpg);//注意:此处不用写no-repeat left center}</style>
</head><body><div class="register"><input type="password" class="ipt"><p class="message">请输入6~16位密码</p></div><script>var ipt = document.querySelector('.ipt')var messege = document.querySelector('.message')ipt.onblur = function () {if (this.value.length < 6 || this.value.length > 16) {messege.className = 'message wrong';messege.innerHTML = '你输入的位数不对,要求6~16位'} else {messege.className = 'message right';messege.innerHTML = '你输入的正确'}}</script>
</body></html>

操作元素小结:

在这里插入图片描述

排他思想

  • 如果有同一组元素,我们想要某一个元素实现某种样式,需要用到循环的排他思想算法;
    (1)、第一步:所有元素全部清除样式;
    (2)、第二步:给当前元素设置样式;
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>排他思想</title>
</head><body><button>按钮1</button><button>按钮2</button><button>按钮3</button><button>按钮4</button><script>// 首先先排除其他人,然后才设置自己的样式,这种排除其他人的思想我们称为排他思想var btns = document.querySelectorAll('button')for (var i = 0; i < btns.length; i++) {btns[i].onclick = function () {// 1、我们先把所有按钮的背景颜色去掉for (var i = 0; i < btns.length; i++) {btns[i].style.backgroundColor = ''}// 2、然后才让当前的元素背景颜色为pinkthis.style.backgroundColor = 'pink'}}</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;}body {background: url(./images/01.jpeg) no-repeat center top;}.baidu {overflow: hidden;margin: 100px auto;background-color: #fff;width: 410px;padding-top: 3px;}.baidu li {/* list-style: none; */float: left;margin: 0 1px;cursor: pointer;}.baidu img {width: 100px;}</style>
</head><body><ul class="baidu"><li><img src="./images/01.jpeg" alt=""></li><li><img src="./images/02.jpeg" alt=""></li><li><img src="./images/03.jpeg" alt=""></li><li><img src="./images/04.jpeg" alt=""></li></ul><script>// 1、获取元素(类名是 baidu 下的 img)var imgs = document.querySelector('.baidu').querySelectorAll('img')// 2、循环注册事件for (var i = 0; i < imgs.length; i++) {imgs[i].onclick = function () {// this.src 就是我们点击的图片的路径// 把这个路径 this.src 给 body 就可以了//document.body.style.backgroundImage获取body的背景图片document.body.style.backgroundImage = 'url(' + this.src + ')'}}</script>
</body></html>

表格隔行变色效果案例

//onmouseover鼠标经过  onmouseout鼠标离开
<!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>table{width: 800px;margin: 100px auto;text-align: center;border-collapse: collapse;//设置表格的边框是否被合并为一个单一的边框font-size: 14px;}thead tr{height: 30px;background-color: skyblue;}tbody tr{height: 30px;}tbody td{border-bottom: 1px solid #d7d7d7;color: blue;}.bg{background-color: pink;}</style>
</head>
<body><table><thead><tr><th>代码</th><th>名称</th><th>最新公布净值</th><th>累计净值</th><th>前单位净值</th><th>净值增长率</th></tr></thead><tbody><tr><td>003526</td><td>农行金穗3个月定期开放债券</td><td>1.075</td><td>1.079</td><td>1.074</td><td>+0.047%</td></tr><tr><td>003527</td><td>农行金穗4个月定期开放债券</td><td>1.075</td><td>1.079</td><td>1.074</td><td>+0.047%</td></tr></tbody></table><script>// 1、获取元素 获取 tbody 里面所有的 trvar trs=document.querySelector('tbody').querySelectorAll('tr')// 2、利用循环绑定注册事件for(var i=0;i<trs.length;i++){// 3、鼠标经过事件 onmouseovertrs[i].onmouseover=function(){this.className='bg';}// 4、鼠标离开事件 onmouseouttrs[i].onmouseout=function(){this.className='';}}</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>.wrap {width: 300px;margin: 100px auto;}table {width: 100%;margin: 100px auto;text-align: center;border-collapse: collapse;font-size: 14px;}thead tr {height: 30px;background-color: skyblue;}tbody tr {height: 30px;}tbody td {border-bottom: 1px solid #d7d7d7;}</style>
</head><body><div class="wrap"><table><thead><tr><th><input type="checkbox" id="j_cbAll"></th><th>商品</th><th>价钱</th></tr></thead><tbody id="j_tb"><tr><td><input type="checkbox"></td><td>iphone8</td><td>8000</td></tr><tr><td><input type="checkbox"></td><td>iphone9</td><td>9000</td></tr><tr><td><input type="checkbox"></td><td>iphone10</td><td>10</td></tr></tbody></table></div><script>// 第一步:全选和取消全选的做法:让下面所有复选框的checked属性(选中状态)跟随 全选按钮即可// 1、获取元素var j_cbAll = document.getElementById('j_cbAll'); // 全选按钮var j_tbs = document.getElementById('j_tb').getElementsByTagName('input');//下面所有的复选框// 2、注册事件j_cbAll.onclick = function () {// this.checked 它可以得到当前复选框的选中状态,如果是 true 就选中,如果是 false ,就是未选中;console.log(this.checked);for (var i = 0; i < j_tbs.length; i++) {j_tbs[i].checked = this.checked;//将全选按钮的选中或未选中状态赋值给所有的 checkbox }}//第二步:下面复选框需要全部选中,上面全选才能选中做法:给下面所有复选框绑定点击事件,每次点击,都要循环遍历for (var i = 0; i < j_tbs.length; i++) {j_tbs[i].onclick = function () {// flag 控制全选按钮是否选中var flag = true// 每次点击下面的复选框都要循环检查这四个小按钮是否全被选中for (var i = 0; i < j_tbs.length; i++) {if (!j_tbs[i].checked) {flag = false;break;//退出for循环,这样可以提高执行效率;因为只要有一个没有选中,剩下的就循环判断了;}}j_cbAll.checked = flag}}</script>
</body></html>

自定义属性的操作

获取自定义属性值

  • element.属性 获取属性值;
<div id='demo'></div>var div=document.querySelector('div')
// 获取元素的属性
// 方法1:element.属性
console.log(div.id); // demo
  • element.getAttribute('属性') attribute 本意“属性”;
<div id='demo'></div>var div=document.querySelector('div')
// 获取元素的属性
// 方法2:element.getAttribute('属性')
console.log(div.getAttribute('id')); // demo
  • element.属性 获取属性值 和 element.getAttribute('属性') 获取属性值 的区别?
    (1)、element.属性 获取内置属性值(元素本身自带的属性)如:id class等;
    (2)、element.getAttribute('属性') 主要获得自定义的属性(标准)我们程序员自定义的属性;

设置属性值

  • element.属性 = '值' 设置内置属性值;
<div id='demo' class='nav'></div>var div = document.querySelector('div')
div.className= 'sss'
  • element.setAttribute('属性','值') ;主要针对于自定义属性;
<div id='demo' index='1' class='nav'></div>var div = document.querySelector('div')
div.setAttribute('index','2')// class比较特殊,这里面写的就是class,不是className
div.setAttribute('class','sss')

移除属性

  • element.removeAttribute('属性')
<div id='demo' index='1' class='nav'></div>var div = document.querySelector('div')
div.removeAttribute('index')

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>.tab {width: 1200px;height: 100px;}.tab_list {width: 100%;float: left;}.tab_con {width: 100%;float: left;padding: 20px 60px;}.tab_list ul{width: 95%;height: 39px;background: rgb(223, 221, 221);}.tab_list li {float: left;height: 39px;line-height: 39px;padding: 0 20px;text-align: center;cursor: pointer;list-style: none;}.tab_list .current {background-color: #c81623;color: #fff;}.item_info {padding: 20px 0 0 20px;}.item {display: none;}</style>
</head><body><div class="tab"><div class="tab_list"><ul><li class="current">商品介绍</li><li>规格与包装</li><li>售后保障</li><li>商品评价</li><li>手机社区</li></ul></div><div class="tab_con"><div class="item" style="display: block;">商品介绍模块内容</div><div class="item">规格与包装模块内容</div><div class="item">售后保障模块内容</div><div class="item">商品评价模块内容</div><div class="item">手机社区模块内容</div></div></div><script>// 先获取父组件,再获取父组件下的所有的livar tab_list = document.querySelector('.tab_list');var lis = tab_list.querySelectorAll('li');var items = document.querySelectorAll('.item')// for循环绑定点击事件for (var i = 0; i < lis.length; i++) {// 开始给5个小li 设置索引号lis[i].setAttribute('index', i) // element.setAttribute('属性','值')// 1、上面的模块选项卡:点击某一个,当前这个底色会是红色,其余不变(排他思想) 修改类名的方式// 干掉所有人,其余的li清除class这个类lis[i].onclick = function () {for (var i = 0; i < lis.length; i++) {lis[i].className = '';}// 留下我自己this.className = 'current'/*2、下面的显示内容模块:下面的模块显示内容和上面的选项卡一一对应,相匹配;给上面的tab_list里面的所有小li添加自定义属性,属性值从0开始编号;*/var index = this.getAttribute('index')//element.getAttribute('属性')console.log(index);// 干掉所有人,让其余的item 这些div隐藏for (var i = 0; i < lis.length; i++) {items[i].style.display = 'none'}// 留下我自己,让对应的item显示出来items[index].style.display = 'block'}}</script>
</body></html>

H5自定义属性

  • 自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中;
  • 自定义属性获取是通过element.getAttribute('属性') 获取;但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性;
<div getTime='20'></div>// getTime 是自定义属性,只能通过 getAttribute 获取
var div = document.querySelect('div')
console.log(div.getTime) // undefined
console.log(div.getAttribute('getTime'))

H5给我们新增了自定义属性

设置H5自定义属性

  • H5规定自定义属性以 data- 开头作为属性名并且赋值;
<div data-index='1'></div>// 或者使用JS设置 element.setAttribute('data-index',2)
div.setAttribute('data-time',20)

获取H5自定义属性

  • 兼容性获取 element.getAttribute('data-index')
  • H5新增 element.dataset.index 或者 element.dataset['index'] ie11才开始支持;(只能获取以data- 开头的)
<div getTime="20" data-index="2" data-list-name="andy"></div><script>var div=document.querySelector('div')// H5新增的获取自定义属性的方法// dataset 是一个【集合】,里面存放了所有以data开头的自定义属性console.log(div.dataset);// DOMStringMap {index: '2'}console.log(div.dataset.index);// 2console.log(div.dataset['index']);// 2 // 如果自定义属性里面有多个 - 连接的单词,我们获取的时候采用【驼峰命名法】console.log(div.dataset.listName); //andy
</script>

DOM中的节点操作

  • 获取元素通常使用两种方式:
    (1)、利用DOM提供的方法获取元素:如:document.getElementById() 等;这种方法逻辑性不强、繁琐;
    (2)、利用节点层级关系获取元素:利用父子兄节点关系获取元素;这种方法逻辑性强,但是兼容性稍差;
    ** 这两种方法都可以获取元素节点,我们后面都会用到,但是节点操作更简单。

节点概述

  • 网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node 来表示;
  • HTML DOM 树中的所有节点均可以通过JavaScript 进行访问,所有HTML 元素(节点)均可被修改,也可以创建和删除;
  • 一般的,节点至少拥有nodeType (节点类型)、nodeName (节点名称)、nodeValue (节点值)这三个基本属性;
  • 元素节点nodeType 为1;
  • 属性节点nodeType 为2;
  • 文本节点nodeType 为3;(文本节点包含文字、空格、换行等)
  • 我们在实际开发中,节点操作主要操作的是元素节点;
<div class="box"></div>var box=document.querySelector('.box')
console.dir(box) 

在这里插入图片描述

节点操作之父节点

节点层级

  • 利用DOM 树可以把节点划分为不同的层级关系,常见的是【父子兄层级关系】;
父级节点: node.parentNode
  • 得到的是离元素最近的父级节点;如果指定的节点没有父节点就返回null
<div class="box"><span class="erweima"></span>
</div>//获取父节点
var erweima=document.querySelector('.erweima')
//获取 erweima 节点的父节点;得到的是离元素最近的父级节点
erweima.parentNode 

节点操作之子节点

子节点: parentNode.childNodes(标准)(获取到的是所有的子节点,包含 元素节点、文本节点等)

  • parentNode.childNodes 返回包含指定节点的子节点的集合,该集合为即时更新的集合;
  • 注意:返回值里面包含了所有的子节点,包括元素节点、文本节点等;如果只想要获得里面的元素节点,则需要专门处理。所以我们一般不提倡使用 childNodes
<ul><li></li><li></li><li></li>
</ul>//DOM提供的方法(API)获取
var ul=document.querySelector('ul')
var lis=ul.querySelectorAll('li')//子节点(获取到的是所有的子节点,包含 元素节点、文本节点等)
console.log(ul.childNodes)
  • 专门处理:只想要获得里面的元素节点
var ul=document.querySelector('ul')
for(var i=0;i<ul.childNodes.length;i++){if(ul.childNodes[i].nodeType == 1){//ul.childNodes[i]是元素节点console.log(ul.childNodes[i])}
}
  • parentNode.children (非标准):是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回(这个是我们重点掌握的);虽然parentNode.children 是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用。
//children 获取所有的子元素节点(也是我们实际开发常用的)
var ul=document.querySelector('ul')
console.log(ul.children )

节点操作之第一个子元素和最后一个子元素

<ol><li></li><li></li><li></li>
</ol>var ol=document.querySelector('ol')
//1、firstChild 第一个子节点,不管是文本节点还是元素节点;找不到就返回 null
console.log(ol.firstChild)
console.log(ol.lastChild)//2、firstElementChild 返回第一个子元素节点
console.log(ol.firstElementChild)
console.log(ol.lastElementChild)
  • parentNode.firstElementChildparentNode.lastElementChild 注意:这两个方法有兼容性问题,IE9 以上才支持;
  • 实际开发中,firstChildlastChild 包含其他节点,操作不方便;而firstElementChild lastElementChild 又有兼容性问题,那么我们如何获取第一个子元素节点或最后一个子元素节点呢?
    (1)、如果想要第一个子元素节点,可以使用parentNode.children[0]
//实际开发的写法,既没有兼容性问题又返回第一个子元素
console.log(ol.children[0])
console.log(ol.children[3])//第四个子元素//得到最后一个子元素
console.log(ol.children[ol.children.length-1])

新浪下拉菜单案例

<ul class="nav"><li><a href="#">微博</a><ul><li><a href="">私信</a></li><li><a href="">评论</a></li><li><a href="">@我</a></li></ul></li><li><a href="#">微博</a><ul><li><a href="">私信</a></li><li><a href="">评论</a></li><li><a href="">@我</a></li></ul></li><li><a href="#">微博</a><ul><li><a href="">私信</a></li><li><a href="">评论</a></li><li><a href="">@我</a></li></ul></li></ul><script>// 1、获取元素var nav = document.querySelector('.nav');var lis = nav.children; //得到四个小li// 2、循环遍历事件for (var i = 0; i < lis.length; i++) {lis[i].onmouseover = function () {this.children[1].style.display = 'block'}lis[i].onmouseout = function () {this.children[1].style.display = 'none'}}</script>

兄弟节点 node.nextSiblingnode.previousSiblingnode.nextElementSiblingnode.previousElementSibling

  • node.nextSibling 返回当前元素的下一个兄弟节点(包括【元素节点】 和 【文本节点】等等),找不到就返回null;同样,也是包含所有的节点;
<div>我是div</div>
<span>我是span<span>var div=document.querySelector('div')
console.log(div.nextSibling) //得到div的兄弟节点,包括元素节点 和 文本节点 #text
  • node.previousSibling 返回当前元素的上一个兄弟节点(包括【元素节点】 和 【文本节点】等等),找不到就返回null;同样,也是包含所有的节点;
  • node.nextElementSibling 返回当前元素下一个兄弟元素节点,找不到就返回null;
  • node.previousElementSibling 返回当前元素上一个兄弟元素节点,找不到就返回null;
  • node.nextElementSiblingnode.previousElementSibling 这两个方法有兼容性问题,IE9以上才支持;
如何解决兼容性问题?自己封装一个兼容性的函数。
function getNextElementSibling(element){var el=element;while(el=el.nextSibling){if(el.nodeType === 1){return el;}}return null
}

节点操作之创建和添加节点

创建节点:document.createElement('tagName')

  • document.createElement() 方法创建由tagName 指定的HTML 元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称之为【动态创建元素节点】;
<ul></ul>//创建元素节点(只是创建了节点,未添加到页面上)
var li=document.createElement('li');

添加节点:node.appendChild(child)node.insertBefore(child,指定元素)

  • node.appendChild(child) 方法将一个节点添加到指定父节点的子节点列表【末尾】。类似于css 里面的after 伪元素;(node 是父级;child 是子级)
<ul></ul>//创建元素节点(只是创建了节点,未添加到页面上)
var li=document.createElement('li');
var ul=document.querySelector('ul')
//将节点添加到页面上
ul.appendChild(li)
  • node.insertBefore(child,指定元素) 方法将一个节点添加到父节点的指定子节点的【前面】。类似于css 里面的before 伪元素;
<ul></ul>//创建元素节点(只是创建了节点,未添加到页面上)
var lili=document.createElement('li');
var ul=document.querySelector('ul')
//将节点添加到ul的第一个子节点的前面上
ul.insertBefore(lili,ul.children[0])
  • 总结:我们想要页面添加一个新的元素:1、创建元素;2、添加元素;
案例:简单版本发布留言
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>简单版发布留言案例</title>
</head><body><textarea name="" id="" cols="30" rows="10"></textarea><button>发布</button><ul></ul><script>// 1、获取元素var btn = document.querySelector('button');var text = document.querySelector('textarea');var ul = document.querySelector('ul');// 2、注册事件btn.onclick = function () {if (text.value == '') {alert('你没有输入内容')return false} else {// (1)、创建元素var li = document.createElement('li');// 先有li才能赋值li.innerHTML = text.value// (2)、添加元素// ul.appendChild(li) //添加到最后// 添加到最前面ul.insertBefore(li,ul.children[0])}}</script>
</body></html>

节点操作 – 删除节点 node.removeChild(child)

  • node.removeChild(child)方法从DOM 中删除一个子节点,返回删除的节点;
<button>删除</button>
<ul><li>熊大</li><li>熊二</li><li>光头强</li>
<ul>
//1、获取元素
var ul=document.querySelector('ul');
//2、删除元素
//ul.removeChild(ul.children[0]) //删除“熊大”
//3、点击按钮,依次删除里面的孩子
var btn=document.querySelector('button');
btn.onclick=function(){if(ul.children.length == 0){this.disabled= 'true' // 元素删完让按钮置灰}else{ul.removeChild(ul.children[0])}
}
案例:删除留言案例
<!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>li {width: 300px;padding: 5px;background-color: pink;color: red;font-size: 14px;margin: 15px 0;}li a {float: right;}</style>
</head><body><textarea name="" id="" cols="30" rows="10"></textarea><button>发布</button><ul></ul><script>// 1、获取元素var btn = document.querySelector('button');var text = document.querySelector('textarea');var ul = document.querySelector('ul');// 2、注册事件btn.onclick = function () {if (text.value == '') {alert('你没有输入内容')return false} else {// (1)、创建元素var li = document.createElement('li');// 先有li才能赋值// 小技巧:阻止连接跳转需要添加 javascript:void(0); 或 javascript:;li.innerHTML = text.value + "<a href='javascript:void(0)'>删除</a>"// (2)、添加元素// ul.appendChild(li) //添加到最后// 添加到最前面ul.insertBefore(li, ul.children[0])// (3)、删除元素 删除的是当前链接的li,它的父亲 this.parentNode var as = document.querySelectorAll('a')for (var i = 0; i < as.length; i++) {as[i].onclick = function () {ul.removeChild(this.parentNode);}}}}</script>
</body></html>
  • 小技巧:阻止<a></a>连接跳转需要添加javascript:void(0); javascript:; 如:<a href='javascript:void(0);'>删除</a>

节点操作 – 复制节点(克隆节点) node.cloneNode()

  • node.cloneNode()方法返回调用该方法的节点的一个副本。也称为【克隆节点】或【拷贝节点】;
<ul><li>1</li><li>2</li><li>3</li>
</ul>var ul=document.querySelector('ul')
//1、克隆节点,第一个li
var lili= ul.children[0].cloneNode()//2、将克隆的第一个节点放到页面中
ul.appendChild(lili)
  • 注意
    (1)、如果括号参数【空】或者为【false】,则是【浅拷贝】,即只克隆复制节点本身,不克隆里面的子节点。(只复制标签,不复制里面的内容。)node.cloneNode()
    (2)、 想要深拷贝,括号里面填true 即可(既复制标签,也复制里面的内容);node.cloneNode(true)
案例:动态生成表格
<!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>table {width: 500px;margin: 100px auto;border-collapse: collapse;text-align: center;}td,th {border: 1px solid #333;}thead tr {height: 40px;background-color: #ccc;}</style>
</head><body><table cellspacing="'0"><thead><tr><th>姓名</th><th>科目</th><th>成绩</th><th>操作</th></tr></thead><tbody></tbody></table><script>// 1、先准备好学生的数据var datas = [{ name: '张三', subject: 'javaSript', score: 100 },{ name: '李四', subject: 'javaSript', score: 100 },{ name: '王五', subject: 'javaSript', score: 100 },]// 2、往 tbody 里面创建行,有几个人(通过数组的长度)我们就创建几行;var tbody = document.querySelector('tbody')for (var i = 0; i < datas.length; i++) { //外面的for循环管行 tr// 创建 tr 行var tr = document.createElement('tr')tbody.append(tr) //将创建的 tr 放到 tbody 里// 行里面创建单元格 td (跟数据有关系的三个单元格),单元格的数量取决于每个对象里面的属性个数 for循环遍历对象for (var k in datas[i]) { //里面的for循环管列 td//创建单元格var td = document.createElement('td')// 把对象里面的属性值 datas[i][k]  给 tdconsole.log(datas[i][k]); //对象里面的属性值 td.innerHTML = datas[i][k];tr.append(td) //将创建好的 td 放到 tr 里               }// 3、创建有删除2个字的单元格var td = document.createElement('td');td.innerHTML = '<a href="javascript:;">删除</a>';tr.appendChild(td)}// 4、删除操作var as = document.querySelectorAll('a')for (var i = 0; i < as.length; i++) {as[i].onclick = function () {// 点击a,删除当前a所在的行(链接的爸爸的爸爸)tbody.removeChild(this.parentNode.parentNode)}}// 复习:for in 遍历对象// for(var k in obj){//     k 得到的是属性名//     obj[k] 得到的是属性值// }</script>
</body></html>

节点操作 – document.write 创建元素

三种动态创建元素的区别:

  • document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘;(页面上之前的元素被清除,重新创建了一个新的页面,新页面上只展示document.write创建的元素)
<button>点击</button><p>abdjk</p><script>// document.write 会导致页面重绘(页面上之前的元素被清除,重新创建了一个新的页面,新页面上只展示document.write创建的元素);(如果页面文档流加载完毕,再调用这句话会导致页面重绘)var btn=document.querySelector('button')btn.onclick=function(){document.write('<div>123</div>')}
</script>
//当整个页面都加载完了,再调用里面的函数
window.onload=function(){}
  • element.innerHTMLdocument.createElement 效率对比:
    (1)、element.innerHTML 是将内容写入某个DOM 节点,不会导致页面全部重绘;创建多个元素效率更高(不是拼接字符串,而是采取数组的形式拼接),结构稍微复杂;
    (2)、document.createElement 创建多个元素效率稍微低一点点,但是结构更清晰;
    (3)、总结:不同浏览器下,element.innerHTML 效率要比 document.createElement 高;

Dom 重点核心总结

  • 文档对象模型(Document Object Model,简称 DOM),是W3C组织推荐的处理可扩展标记语言(HTML 或 XML)的标准【编程接口】;
  • W3C已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式;
  • 对于 javaSript ,为了能够使 javaSript 操作 HTML ,javaSript 就有了一套自己的 DOM 编程接口;
  • 对于 HTML ,dom 使得 html 形成一棵 dom树,包含文档、元素、节点;
    在这里插入图片描述
  • 我们获取过来的DOM元素是一个对象(Object),所以称为【文档对象模型】;
  • 关于DOM操作,我们主要针对于【元素的操作】。主要有:创建、增、删、改、查、属性操作、事件操作;
  • 创建:document.writeinnerHtmlcreateElement
  • 增:appendChildinsertBefore
  • 删:removeChild
  • 改:主要修改dom的元素属性,dom元素的内容、属性、表单的值等
    (1)、修改元素属性:src href title 等;
    (2)、修改普通元素内容:innerHTML innerText
    (3)、修改表单元素:value type disabled 等;
    (4)、修改元素样式:style className
  • 查:主要获取查询dom的元素:
    (1)、DOM提供的API方法:getElementById 等;
    (2)、H5提供的新方法:querySelector querySelectorAll
    (3)、利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling nextElementSibling)提倡使用;
  • 属性操作:主要针对于自定义属性
    (1)、setAttribute :设置dom的属性值;
    (2)、getAttribute :得到dom的属性值;
    (3)、removeAttribute :移除属性;
  • 事件操作:给元素注册事件,采取 事件源.事件类型=事件处理程序
    在这里插入图片描述

事件高级

注册事件两种方式

  • 给元素添加事件,称为【注册事件】或者【绑定事件】;
  • 注册事件有两种方式:【传统方式】和【方法监听注册方式】;
    (1)、传统方式:利用 on 开头的事件 onclick ;特点:注册事件的【唯一性】,即同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数;
<button onclick='alert("hi~")'></button>
btn.onclick=function(){}

(2)、方法监听注册方式:W3C标准推荐方式;addEventListener() 它是一个方法;IE9之前的IE不支持此方法,可使用attachEvent() 代替;特点:同一个元素同一个事件可以注册多个监听器(事件处理函数);按注册顺序依次执行;

addEventListener()

  • 事件监听方式
  • eventTarget.addEventListener(type,lister[,useCapture]) 方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数;
    (1)、type :事件类型字符串,如:click mouseover 注意这里不要带on
    (2)、listener 事件处理函数,事件发生时,会调用该监听函数;
    (3)、useCapture 可选参数,是一个布尔值,默认是false
//注意:事件监听注册事件 addEventListener 里面的事件类型是字符串,要加引号,而且不带 on
//同一个元素,同一个事件可以添加多个侦听器(事件处理程序)
btn.addEventListener('click',function(){})

attachEvent 注册事件(IE9以前的版本支持)

  • eventTarget.attachEvent(eventNameWithon,callback)
  • eventTarget.attachEvent(eventNameWithon,callback)方法将指定的监听器注册到eventTarget (目标对象)上,当该对象触发指定的事件时,指定的回调函数就会被执行;
  • 该方法接收两个参数:
    (1)、eventNameWithon :事件类型字符串,比如:onclick onmouseover 这里要带 on ;
    (2)、callback:事件处理函数,当目标触发事件时回调函数被调用;
btn.attachEvent('onclick',function(){})

注册事件兼容性解决方案(封装兼容性函数)

  • 兼容性处理的原则:首先照顾大多数浏览器,再处理特殊浏览器;
<!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><script>function addEventListener(element, eventName, fn) {// 判断当前浏览器是否支持 addEventListener 方法if (element.addEventListener) {element.addEventListener(eventName, fn);//第三个参数 默认是false} else if (element.attachEvent) {element.attachEvent('on' + eventName, fn)} else {// 相当于 element.onclick = fnelement['on' + eventName] = fn}}</script>
</body></html>

删除事件(解绑事件)

删除事件的方式:

(1)、传统注册方式

eventTarget.onclick = null
<body><div>1</div><div>2</div><div>3</div><script>var divs = document.querySelectorAll('div')divs[0].onclick = function () {alert(11)//传统方法删除事件divs[0].onclick = null}</script>
</body>

(2)、方法监听注册方式

  • 方法1:
eventTarget.removeEventListener(type,listener[,useCapture]);
<body><div>1</div><div>2</div><div>3</div><script>var divs = document.querySelectorAll('div')// removeEventListener 删除元素divs[1].addEventListener('click', fn) //里面的 fn 不需要加小括号调用function fn() {alert(22);divs[1].removeEventListener('click', fn)}</script>
</body>
  • 方法2:(谷歌浏览器不兼容)
eventTarget.detachEvent(eventNameWithOn,callback);
<div>1</div>
<div>2</div>
<div>3</div>	var divs = document.querySelectorAll('div')
divs[2].attachEvent('onclick', fn1);function fn1() {alert(33)divs[2].detachEvent('onclick', fn1)}
删除事件兼容性解决方案
function removeEventListener(element,eventName,fn){//判断当前浏览器是否支持 removeEventListener 方法if(element.removeEventListener){element.removeEventListener(eventName,fn);//第三个参数,默认是false}else if(element.detachEvent){element.detachEvent('on'+eventName,fn);}else{element['on'+eventName]=null;}
}

DOM事件流

  • 事件流描述的是从页面中接收事件的顺序;
  • 事件发生时会在元素节点之间按照待定的顺序传播,这个传播过程DOM事件流
    -
    在这里插入图片描述
  • 注意:
    (1)、JS代码中只能执行捕获或者冒泡其中的一个阶段;
    (2)、onclickattachEvent 只能得到冒泡阶段;
    (3)、addEventListener(type,listener[,useCapture]) 第三个参数如果是 true ,表示在事件捕获阶段调用事件处理程序;如果是false (不写默认是false),表示在事件冒泡阶段调用事件处理程序;
    (4)、实际开发中我们很少使用事件捕获,更关注事件冒泡;
    (5)、有些事件是没有冒泡的,比如:onblur onfocus onmouseenter onmouseleave
<!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>DOM事件流</title><style>.father {width: 200px;height: 200px;background-color: aqua;}.son {width: 100px;height: 100px;background-color: blueviolet;margin: 0 auto;}</style>
</head><body><div class="father"><div class="son">son盒子</div></div><script>/*DOM事件流 三个阶段:1、JS代码中只能执行捕获或者冒泡其中的一个阶段;2、onclick 和 attachEvent(ie)只能得到冒泡阶段;3、捕获阶段 如果 addEventListener 第三个参数是 true 那么则处于捕获阶段;document->html->body->father->son*/// var son = document.querySelector('.son')// son.addEventListener('click', function () {//     alert('son')// }, true)// var father = document.querySelector('.father')// father.addEventListener('click', function () {//     alert('father')// }, true)// 4、冒泡阶段 如果 addEventListener 第三个参数是 false 或者省略, 那么则处于冒泡阶段;son->father->body->html->documentvar son = document.querySelector('.son')son.addEventListener('click', function () {alert('son')}, false)var father = document.querySelector('.father')father.addEventListener('click', function () {alert('father')}, false)document.addEventListener('click', function () {alert('document')})</script>
</body></html>

事件对象

eventTarget.onclick=function(event){} 
eventTarget.addEventListener('click',function(event){})
  • 这个event 就是事件对象,我们还喜欢写成 e 或者 evt
  • 这个event是个形参,系统帮我们设定为事件对象,不需要传递实参过去;
  • 当我们注册事件时,event对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数);
  • 官方解释:event 对象代表事件的状态,比如键盘按钮的状态、鼠标的位置、鼠标按钮的状态;
  • 简单解释:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法;比如:谁绑定了这个事件;鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置;键盘触发事件的话,会得到键盘的相关信息,如按了哪个键;
  • 在IE6~8中,浏览器不会给方法传递参数,如果需要的话,需要到window.event中获取查找;解决:
    e=e || window.event
<!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><div>123</div><script>var div = document.querySelector('div')div.onclick = function (event) {console.log(event);}div.addEventListener('click', function (event) {console.log(event);})/*1、event 就是一个事件对象,写到我们侦听函数的 小括号里面,当形参来看;2、事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数;3、事件对象是我们事件的一系列相关数据的集合,跟事件相关的;比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标;如果是键盘事件,里面就包含了键盘事件的信息,比如:判断用户按下了哪个键;4、这个事件对象我们可以自己命名,比如:event、evt、e;5、事件对象也有兼容性问题,ie678通过 window.event 获取;兼容性写法:e=e || window.event;*/        </script>
</body></html>

事件对象的常见属性和方法

1、targetthis 区别

在这里插入图片描述

  • (1)、e.target 返回的是触发事件的对象(元素);
<body><div>123</div><ul><li>abc</li><li>abc</li><li>abc</li></ul><script>var div=document.querySelector('div')div.addEventListener('click',function(e){console.log(e.target); //<div>123</div>console.log(this); //<div>123</div>})</script>
</body>

注意this 返回的是绑定事件的对象(元素);

<body><div>123</div><ul><li>abc</li><li>abc</li><li>abc</li></ul><script>var div = document.querySelector('div')div.addEventListener('click', function (e) {console.log(e.target); //<div>123</div>console.log(this); //<div>123</div>})var ul = document.querySelector('ul')ul.addEventListener('click', function (e) {//我们给ul绑定了事件,那么 this 就指向 ulconsole.log(this);//<ul><ul>// 注意:此处没有写第三个参数,所以默认是false(冒泡),li 没有绑定点击事件,点击的是 li ,li没找到事件就往上找,这是冒泡;console.log(e.currentTarget);// 了解:跟 this 有个非常相似的属性 currentTarget (IE678不兼容)console.log(e.target);//<li><li>})/*区别:e.target 点击了哪个元素,就返回哪个元素;this 哪个元素绑定了这个点击事件,那么就返回谁;*/ // 考虑兼容性问题的写法div.onclick = function (e) {e = e || window.event;var target = e.target || e.srcElement;console.log(target);}</script>
</body>
2、e.type
<body><div>123</div><a href="http://www.baidu.com">百度</a><form action="http://www.baidu.com"><input type="submit" value="提交" name="sub"></form><script>// 常见事件对象的属性和方法// 返回事件类型var div = document.querySelector('div')div.addEventListener('click', fn);div.addEventListener('mouseover', fn)div.addEventListener('mouseout', fn)function fn(e) {console.log(e.type);}</script>
</body>
3、事件对象阻止默认行为
<a href="http://www.baidu.com">百度</a>
<form action="http://www.baidu.com"><input type="submit" value="提交" name="sub">
</form>// 阻止默认行为(事件):让链接不跳转,或者让提交按钮不提交;
var a=document.querySelector('a');
a.addEventListener('click',function(e){e.preventDefault();//DOM推荐的标准写法(低版本IE浏览器不支持)
})
// 传统的注册方式
a.click = function (e) {// 普通浏览器 e.preventDefault();---> 方法e.preventDefault()// 低版本浏览器 ie678 用 returnValue ---> 属性e.returnValue;/*我们可以利用 return false ,也能阻止默认行为,而且没有兼容性问题;特点:return后面的代码不执行了,而且只限于传统的注册方式;*/ return false
}
4、阻止事件冒泡
  • 事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点;事件冒泡本身的特性,会带来的坏处,也会带来好处,需要我们灵活掌握;
  • 阻止事件冒泡:标准写法:利用事件对象里面的stopPropagation() 方法;
<body><div class="father"><div class="son">son盒子</div></div><script>var son = document.querySelector('.son')son.addEventListener('click', function (e) {alert('son')e.stopPropagation(); //stop停止  propagation 传播 ;有兼容性问题e.cancelBubble=true;// 低版本IE浏览器}, false)var father = document.querySelector('.father')father.addEventListener('click', function () {alert('father')}, false)document.addEventListener('click', function () {alert('document')})if(e && e.stopPropagation){e.stopPropagation();}else{window.event.cancelBubble=true;}</script>
</body>
5、事件委托(代理、委派)
  • ul里面有多个li,点击每个li都会弹出对话框,以前需要给每个li注册事件,是非常辛苦的,而且访问DOM的次数越多,这就会延长整个页面的交互就绪时间;
  • 事件委托:也称为事件代理,在jQuery里面称为事件委派
  • 事件委托的原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。以上案例:给ul注册点击事件,然后利用事件对象的target 来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器;
  • 事件委托的作用:我们只操作了一次DOM ,提高了程序的性能;
<body><ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul><script>var ul = document.querySelector('ul')ul.addEventListener('click', function fn(e) {// alert('被点击了')// e.target 可以得到我们点击的对象e.target.style.backgroundColor = 'pink'})</script>
</body>
6、常用的鼠标事件
  • event 对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象MouseEvent和键盘事件对象KeyboardEvent
    在这里插入图片描述
  • 禁止鼠标右键菜单:contextmenu 主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单;
document.addEventListener('contextmenu',function(e){e.preventDefault();
})
  • 禁止鼠标选中:selectstart 开始选中;
document.addEventListener('selectstart',function(e){e.preventDefault();
})
<body>我是一段不愿意分享的文字<script>// contextmenu 可以禁用右键菜单document.addEventListener('contextmenu', function (e) {e.preventDefault();})// 禁止选中文字 selectstartdocument.addEventListener('selectstart', function (e) {e.preventDefault();})</script>
</body>
  • 获得鼠标在页面中的坐标:鼠标事件对象MouseEvent
    在这里插入图片描述
<script>// 鼠标事件对象 MouseEventdocument.addEventListener('click', function (e) {// 1、client 鼠标在可视区的x和y坐标console.log(e.clientX);console.log(e.clientY);// 2、page 鼠标在页面文档的x和y坐标console.log(e.pageX);console.log(e.pageY);// 3、screen 鼠标在电脑屏幕的x和y坐标console.log(e.screenX);console.log(e.screenY);})</script>
  • 案例:跟随鼠标的天使
<!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>img {position: absolute;}</style>
</head><body><img src="./images/angel.gif" alt=""><script>/*1、鼠标不断的移动,使用鼠标移动事件:mousemove;2、在页面中移动,给 document 注册事件;3、图片要移动距离,而且不占位置,我们使用绝对定位即可;4、核心原理:每次鼠标移动,我们都会获得最新的鼠标坐标,把这个 x 和 y 坐标作为图片的 top 和 left 值就可以移动图片;*/var pic = document.querySelector('img')document.addEventListener('mousemove', function (e) {// mousemove 只要我们鼠标移动1px,就会触发这个事件;var x = e.pageX;var y = e.pageY;console.log('x坐标是' + x, 'y坐标是' + y);// 注意:千万不要忘记给 left 和 top 添加 px 单位;// 减50和40是减去图片的长和宽的一半,从而使鼠标箭头的位置处于图片的中心;pic.style.left = x - 50 + 'px';pic.style.top = y - 40 + 'px';})</script>
</body></html>
7、常用的键盘事件

在这里插入图片描述

  • 三个事件的执行顺序:keydown –> keypress –> keyup
  • 利用keyCode 判断用户按下哪个键;
  • 键盘事件对象中的keyCode属性可以得到相应键的ASCII值码;
    在这里插入图片描述
<body><script>// 键盘事件对象中的 keyCode 属性可以得到相应键的 ASCII 码值;// 1、我们的 keyup 和 keydown 事件不区分字母大小写;例如:a 和 A 得到的都是65;// 2、我们的 keypress 事件,区分字母大小写;例如:a 得到的都是 97 和 A 得到的都是 65;document.addEventListener('keyup', function (e) {console.log(e);console.log('up:' + e.keyCode);if (e.keyCode === 65) {alert('按下了a键')} else {alert('没有按下a键')}})document.addEventListener('keypress', function (e) {console.log(e);console.log('press:' + e.keyCode);})</script>
</body>
  • 案例:模拟京东按键输入内容
<body><input type="text"><script>/*1、核心思路:检测用户是否按下了s键,如果按下s键,就把光标定位到搜索框里面;2、使用键盘事件对象里面的keyCode判断用户按下的是否是s键;3、搜索框获得焦点:使用js里面的 focus() 方法;*/var search = document.querySelector('input')document.addEventListener('keyup', function (e) {//此处用keydowm会把s填入输入框console.log(e.keyCode);if (e.keyCode === 83) {search.focus();}})</script>
</body>
  • 案例:模拟京东快递单号查询
<!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>body,html {margin: 0;padding: 0;}.search {position: relative;width: 178px;margin: 100px;}.con {display: none;position: absolute;top: -40px;width: 171px;border: 1px solid rgba(0, 0, 0, .2);box-shadow: 0 2px 4px rgba(0, 0, 0, .2);padding: 5px 0;font-size: 18px;line-height: 20px;color: #333;}.con::before {  /* 倒三角形 */content: '';width: 0;height: 0;position: absolute;top: 28px;left: 18px;border: 8px solid #000;border-style: solid dashed dashed;border-color: #fff transparent transparent;}</style>
</head><body><!-- 案例分析:(1)、快递单号输入内容时,上面的大号字体盒子(con)显示(这里面的字号更大);(2)、表单检测用户输入:给表单添加键盘事件;(3)、同时把快递快递单号里面的值(value)获取过来赋值给con盒子(innerText)作为内容;注意:keydown 和 keypress 在文本框里的特点:他们两个事件触发的时候,文字还没有落入文本框中;keyup 事件触发的时候,文字已经落入文本框里面了;--><div class="search"><div class="con">123</div><input type="text" placeholder="请输入您的快递单号" class="jd"></div><script>var con = document.querySelector('.con');var jd_input = document.querySelector('.jd');jd_input.addEventListener('keyup', function () {if (this.value === '') {con.style.display = 'none';} else {con.style.display = 'block';con.innerText = this.value;}})//当我们失去焦点,就隐藏这个con盒子jd_input.addEventListener('blur', function () {con.style.display = 'none'})//当我们获得焦点,就显示这个con盒子jd_input.addEventListener('focus', function () {if (this.value !== '') {con.style.display = 'block'}})        </script>
</body></html>

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注