JavaScript知识整理

   日期:2020-04-30     浏览:123    评论:0    
核心提示:快乐的棒棒糖~~资料纯手打。也算自己又重新复习了一遍吧。希望对小伙伴们有所帮助23333~JavaSjavascript

全部JavaScript内容整理,全文除前面内容因知识较琐碎或为了更好的表达而用了部分图片外,共计约6万字,全手打。全部整理在一起而不是分开来写,主要是方便以后有疑问直接Ctrl + F搜索文档,即可查询。

JS主要分为3部分,即 ECMAScript , DOM,BOM。移动端暂时没写进来。

因时间仓促,每天凌晨挤时间整理,难免有遗漏,以后发现后会回来补。

话不多说,干货奉上~

JavaScript

计算机基础(了解)

数据存储单位

bit byte kb Gb Tb

如图:

java和javascript的关系: 两者毫无关系。类似于雷锋和雷峰塔的关系。 script是脚本的意思。javascript 是脚本语言,会逐行解释执行。简称JS。

html / css / js三者的关系

三者的简单介绍

html / css 标记语言 ---- 描述类语言 html 决定网页结构和内容(决定看到什么)。相当于人的身体。比如这样:


css决定网页呈现给用户的模样(决定好不好看)。相当于给人穿衣服、化妆等。比如这样:

JS脚本语言---- 编程类语言
实现业务逻辑和页面控制(决定功能)。相当于人做出的各种动作。比如这样:

JS的组成

JS包括三部分: 1,ECMAScript ,即欧洲计算机制造商协会通过的一种标准化的脚本程序设计语言。在这之前,脚本语言比较混乱。 2,DOM,即document object model 页面文档对象模型。它的主题是document。 3,BOM,即brower object model 浏览器对象模型。其实更应该叫做 WOM,即 window object model ,因为它的作用对象就是window。

JS的三种书写位置(和CSS非常相似)

1,**行内式**。即 直接写在标签里。比如:


特点:
①可以将单行或者少量JS代码写在HTML标签的事件属性中(以on开头的属性),如:onclick。
②注意单双引号的使用:在THML中推荐使用双引号,在JS中推荐使用单引号。
③可读性差,在HTML中编写JS大量代码时,不方便阅读;
④引号易错,引号多层嵌套匹配时,非常容易弄混淆。
⑤在特殊情况下使用。
2,内嵌式。写在被head标签包含。比如:

 <head>
 	<script>
 		alert('hello world');
 	</script>
 </head>

特点:①可以将多行JS写到

<body>
	<div>
	</div>
	...
	<script src="js/my.js"></script>
</body>

①利于HTML页面代码结构化,把大段JS代码独立到HTML页面之外,既美观,又方便文件级别的复用。
②引用外部JS文件的

JS的注释方法(这点和java一样的)

1,单行注释: //内容 2,多行注释:

JS输入输出语句:

1,在F12里输出: console('内容'); 2,在页面弹窗里输出: alert('内容'); 3,在页面弹窗里输入:prompt('内容');

JS变量

什么是变量

白话:变量就是一个装东西的盒子。 通俗:变量是用于存放数据的容器。完美通过**变量名**获取数据,甚至可以修改数据。 比如以下三种变量:

变量在内存中的存储

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


类似于酒店的房间,一个房间就可以看作一个变量。

变量的使用

变量在使用时分为两步: 1,**声明变量**。
//声明一个名称为age的变量。
var age;

var是JS的一个关键字。用来声明变量(variable变量的意思)。使用该关键字声明变量后,计算机会自动为变量分配内存空间,不需要程序员管。
②age是程序员定义的变量名。我们要通过变量名来访问内存中分配的空间。
2,给变量赋值。

age = 10;//给age这个变量赋值为10.

① = 用来把右边的值 赋给左边的变量空间中。此处代表赋值的意思。
②变量值是程序员保存到变量空间里的值。
3,变量的初始化。

var age = 18; //声明变量同时赋值为18.

声明一个变量并赋值,我们称之为变量的初始化。

变量的语法扩展

1,更新变量 一个变量被重新赋值后,它原有的值就会被覆盖。变量值将以最后一次赋的值为准。
var age = 18;
age = 19;//最后的结果就是19.因为18被新赋值的19给覆盖了。

2,同时声明多个变量
同时声明多个变量时,只需要写一个var,多个变量名之间使用英文逗号隔开。比如:

var age = 10, name = 'zs', sex = 2;

3,声明变量的特殊情况。
①只声明,不赋值。比如:

var age;
console.log(age);

输出结果就是 undefined。
②不声明,只赋值。

age = 10;
console.log(age);

输出结果是 10.
③不声明,不赋值

console.log(age);//没声明,也没赋值

输出结果时直接报错。

变量的命名规范


提示:也不要用name作为变量名。

数据类型

为啥需要数据类型

在计算机中,不同的数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间。于是定义了不同的数据类型。

变量的数据类型

变量是用来存储值的所在处,它们有名字和数据类型。变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。JS是一种弱类型或者说是动态语言。这意味着不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。

比如:
var age = 10; //这个age变量是一个数字型。
var areYouOk = '是的'; //这是一个字符串。
//在代码运行时,变量的数据类型是由JS根据等号右边的变量值的数据类ing来判断的。
//运行完毕后,变量就确定了数据类型。

JS拥有动态类型,同时也意味着相同的变量科用作不同的类型。比如:

var x = 6; //变量x是数字。
var x = 'Bill'; //现在x是字符串了。

简单数据类型(基本数据类型)

JS中的简单数据类型及其说明如下: 数字型 布尔型 字符串型 undefined null 五个类型。


数字型的三个特殊值
Infinity -Infinity NaN

判断一个变量是否为非数字型: isNaN() 。

字符串型String

字符串转义符

字符串长度

变量.length

var strMsg = 'haha';
alert(strMsg.length);//输出结果是4

字符串拼接

拼接符: + 字符串 + 任何类型 = 拼接之后的新字符串类型 拼接前会把与字符串相加的任何类型转换成字符串,再拼接成一个新的字符串。


拼接号 + 的口诀: 数值相加,字符相连。
还有一种常用情形: 字符串 + 变量 + 字符串
比如:

var age = 18;
console.log('我今年' + age + '岁了');//输出结果:我今年18岁了

布尔型 Boolean

布尔类型有两个值: true 真 和 false 假 。 布尔型和数字型相加的时候,true的值是1, false的值是0.
console.log(ture + 1);//2
console.log(false + 1); //1

undefined 和 null

获取变量的数据类型

typeof() 可用来获取检测变量的数据类型。

数据类型转换

转换成字符串类型有三种方法: 1,变量.toString() 。 2,String(变量)。 3, ' ' + 变量 。 经常用的方式。

转换为数字型

有4种方法: 1,parseInt(变量)。这是转换为整数数字型。小数不行。 2,parseFloat(变量) 。这是转换为小数的数字型。 3, Number(变量) 。 4,利用运算符号 - * / ,进行隐式转换。 ‘12’ - 0 , ‘123’ - ‘120’ 。

如何判断一个数是整数

有两种方法: 1, 如果一个数是整数,那么parseInt()函数和parseFloat() 函数的返回值是相同的,反之返回不同的值说明是小数,根据这个特点来判断一个数是整数还是小数。 2, 用Number.isInteger(变量)来检验。
Number.isInteger(3) // true
Number.isInteger(3.1) // false
Number.isInteger('') // false
​Number.isInteger('3') // false
​Number.isInteger(true) // false
Number.isInteger([]) // false

转换为布尔型

方法: Boolean(变量)。

运算符(Operater)

算术运算符

符号: + - * / %


算术运算符优先级问题: 先乘除,后加减,有()就先算()里面的。

浮点数的精度问题

浮点数值的最高精度是17位小数,但在进行计算时其精度远远不如整数。

递增和递减运算符(容易懵,多练习!)

前置递增运算符

++num ; 类似于 num = num + 1; 先自加,后赋值。

后置递增运算符

num++; 类似于 num = num + 1 ; 先赋值,后自加。
总结:前置就是先自加,后置就是后自加。

比较运算符

两个数据进行比较时所使用的运算符,比较运算后,会返回一个布尔值(true/ false)作为比较运算的结果。 运算符号: > < >= <= == != === !==


注意:‘37’ == 37 true ==会把字符串型的37转化为数字型的37,然后再和37进行比较。

===就不会转换了。

逻辑运算符 && || !

返回值也是布尔值。经常用于多个条件的判断。 && : 一假为假,全真为真。 || : 一真为真,全假为假。 ! : 非真为假, 非假为真。

逻辑运算符的短路运算(逻辑中断)

表达式1 && 表达式2: 如果1为真,则返回表达式2 。如果1为假,返回表达式1 。 就不会再去看表达式2了,更不会去执行。
console.log(1 && 2);//结果: 2
console.log(0 && 6);//结果: 0

||的短路运算
和&&刚好相反。 如果表达式1的结果为真,则返回表达式1,就根本不会再去看表达式2写的什么了,表达式2根本就不会有执行的机会; 如果表达式1为假,那么返回表达式2.

console.log(1 || 2);//结果: 1
console.log(0 || 1);//结果: 1

赋值运算符 = += -= *= /= %=

num += 2 相当于 num = num + 2;其他符号类似。

运算符的优先级

如下表:

流程控制:控制代码的执行顺序

分为三种结构: 1,顺序结构。就是按照正常的顺序,由前到后依次执行。 2,分支结构: if ,if else,else 。三元表达式 , switch语句。
if(条件语句) {
  执行语句;
} else {
   执行语句;
}
----
if() {
}
else if {
}
else if {
} ...
else {
}
-----
三元表达式:    条件表达式 ? 执行语句1 : 执行语句2 
------
switch (表达式) {
case1: 执行语句1breakcase2: 执行语句1break...
 default:
      最后执行语句;
}

if else结构 和 if else if 结构的区别: 如果有一个else if满足条件并执行语句,那么直接退出,并且剩下的所有else if都将不会被访问。
3,循环结构: for , while , do while 。
for(初始化变量; 条件表达式; 操作表达式){
  被循环的语句;
}
forvar i = 1; i <= 100; i++) {

console.log('hello world');

}

执行顺序:1,先执行var i = 1;

​          2,再执行判断语句  i <= 100;3,接着执行 console.log('hello world');4,最后执行 i++5,第二轮:这时候 i的值变成2 了, 仍然是先执行var i = 1; 依此类推。

断点判断法,判断执行顺序。 F12 里面 sources  找到需要调试的文件  在程序的某一行设置断点。
------------------------
while(条件表达式){
	循环体代码;
}

while执行思路:

do {
	循环体代码-条件表达式为true时 重复执行循环体代码;
}while(条件表达式);

do while 执行思路:

循环小结

循环中的continue 关键字

意思是 退出当前条件下的循环,直接跳到下一次的循环继续进行。

例如,小朋友能吃5个包子,当他准备吃第3个包子的时候,发现包子里有虫子,然后把第3个包子扔掉了,继续去吃第4个包子和第5个包子。 所以他一共只吃了4个包子。

循环中的break关键字

意思是 退出从当前条件下的剩余所有循环。到此就终止所有循环了。

例如,小朋友能吃5个包子,当他准备吃第3个包子的时候,发现包子里有虫子,一气之下把第3个包子扔掉了,接着第4个和第5个包子也扔掉了。所以他一共只吃了2个包子。

数组:本质就是变量。可以存更多值的变量!

如图:

创建数组

两种方法: 1,用new创建数组。
var 数组名 = new Array();
var arr = new Array();//创建了一个新的空数组

2,用数组字面量创建数组[ ](更简单)

//1,使用数组字面量方式创建空的数组
var arr = [];
//2,使用数组字面量方式创建带初始值的数组
var arr1 = ['1','haha','pink']

数组的索引

//定义数组
var arrStus = [1,2,3];
//获取数组中的第二个元素
console.log(arrStus[1]);
//操作数组的行为,都是通过操作索引号来完成的。

用循环可以遍历数组。

给数组新增元素,给数组扩容

方法1: 修改length长度。
//就是直接让length属性等于另外一个值。


方法2: 修改数组索引新增数组元素。

冒泡排序

#### 把一系列数据从大到小或从小到大排序显示。

两两比较,交换位置。

函数

就是封装的一段可被重复调用执行的代码块。封装就是用{}包起来。有点像电脑主机把里面的零件包起来。

函数的使用:先声明一个函数,再调用函数。

声明函数

//声明函数
function 函数名() {
	//函数体代码
}
//function是声明函数的关键字,必须小写。

调用函数

//调用函数
函数名();//通过调用函数名来执行函数体代码。
//调用的时候千万不要忘记添加()

函数的参数

参数分为形参和实参。
//声明时:
function 函数名(形参1,形参2...{
	...
}
//调用时:
函数名(实参1,实参2...

形参就是不用声明的变量。
用法举例:

function cook(aru) {
	console.log(aru);
}
cook('番茄炒蛋');
cook('黄瓜炒蛋');

函数的返回值

用return语句。 把返回值返回给函数调用者。由函数调用者决定是否输出。举例:
function getSum(num1, num2) {
	return num1 + num2;
}
console.log(getSum(1, 2));

return最多只能返回一个值。

如果确实需要返回多个值,可以用数组。return[值1, 值2…]。
函数如果有return,则返回return后面的值。
如果没有return,返回的是undefined 。
return的另一个用处: 终止return后面的代码。也就是函数中return后面的代码不会再被执行。

arguments

只有函数才有arguments,函数内置的,默认存在的。 arguments就是一个默认存在的数组。不用创建,可以直接拿来用。
//arguments的使用
function fn() {
	console.log(arguments);//里面存储了所有传递过来的实参。
	console.log(arguments.length);
	console.log(arguments[2]);
	//我们可以按照数组的方式遍历arguments
	for(var i = 0;i < arguments.length; i++) {
		console.log(arguments[i]);
	}
}
//调用上面的函数。
fn(1, 2, 3);
fn(1,2,3,4,5);

arguments应用举例:

//利用函数求任意个数的最大值
function getMax() {
	var max = arguments[0];
	for(var i = 0; i < arguments.length; i++) {
		if(arguments[i] > max) {
			max = arguments[i];
		}
	}
	return max;
}
console.log(getMax(1,2,3));
console.log(getMax(11,2,34,444,5,100));

函数可以调用另一个函数

因为每个函数都是独立的代码块,用于完成特殊任务,因此经常会用到函数相互调用的情况。

举例:
function fn1() {    

​      console.log(111);       //这里是执行的第**二**步。 输出111.**fn2();**           //这里是执行的第**三**步。 调用fn2()函数。

​       console.log('fn1');      //第**六**步。fn1()函数还没执行完,继续执行。 输出fn1.

}

function fn2() {

​         console.log(222);  //这里是执行的第**四**步。 开始执行fn2()函数里的语句。输出222.

​         console.log('fn2');      //这里是执行的第**五**步。 输出fn2. 

}

fn1();  //执行顺序:上面的fn1()和fn2()函数都还没调用,不执行。这里是第**一**步。 调用fn1()函数。

函数的声明

两种声明方式:

1,利用函数关键字自定义函数(命名函数)
function fn() {
	...
}
fn();//调用函数。
//这种声明方式就是前面讲的构造函数的方式。

2,函数表达式(匿名函数)

var 变量名 = function() {
	...
}
变量名();//调用函数
注意:
1,函数表达式声明方式跟声明变量差不多,
只不过变量里面存的是一个函数。
2,函数表达式也可以传递参数。比如:
var fun = function(aru) {
	console.log('我是函数表达式');
}
fun('pink');

作用域

分为 全局作用域 和 局部作用域。 //局部作用域也叫函数作用域,因为在函数内部的变量都是局部变量。在函数外面不起作用。

注意:如果在函数内部,没有声明,直接赋值的变量,也属于全局变量。例如:
正常的声明变量 var num1 = 10;这个在函数中声明,就是局部变量。
如果直接写 num2 = 20; 那么num2就是一个全局变量了。(但是这种情况要避免使用。以免混淆)

预解析

js引擎运行js代码分为两步:先预解析,再执行代码。


例如:

console.log(num);//undefined 
var num = 10;
//相当于执行了以下代码,先预解析,再执行:
var num;
console.log(num);
num = 10;
fun();//报错
var fun = function() {
	console.log(22);
}
//相当于执行了以下代码
var fun;
fun();
fun = function() {
	console.log(22);
}

案例1:结果是几?

//案例1
var num = 10;
fun();
function fun() {
	console.log(num);
	var num = 20;
}
------------------
预解析:

var num = 10;

function fun() {var  num;

​    console.log(num);

​      num = 20;         

}

fun();

//最后输出是 defined;
//案例2:结果是几?
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
	var a=b=c=9;
	console.log(a);
	console.log(b);
	console.log(c);
}
--------预解析小知识点----------
var a=b=c=9;
//相当于 var a = 9;
			b = 9;
			c = 9;
	b和c直接赋值,没有var声明。所以b和c是全局变量。
	而a有var声明,所以是函数内的局部变量。
如果改成var a = 9, b = 9, c = 9;那么,a b c都被var声明了,就都是函数内的局部变量。这种声明方式叫集体声明。

对象Object:万物皆对象

对象必须是一个具体的事物。比如明星不是对象,而具体的明星迪丽热巴就是一个对象。

什么是对象

为什么需要对象

保存一个值时,可以使用变量,保存多个值(一组值)时,可以使用数组。如果保存一个人的完整信息呢?例如,将张三疯的个人信息保存在数组中的方式为:
var arr = ['张三疯', '男', 128, 154];

里面的值分别代表什么呢?数组可以存储值,但是不能完整的把意思表达清楚。
而JS中的对象表达结构更清晰,更强大。张三疯的个人信息在对象中的表达结构如下:

创建对象的三种方式

在JS中,现阶段外面可以采用三种方式创建对象: 1,**利用字面量创建对象**
var obj = {};//这样就创建了一个空对象
//像不像数组的字面量创建方式:var arr = [];
var obj = {
	uname: '张三疯',
	age: 18,
	sex: '男',
	sayHi: function() {
		console.log('hi~');
	}
}
//对象创建好了,怎么使用呢?
//(1)调用对象的属性 对象名.属性名。如:
console.log(obj.uname);
//(2)调用方法2: 对象名['属性名']
console.log(obj['age']);
//(3)调用对象的函数sayHi 对象名.方法名() 
//千万不要忘记小括号
obj.sayHi();

如上,uname这些属性后面需要加逗号,同理,sayHi函数如果后面还有函数,这个函数写完后,仍然需要加逗号,和下一个函数隔开。(是不是很像数组存储值的方式??)
2,利用new Object创建对象

var obj = new Object();//创建了一个空对象
obj.uname = '张三疯';
obj.age = 18;
obj.sex = '男';
obj.sayHi = function() {
	console.log('hi~');
}
//外面是利用等号 = 赋值的方法,添加对象的属性和函数
//每个属性和方法之间用分号结束;

3,利用构造函数创建对象

为什么需要使用构造函数?

前面的两种创建对象方式 依次只能创建一个对象。每次创建一个对象后,对象之间有很多的属性和方法是相同的。只能一直复制。 所以可以利用函数的方法,重复这些相同的代码,这样的函数就叫 构造函数

构造函数和普通函数不一样的是,它里面封装的是对象,而非普通的可重复代码。

构造函数 就是把对象里面一些相同的属性和方法抽象出来 封装到函数里。


构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与new运算符一起使用。我们可以把对象中的一些公共的属性和函数抽取出来,然后封装到这个函数里面。
//利用构造函数创建对象
//我们想要创建四大天王的对象 相同的属性有:名字 年龄 性别 
//相同的方法有: 唱歌
//构造函数的语法格式:
function 构造函数名() {
	this.属性 = 值;
	this.方法 = function() {}
}
new 构造函数名();
-----------开始创建对象--------
function Star(uname, age, sex) {
	this.name = uname;
	this.age = age;
	this.sex = sex;
	this.sing = function(sang) {
		console.log(songs);
	}
}
var ldh = new Star('刘德华', 18,);//调用函数返回的是一个对象
//console.log(typeof ldh);
console.log(ldh.name);
console.log(ldh['sex'];
ldh.sing('冰雨');
-------------------
var zxy = new Star('张学友', 19, '男');
console.log(zxy.name);
console.log(zxy.age);
zxy.sing('吻别');

注意:
1,构造函数名字首字母要大写。
2,我们构造函数不需要return,就可以返回结果。
3,我们调用构造函数,必须用new
4,我们只要new Star() 调用函数就创建一个对象。如ldh {}
5,我们的属性和方法前面必须添加this 。
为啥要用this. 因为对象一定是具体的事物,name不是具体事物,加个this. 就是特指这个名字,就是具体的对象了。

for in 遍历对象

//遍历对象的格式
for(变量 in 对象) {

}
------------应用举例------------
for(var k in obj) {
	console.log(k);//k变量输出,得到的是属性名
	console.log(obj[k]);//obj[k]得到的是 属性值
}

内置对象

前面讲过内置数组arguments 。 简单点说,内置对象就是自带的功能,不需要再写程序,就可以直接拿来用的。


内置对象可以在MDN上查文档,了解内置对象及其用法。

内置对象:Math对象

取两个数之间的随机整数,并且包含这两个整数:
function getRandom(min, max) {return Math.floor(Math.random()*(max-min + 1))+ min);

}

console.log(getRandom(1, 10));

内置对象:Date对象

因为Date是构造函数(因为这个函数名的首字母是大写的,所以是构造函数),必须用new之后才能使用。
//Date()日期对象。 是一个构造函数。
//必须使用new 来调用创建我们的日期对象
var arr = new Array();//创建要给数组对象
var obj = new Object();//创建一个对象实例
//1,使用Date 如果没有参数,返回所用电脑设备的当前时间
var date = new Date();
console.log(date);

var date1 = new Date(2019,10,1);
console.log(date1);//返回的是11月,不是10月,有点特殊
var date2 = new Date('2019-10-1 8:8:8');
console.log(date2);

日期格式化

我们想要2019-8-8 8:8:8格式的日期,要怎么办呢?

需要获取日期指定的部分,所以我们要手动得到这种格式。

方法名 说明 代码
getFullYear() 获取当年 dObj.getFullYear()
getMonth() 获取党羽(0-11) dObj.getMonth()
getDate() 获取当天 dObj. getDate()
getDay() 获取星期几(周日0到周六6) dObj.getDay()
getHours() 获取当前小时 dObj.getHours()
getMinutes() 获取当前分钟 dObj. getMinutes()
getSeconds() 获取当前秒数 dObj.getSeconds()
//格式化日期 年月日
var date = new Date();
console.log(date.getFullYear());//输出当前的年份 2020
console.log(date.getMonth() + 1);//输出当前月份 
//getMonth给的年份比实际年份小1个月 记得月份+1哦
console.log(date.getDate());//输出当前是几号
console.log(date.getDay());//当前是周五,输出值是5
//周日对应0 周一对应1 ...周六对应6
------------------------
//案例:写一个输出值为2020年4月24日 星期五
var year = date.getFullYear();
var month = date.getMonth() + 1;
var dates = date.getDate();
var arr = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
var day = date.getDay();
console.log('今天是' + year + '年' + month + '月' + dates + '日' + arr[day]);
//格式化 时分秒
var date = new Date();
console.log(date.getHours());//时
console.log(date.getMinutes());//分
console.log(date.getSeconds());//秒
//案例:封装一个函数 输出当前的时分秒 格式08:08:08
function getTimer() {
	var time = new Date();
	var h = time.getHours();
	h = h < 10 ? '0' + h : h;
	var m = time.getMinutes();
	m = m < 10 ? '0' + m : m;
	var s = time.getSeconds();
	s = s < 10 ? '0' + s : s;
	return h + ':' + m + ':' + s;
}
console.log(getTimer());
//获得Date总的毫秒数 不是当前时间的毫秒数 
//而是距离1970年1月1号过了多少毫秒
//1,通过valueOf() getTime()
var date = new Date();
console.log(date.valueOf());
//就是我们当前时间 距离1970.1.1 总的毫秒数
console.log(getTime());
//2,简单的写法(最常用的写法)
var date1 = +new Date();
//+new Date() 返回的就是总的毫秒数
console.log(date1);
//3,H5新增的 获得总的毫秒数
console.log(Date.now());

京东活动倒计时案例


Array对象

//创建数组的两种方式
//1,数组字面量创建
var arr = [];//创建了一个空数组
var arr1 = [1,2,3];//创建时可以直接赋值。
console.log(arr[0]);
//1,new Array() 和创建对象很像
var arr2 = new Array();//创建了一个空数组
var arr3 = new Array(2);//创建了一个数组长度为2的数组
//也就是说,里面有2个数组元素
var arr3 = new Array(2,3);
//等价于[2,3] 这样写表示 里面有2个数组元素,是2和3
console.log(arr3);

怎么检测是否为数组

方法1,instance of arr

方法2: Array.isArray(arr)

添加/ 删除数组元素的方法

方法名 说明 返回值
push(参数1…) 末尾添加一个或多个元素,会修改原数组 并返回新的长度
pop() 删除数组最后一个元素,把数组长度减1,无参数、会修改原数组 返回它删除的元素的值
unshift(参数1…) 向数组的开头添加一个或更多元素,会修改原数组 并返回新的长度
shift() 删除数组的第一个元素,数组长度减1 ,无参数、会修改原数组 并返回第一个元素的值
//添加 删除数组元素的方法
//1,push() 在数组的末尾 添加一个或者多个数组元素
var arr = [1,2,3];
console.log(arr.push(4,'pink'));//5
console.log(arr);//[1, 2, 3, 4, "pink"];
------------------
//2,unshift()在数组开头添加一个或者多个数组元素
console.log(arr.unshift('red', 'purple'));//7
console.log(arr);//["red", "purple", 1, 2, 3, 4, "pink"]
------------------
//3,pop()它可以删除数组的最后一个元素
console.log(arr.pop());//pink
console.log(arr);//["red", "purple", 1, 2, 3, 4]
-------------------
//4,shift()它可以删除数组的第一个元素
console.log(arr.shift());//red
console.log(arr);//["purple", 1, 2, 3, 4]

数组排序

方法名 说明 是否修改原数组
reverse() 反转数组中元素的顺序,无参数 会改变原来的数组,返回新数组
sort() 对数组的元素进行排序 会改变原来的数组,返回新数组
//1,翻转数组
var arr = [1,2,3,4];
console.log(arr.reverse());//[4, 3, 2, 1]
console.log(arr);//[4, 3, 2, 1]
//2,数组排序(冒泡排序)
var arr1 = [13,4,77,1,7];
arr1.sort(function(a,b) {
	//return a - b;让数组按照升序的顺序排序
	return b - a;//让数组按照降序的顺序排序
});
console.log(arr1);//[77, 13, 7, 4, 1]

返回数组元素索引号的方法

//用 indexOf(数组元素) 
//意思是返回该数组元素的索引号 从前往后查找
//它只返回第一个满足条件的索引号
//它如果在该数组里面找不到该数组元素,则返回 -1
var arr = [1,3,4,1,9];
console.log(arr.indexOf(1));//0

//封装一个去重的函数unique 独一无二的
//var arr = ['c','a','z','a','x','a','x','c','b'];
function unique(arr) {
	var arr1 = [];
	for(var i = 0; i < arr.length; i++) {
		if(arr1.indexOf(arr[i]) === -1) {
			arr1.push(arr[i]);
		}
	}
	return arr1;
}
var demo = unique(['c','a','z','a','x','a','x','c','b']);
console.log(demo);//["c", "a", "z", "x", "b"]

数组转换为字符串

方法名 说明 返回值
toString() 把数组转换成字符串,每项中间用逗号隔开 返回一个字符串
join(‘分隔符’) 把数组转换成字符串,并且改变每个字符间的分隔符号 返回一个字符串
//1,toString() 将我们的数组转换为字符串
var arr = [1,2,3];
console.log(arr.toString());//1,2,3
//2,join('分隔符')
console.log(arr.join());//1,2,3
console.log(arr.join('-'));//1-2-3
console.log(arr.join('&'));//1&2&3

连接 截图 删除 数组元素

方法名 说明 返回值
concat() 连接两个或多个数组arr1.concat(arr2),不影响原数组 返回连接后的新数组
slice() 数组截取slice(begin的索引号, end的索引号) ,这里的索引号包含左不包含右 返回被截取元素组成的新数组,不会影响原数组
splice() 指定删除数组的某些元素splice(第几个索引号开始,要删除几个)。同时还可以向新数组里添加新的元素,splice(第几个索引号开始,要删除几个,要添加的元素) 返回被删除项目的新数组,会影响原数组
//1,concat()
var arr = [1,2,3,4,5];
var arr1 = [6,7];
console.log(arr.concat(arr1));//[1, 2, 3, 4, 5, 6, 7]
console.log(arr.slice(0,2));//[1, 2]
console.log(arr.splice(2,2));//[3, 4]
console.log(arr);//[1, 2, 5]
var arr1 = [5,6,7,8,9];
arr1.splice(2,0,10);
document.write(arr1);//5,6,10,7,8,9
console.log(arr1);//[5, 6, 10, 7, 8, 9]

字符串对象

基本包装类型

字符串的不可变

指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。
var str = 'abc';
str = 'hello';
//当重新给str赋值的时候,常量'abc‘不会被改变,依然在内存中
//重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变
//由于字符串的不可变,在大量拼接字符串的时候会有效率问题
var str = '';
for(var i = 0; i < 10000; i++;) {
	str += i;
}
console.log(str);
//这个结果需要花费大量时间来显示,因为需要不断的开辟新的空间
//字符串对象 根据字符返回位置 str.indexOf('要查找的字符', [起始的索引号位置])
var str = '改革春风吹满地,春天来了';
console.log(str.indexOf('春');//不写起始位置,默认从头开始查找
console.log(str.indexOf('春', 3));
//从索引号是3的位置开始往后查找

indexOf()案例

var str = 'oabcoefoxyozzopp';
var index = str.indexOf('o');//第一个'o'出现的位置
var num = 0;
while(index !== -1) {
	//console.log(index);
	document.write(index);
	num++;
	index = str.indexOf('o', index + 1);
}
//console.log('o出现的次数是:' + num);
document.write('o出现的次数是:' + num);

根据位置返回字符(重点)

方法名 说明 使用说明和举例
charAt(index) 返回指定位置的字符(index是字符串的索引号) str.charAt(0)就是返回str字符串索引号为0的字符
charCodeAt(index) 返回指定位置的字符的ASCII码(index是索引号) str.charCodeAt(0)
str[index] 获取指定位置的字符 HTML5,IE8+支持,和charAt()等效

案例:返回字符位置

判断一个字符串'abcoefoxyxzzopp'中出现次数最多的字符,并统计其次数。

核心算法
1,利用charAt()遍历整个字符串
2,把字符串里面的每个字符,都存储给对象。如果该对象没有属性(即这个字符在对象里存储的次数为0),那么次数就赋值为1,如果这个字符在对象里已经存储了,就让存储次数自增1
3,遍历这个对象,得到最大值和该字符

var str = 'avcoefoxyozzopp';
var o = {};//创建一个空对象o
//遍历字符串
for(var i = 0; i < str.length; i++) {
	//chars 是字符串里的每一个字符
	var chars = str.charAt(i);
	if(o[chars]) {//如果o对象里还没有存储这个chars属性(即字符)
		o[chars]++;//那么这个chars字符存储的字数就自增1
	} else {
		//这个字符已经在o对象里还没有存储,那就让存储的次数等于1
		o[chars] = 1;
	}
}
console.log(o);//Object {a:1 c:1 e:1 f:1 o:4 p:2 v:1 x:1 y:1 z:2}
//现在每个字符都在o对象里存储了,开始遍历o对象
var max = 0;
var ch = '';
for(var k in o) {
	//k是属性名(即存储的字符)
	//0[k]就是属性值,即该字符在o对象里存储的次数
	if (o[k] > max) {
		max = o[k];//把存储的次数赋值给max
		ch = k;//把存储的字符赋值给ch
	}
}
console.log(max);//输出次数 4
console.log(ch);//输出该次数最多的字符 o
//

字符串的操作方法(重点)

方法名 说明
str1.concat(str2) concat()方法用于连接两个或多个字符串。拼接字符串,等效于 + ,但是 + 拼接法更常用
substr(start, length) 从start(索引号)位置开始,length取的个数,重点记住这个
slice(start, end) 从start位置开始,截图到end位置,不包含end 。这里的开始和结束都是索引号
substring(start, end) 从start位置开始,截取到end位置,不包含end 。基本和slice相同,但是开始和结束位置不能是负数
//字符串操作方法
//1,concat(str1,str2,str3…)
var str1 = 'i';
var str2 = ' love';
console.log(str1.concat(str2));// i love
//2,substr(start, length)
var str = "hello";
console.log(str.substr(2,2));// ll

简单类型和复杂类型

简单类型又叫基本数据类型或者值类型,复杂类型又叫做引用类型。

值类型:简单数据类型 / 基本数据类型, 在存储时变量中存储的是值本身,因此叫做值类型。
如,string , number , boolean , undefined , null

但是null比较特殊。 null类型返回的是一个空对象。

var timer = null;
console.log(typeof timer);// object

引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型。
通过new关键字创建的对象,如Object,Array,Date等,都是引用类型。

堆和栈(了解)

简单类型传参

函数的形参也可以看作是一个变量,当我们把一个值类型作为参数传给函数的形参时,其实是把变量在栈空间的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到它的外部变量。

通俗的讲,就是形参就是一个可以改变的参数,不管怎么改,在传来实参的时候,都不影响函数的调用。

function fn(a) {
	a++;
	console.log(a);
}
var x = 10;
fn(x);
console.log(x);

复杂类型(引用类型)传参

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

学到这里。js的第一部分 即 ECMAScript就学完了。
-------------------------------------------------

Web APIs 的学习:即 DOM 和BOM

web apis 和 js 的基础关联性

js基础阶段以及web apis阶段


JS 基础学习 ECMAScript 基础语法为后面做铺垫,Web APIs 是 JS 的应用,大量使用 JS基础语法做交互效果。

API 和 Web API

API:应用程序接口

Web API:浏览器提供的应用程序接口

DOM(文档对象模型)

DOM是什么?


DOM树

  • 文档:一个页面就是一个文档,DOM中使用document表示。
  • 元素:页面中的所有标签都是元素,DOM中使用element表示。
  • 节点: 网页中的所有内容都是节点(标签、属性、文本、注释、空格等),DOM中使用node表示。
    DOM把以上所有内容都看作是对象

DOM如何获取元素

DOM如何获取页面元素

  • 根据ID获取 document.getElementById()
  • 根据标签名获取 document.getElementByTagName()
  • 通过HTML5新增的方法获取
  • 特殊元素获取

根据ID获取

使用 getElementById() 方法可以获取带有ID元素的对象。
<body>
	<div id="time">2019-9-9</div>
	<script>
		//1,因为我们文档页面是从上往下加载,所以先得有标签,所以我们的script写到标签的下面。
		//2,get获得element 元素 by 通过 驼峰命名法
		//3,参数 id 是大小写敏感的字符串
		//4,返回的是一个元素对象
		var timer = document.getElementById('time');
		console.log(timer);
		console.log(typeof timer)//5,console.dir 打印我们返回的元素对象,更好的查看里面的属性和方法
		console.dir(timer);
	</script>
</body>

根据标签名获取

使用document.getElementByTagName()方法可以获取带有指定 标签名,对象的集合。 使用语法: document.getElementByTagName('标签名');

注:这里不一定要用document,还可以用标签名或ID等元素。可以获取某个标签里面的一些标签。 如果是获取了多个元素,Element要加s 。
<body>
	<ul>
		<li>2333</li>
		<li>2333</li>
		<li>2333</li>
		<li>2333</li>
	</ul>
	<ul id="nav">
		<li>666</li>
		<li>666</li>
		<li>666</li>
		<li>666</li>
	</ul>
	<script>
		//1,返回的是 获取过来的元素对象集合 以伪数组的形式存储的
		var lis = document.getElementsByTagName('li');
		console.log(lis);
		console.log(lis[0]);
		//2,我们想要依次打印里面的元素,我们可以采取遍历的方式
		for(var i = 0; i < lis.length; i++) {
			console.log(lis[i]);
		}
		//3,element.getElementsByTagName() 可以得到这个元素里面的某些标签
		var nav = document.getElement('nav');
		var navLis = nav.getElementByTagName('li');
		console.log(navLis);
	</script>
</body>

通过HTML5新增的方法获取元素

根据类名来获取。

但是要注意,这个方法值支持ie9以上的浏览器版本。
  1. document.getElementsByClassName(‘类名’);
  2. document.querySelector( ’ 选择器 ’ );
  3. document.querySelectorAll(‘选择器’);

第2个和第3个获取元素方式,选择器必须带符号。类的选择器就加’ . ',ID选择器就加个#

获取特殊元素(body , html )

  1. 获取body元素
    document.body //返回body元素对象
  2. 获取html元素
    document.html // 返回html元素对象

事件基础

1. 谁发生 2. 怎么发生 3. 发生什么
<body>
	<button id="btn">唐伯虎</button>
	<script>
		//点击一个按钮,弹出对话框
		//1,事件是由三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素
		//(1)事件源 就是 谁发生 --按钮
		//谁发生就把谁获取过来,先获取再操作
		var btn = document.getElementById('btn');
		//(2)事件类型 怎么发生 比如鼠标点击
		//(3)事件处理程序 发生什么 
		//通过一个函数赋值的方式完成,发生的内容都在函数里
		btn.onclick = funtion() {
			alert('点秋香');
		}
		//谁发生 btn
		//怎么发生 onclick
		//发生什么 alert
	</script>
</body>

常见的鼠标事件(怎么发生)

鼠标事件 触发条件
onclick 鼠标点击左键触发
ondbclick 鼠标双击触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发
oncontextmenu 禁用右键菜单
onselectstart 禁止选中文字

mouseenter 和 mouseover 的区别

mouseenter不会冒泡。


可以这样理解:


mouseout和mouseleave的区别

二者都是鼠标移出。mouseout冒泡。 mouseleave不冒泡。(出去冒泡,离开不冒泡)

mouseout对应上面的mouseover ,mouseleave对应上面的mouseenter。

注册事件的第二种方法(监听法)

就是谁发生、怎么发生、发生了什么 的第二种表达方式。
谁发生.addEventListener(怎么发生,发生了什么的函数)
  • 怎么发生:这里的触发事件不带on,比如click
  • 发什么了什么的函数: function() { 要发生的事情 };
//例如上面的唐伯虎点秋香例子
btn.addEventListener('click', function() {
	alert('点秋香');
})

节点操作01

  • 改变元素内容

element.innerText
//从起始位置到终止位置的内容。但它去除html标签,同时空格和换行也会去掉
element.innerHTML
//起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行
innerText 和 innerHTML的区别
  1. innerText 不识别html标签 非标准 去除空格和换行
  2. innerHTML 识别html标签 按照W3C标准 保留空格和换行
  3. 这两个属性都是可读写的,可以获取元素里面的内容。例如:
<p>2333</p>
<script>
	var p = document.getElementByTagName('p');
	console.log(p.innerText);
	console.log(p.innerHTML);
</script>

常见元素的属性操作

三种操作情况:
  1. innerText 、innerHTML 改变元素内容
  2. src、 href
  3. id、alt、title

表单元素的属性操作

利用DOM可以操作如下表单元素的属性:

type , value , checked , selected , disabled

<body>
	<button>按钮</button>
	<input type="text" value="输入内容" />
	<script>
		//1,获取元素
		var btn = document.querySelector('button');
		var inp = document.querySelector('input');
		//2,注册事件--谁发生 怎么发生 发生什么
		btn.addEventListener('click', function() {
		//inp.innerHTML = '被点击了'; 这个是 普通盒子 比如div标签里面的内容被修改,不是value里的内容被改变
		//表单里面的值 文字内容是通过valve来修改的
			inp.value = '我被点击了';
		//如果想要某个表单被禁用,不能重复点击disabled 我们想要这个按钮 button禁用
		//btn.disbled = true; 这样就被禁用了
		this.disabled = true;//这里的this就是btn,因为是btn发生的,这里的this就特指btn了。
		//this指向的是发生的那个元素 btn
		})
	</script>
</body>

案例:京东登陆界面的密码表单
输入密码时,默认不显示密码。点击小眼睛图标时,显示密码。再点击又不显示密码。

//2,注册事件 谁发生 怎么发生 发生什么
var flag = 0;
eye.addEventListener('click', function() {
	//每次点击 flag一定要变化
	if(flag == 0) {
		pwd.type = 'text';
		eye.src = '---';
		flag = 1;//这里就是要变化了。原来是0,这里就要变成1
	} else {
			pwd.type = 'password';
			eye.src = '---';
			flag = 0;//这里又变化了。原来是1,点过一次就变成0了
		}
})

样式属性操作

我们可以通过JS修改元素的大小、颜色、位置等样式。
  1. element.style = ’ ';行内样式操作
  2. element.className 类名样式操作

注意

  1. JS 里面的样式采取驼峰命名法 比如 fontSize , backgroundColor 。注意,这里没有连接的 - 了。
  2. JS修改style 样式操作,产生的是行内样式,css权重比较高。
  3. className 会直接更改元素的类名,会覆盖原先的类名。

第3条里,如果原来的类名还想保留,那就可以这样做,假如原来的类名是class=‘first’ ,现在要用的是class='change’并且不想把原来的first类型替换掉,那就写成 元素.className = ‘first change’ 就阔以了。

<body>
	<div></div>
	<script>
		//1,获取元素
		var div = document.querySelector('div');
		//2,注册事件。谁发生 怎么发生 发生什么
		div.onclick = function() {
			//div.style里面的属性 采取驼峰命名法
			this.style.backgroundColor = 'purple';
			this.style.width = '200px';
		}
	</script>
</body>

这里是this是指向函数的调用者,即div在调用这个函数。 相当于div.style (如上图的div)

如果调用者不是当前的元素,就不能用this了。(如下图function里的box.style 就不能写成this.style)

因为是btn在调用函数,然后让box产生变化。 如果用了this,就是指btn在发生变化了。所以这里不能用this。

当一个元素需要更改的样式较多时,适合用element.className来完成。
<head>
<style>
.change {
	background-color: purple;
	color: #fff;
	font-size: 25px;
	margin-top: 100px;
}
</style>
</head>

<body>
	<div>文本</div>
	<script>
		//当元素样式较多或者功能复杂的情况下,
		//使用element.className获得修改元素样式,
		var div = document.querySelector('div');
		div.onclick = function() {
			this.className = 'change';
		}
	</script>
</body>

JS排他思想


如果有同一组元素,我们想要其中一个元素实现某种样式的情况下,不想让其他同样的元素跟着实现这种样式,就需要用到循环的排他思想算法:

  1. 所有元素全部清除样式(干掉其他人)
  2. 给当前元素设置样式(留下我自己)
  3. 注意顺序不能颠倒。首先干掉其他人,再设置自己。
<ul class='baidu'>
	<li><img src='1' /></li>
	<li><img src='1' /></li>
	<li><img src='1' /></li>
</ul>
<script>
	//1,获取元素 
	var imgs = document.querySelector('.baidu').querySelectorAll('img');
	//console.log(imgs);
	//2,循环注册事件
	for(var i = 0; i < imgs.length; i++) {
		imgs[i].onclick = function() {
		//this.src 就是我们点击的图片的路径
		//console.log(this.src);
		//把这个路径this.src给body就可以了
			document.body.style.backgroundImage = 'url(' + this.src + ')';
		}
	}
</script>

说白了,就是先让包括自己的所有人都不显示,然后再让自己显示。 这样在自己显示的时候,别人就不显示了。

全选反选案例

<script>
	//1,全选和取消全选的做法: 
	//让下面所有复选框的checked属性(选中状态) 跟随 全选按钮即可
	//获取元素
	var j_acAll = document.getElementById('j_cbAll');
	var j_tbs = document.getElementById('j_tb').getElementByTagName('input');
	//即 选出下面所有的复选框
	//注册时间 谁发生 怎么发生 发生什么
	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;
		}
	}
	//2,下面的复选框需要全部选中,上面全选才能选中做法:
	//给下面所有复选框绑定点击事件,每次点击,都要循环看是否都选中了
	for(var i = 0; i < j_tbs.length; i++) {
		j_tbs[i].onclick = function() {
			//flag控制全选按钮是否选中
			var flag = true;
			//每次点击下面的复选框都要循环检查这4个小按钮是否全被选中
			for(var i = 0; i < j_tbs.length; i++) {
				if( !j_tbs[i].checked) {
					flag = false;
					break;
				//退出for循环 这样可以提高运行效率
				//因为只要一个没有选中,剩下的就无需再循环判断了
				}
			}
			j_cbAll.checked = flag;
		}
	}
</script>
//每次点击,都要循环

操作属性

自定义属性的操作

获取属性值
  • element.属性 获取属性值

    作用:获取内置属性值,即元素本身自带的属性

  • element.getAttribute(‘属性’);

    作用:可以获得原有属性值,也可以获得自定义的元素值。主要获取自定义的属性 (标准) 我们程序员自定义的属性。

获取、设置、移除元素属性的应用例子:

<body>
	<div id="demo" index="1"></div>
	<script>
		var div = document.querySelector('div');
		//1,获取元素的属性值
		//(1)element.属性
		console.log(div.id);//demo
		//(2)element.getAttribute('属性')
		//程序员自己添加的属性,我们称为自定义属性,比如这里的 index
		console.log(div.getAttribute('id'));//demo
		console.log(div.getAttribute('index'));//1
		//2,设置元素的属性值
		//(1)element.属性 = ‘值’;
		div.id = 'test';
		div.className = 'navs';
		//(2)element.setAttribute('属性','值');
		//主要针对自定义属性
		div.setAttribute('index', 2);
		div.setAttribute('class', 'footer');
		//class特殊 这里写的就是class 不是className
		//3,移除属性 element.removeAttribute('属性');
		div.removeAttribute('index');
	</script>
</body>

属性操作案例(必须会写)


<script>
	//获取元素
	var 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设置索引号index
		lis[i].setAttribute('index',i);
		lis[i].onclick = function() {
			//1,上面的模块选项卡,点击某一个,当前这个底色会是红色,其他选项卡不变色。
			//所以用到排他思想。干掉所有人,其余的li清除class这个类
			for(var i = 0; i < lis.length; i++) {         		
				lis[i].className = '';		
			}
			//留下我自己
			this.className = 'current';
			//2,下面的显示内容模块
			var index = this.getAttribute('index');
			console.log(index);
			//干掉所有人 让其余的item 这些div 隐藏
			for(var i = 0; i < items.length; i++) {
				items[i].style.display = 'none';
			}
			//留下我自己 让对应的item显示出来
			items[index].style.display = 'block';
		}
	}
</script>

关于自定义属性

H5自定义属性

自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
  1. 设置H5自定义属性

    H5规定自定义属性data- 开头做为属性名并且赋值。说白了就是,自定义属性要用data- 做开头。比如:

<div data-index="1"></div>

或者使用JS设置:

element.setAttribute('data-index', 2)
  1. 获取H5自定义属性

    1,element.getAttribute(‘data-index’) 兼容性好
    2,H5新增 element.dataset.index 或者element.dataset[‘index’] , ie11才开始支持,而且只能取data- 开头的自定义元素属性。
    如果自定义属性里有多个 - 连接的单词,我们获取的时候,采取驼峰命名法。如 div.dataset.listName 或 div.dataset[‘listName’]

节点操作02

网页中的所有内容都是节点(标签,属性,文本,注释,空格等),在DOM中,节点使用node来表示。

HTML DOM树中的所有节点均可通过JS进行访问,所有HTML元素(节点)均可被修改,也可以创建或删除。

一般地,节点至少拥有nodeType(节点类型),nodeName(节点名称)和nodeValue(节点值)这三个基本属性。

  • 元素节点 nodeType 为1
  • 属性节点 nodeType 为2
  • 文本节点 nodeType 为3(文本节点包含文字,空格,换行等)
    我们实际开发中,节点操作主要操作的是元素节点

节点层级

利用DOM树可以把节点划分为不同的层级关系,常见的是 父子兄弟层级关系

1,父级节点

node.parentNode
  • parentNode属性可返回某节点的父节点,注意是最近的一个父节点(亲爸爸)
  • 如果指定的节点没有父节点,则返回null。
<div class="demo">
	<div class="box">
		<span class="erweima">X</span>
	</div>
</div>

<script>
	//1,父节点parentNode
	var erweima = document.querySelector('.erweima');
	//var box = document.querySelector('.box');
	//得到的是离元素最近的父级节点(亲爸爸)
	//如果找不到父节点,就返回null
	console.log(erweima.parentNode);
</script>

2,子节点

有两种获得方式,标准和非标准。
第一种: parentNode.childNodes(标准)
//虽然是标准的,但是不提倡使用

parentNode.childNodes 返回包含指定节点的子节点的集合。该集合为即时更新的集合。

注意:返回值里面包含了所有的子节点,包括元素节点,文本节点(文字,空格,换行等)等。

如果只想要获得里面的元素节点,则需要专门处理。所以我们**一般不提倡使用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是一个只读属性,返回所有子元素节点,其余节点不返回。所以重点掌握这个方法。

获取 第一个子元素和最后一个子元素

实际开发中,firstChild 和 lastChild 包含其他节点,操作不方便,而firstElementChild 和 lastElementChild又有兼容性问题。那么我们如何获取第一个子元素节点或最后一个子元素节点呢?

解决方案:

1.获取第一个子元素节点, parentNode.children[0];
2,获取最后一个子元素节点,
parentNode.children[parentNode.children.length - 1]
这样既可以获得想要的元素节点,又不存在兼容性问题。

节点操作案例:

<script>
	//1,获取元素
	var nav = document.querySelector('.nav');
	var lis = nav.children;//得到4个小li
	//2,注册循环事件 点谁谁发生
	for(var i = 0; i < lis.length; i++) {
		lis[i].onmouseover = function() {
			this.children[i].style.display = 'block';
		}
		lis[i].onmouseout = function() {
			this.children[i].style.display = 'none';
		}
	}
</script>

节点层级--兄弟节点

  1. node.nextSibling

    返回当前元素的下一个兄弟节点,找不到则返回null 。同样,也是包含所有的节点。

  2. node.previousSibling

    返回当前元素上一个兄弟节点,找不到则返回null。同样,也包含所有的节点。

  3. node.nextElementSibling

    返回当前元素下一个兄弟元素节点,找不到则返回null。

  4. node.previousElementSibling

    返回当前元素的上一个兄弟元素节点,找不到则返回null。


    1和2 取兄弟节点的时候,会把空格文本节点也取到。不适合用。

3和4取出来的确实是想要的兄弟节点,但是会有兼容性问题。

如何解决兼容性问题?
需要自己封装一个函数。

function getNextElementSibling(element) {
	var el = element;
	while(el == el.nextSibling) {
		if(el.nodeType === 1) {
			return el;
		}
	}
	return null;
}

不过兄弟节点用的较少。

创建元素节点

document.createElement('tagName');

创建 由tagName指定的HTML元素。因为这些元素原先不存在,是根据我们的需求 动态生成的,所以我们也称为动态创建元素节点

添加节点:先创建,后添加

  1. node.appendChild(child)

    将一个节点添加到指定父节点的子节点列表末尾。类似于css里面的after伪元素。node是父节点,child是子级。

  2. node.insertBefore(child,指定元素)

    将一个节点添加到父节点的指定子节点前面。类似于css里面的before伪元素。

<body>
	<ul>
		<li>2333</li>
	</ul>
	<script>
		//1,创建元素节点
		var li = document.createElement('li');
		//2,添加后节点 node.appendChild(child)
		var ul = document.querySelector('ul');
		ul.appendChild(li);
		//添加前节点 node.insertBefore(child,指定元素);
		var lili = document.creatrElement('li');
		ul.insertBefore(lili,ul.children[0]);
	</script>
</body>

发布留言板案例:


<body>
	<textarea name="" id=""></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.insertBefore(li,ul.children[0]);
				}
		}
	</script>
</body>

删除子节点

node.removeChild(child)
//举例:
ul.removeChild(ul.children[0]);

从DOM中删除一个子节点,返回删除的节点。

复制(克隆)节点:先克隆,再添加

node.cloneNode()
//返回调用该方法的节点的一个副本。
//这里的node是要被克隆的那个元素节点

注意:

  1. 如果括号参数为空或者false,则是浅克隆,即只克隆节点本身,不克隆里面的子节点。
  2. 如果括号里面的参数为true,则是深克隆,会复制节点本身以及里面所有的子节点。
<body>
	<ul>
		<li>1</li>
		<li>2</li>
		<li>3</li>
	</ul>
	<script>
		var ul = document.querySelector('ul');
		var liCopy = ul.children[0].cloneNode();
		ul.appendChild(liCopy);
	</script>
</body>

三种动态创建元素的区别

  • document.write()
  • element.innerHTML
  • document.createElement()
    区别:

  1. document.write()是直接将内容写入页面的内容流,但是文档流执行完毕,它会导致页面全部重绘。
  2. innerHTML是将内容写入某个DOM节点,不会导致页面全部重绘。
  3. innerHTML创建多个元素效率更高,不需要拼接字符串,采取数组形式拼接,结构稍微复杂。
  4. createElement()创建多个元素效率稍微低一点点,但是结构更清晰。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="uft-8" />
	</head>
	<body>
		<button>点击</button>
		<div class="inner"></div>
		<ul class="create"></ul>
		<script>
			//1,document.write()创建元素
				var btn = document.querySelector('button');
				btn.onclick = function() {
					document.write('<div>2333</div>');
				}
				//2,innerHTML 创建元素
				var inner = document.querySelector('.inner');
				var arr = [];
				for(var i = 0; i <= 10; i++) {
					arr.push('<a href="">233</a>');
				}
				inner.innerHTML = arr.join(' ');
				//3,document.createElement()创建元素
				var create = document.querySelector('.create');
				for (var i = 0; i <= 10; i++) {
					var li = document.createElement('li');
					create.appendChild(li);
				}
		</script>
	</body>
</html>

DOM事件流

事件流描述的是从页面中 接收事件的顺序

事件发生时,会在元素节点之间按照特定的顺序传播,这个传播过程就是DOM事件流。

  • 事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程。
  • 事件捕获:网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程。
    注意:
    1,JS代码中只能执行捕获或者冒泡其中的一个阶段。二者只能选其一。
    2,onclick和attachEvent只能得到冒泡阶段。
    3,addEventListener()中function()后面的参数,如果是true,表示在事件捕获阶段条用事件处理程序;如果是不写参数或者参数是false,表示在事件冒泡阶段调用事件处理程序。
    4,实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
    5,有些事件是没有冒泡的,比如 onblur,onfocus,onmouseenter,onmouseleave。

事件对象

什么是事件对象?
eventTarget.onclick = function(event) { };
或
eventTarget.addEventListener('click', function(event) { })
//这个event就是事件对象。可以写成e或者evt。
//这个参数在前面学习中是没有写出来的。

官方解释:event对象代表事件的状态,比如键盘按键的状态,鼠标的位置,鼠标按钮的状态。


简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象event,它有很多属性和方法。
比如:
1,谁绑定了这个事件。
2,鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置。
3,键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。
这个event是个形参,系统帮我们设定为事件对象,不需要传递实参过去。
当我们注册事件时,event对象就会被系统自动创建,并依次传递给事件监听器(即事件处理函数)。
兼容性问题

事件对象的兼容性方案

事件对象本身的获取存在兼容性问题:

1,标准浏览器中是浏览器给方法传递的参数,只需要定义形参3 就可以获得到。 2,在IE6~8中,浏览器不会给方法传递参数,如果需要的话,需要到window.event中获取查找。

解决:
e = e || window.event;

事件对象属性方法 说明
e.target 返回触发事件的对象 标准
e.srcElement 返回触发事件的对象 非标准 ie6-8使用
e.type 返回事件的类型 比如 click,mouseover 不带on
e.cancelBubble 该属性阻止冒泡 非标准 ie6-8使用
e.returnValue 该属性组织默认事件(默认行为) 非标准 ie6-8使用 比如不让链接跳转
e.preventDefault() 该方法组织默认事件(默认行为) 标准 比如不让链接跳转
e.stopPropagation() 阻止冒泡 标准

阻止事件冒泡的两种方式

事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点。

事件冒泡本身的特性,会带来坏处,也会带来好处,需要我们灵活掌握。

阻止事件冒泡

  • 标准写法:利用事件对象里面的e.stopPropagation()方法
  • 非标准写法:IE6-8使用。 利用事件对象cancelBubble属性。
    常用的是标准写法。IE浏览器因为兼容问题,不经常用。如果用了非标准写法,可以调试一下兼容性:
if(e && e.stopPropagation) {
	e.stopPropagation();
} else {
	window.event.cancelBubble = true;	
}

用法:

<body>
	<div class="father">
		<div class="son">son儿子</div>
	</div>
	<script>
		//常见事件对象的属性和方法
		//阻止冒泡 dom 推荐的标准 stopPropagation()
		var son = document.querySelector('.son');
		son.addEventListener('click', function(e) {
		alert('son');
		e.stopPropagation();//停止传播
		e.canselBubble = true;//非标准 取消泡泡
},false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
	alert('father');	
},false);
document.addEventListener('click', function() {
	alert('document');
}
	</script>
</body>

事件委托

事件委托也称为事件代理,在jQuery里面称为事件委派。

事件委托的原理

不是每个子节点单独设置事件监听器,而是事件监听器在其父节点上,然后利用冒泡原理影响设置每个子节点。

比如,给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器。

事件委托的作用

我们只操作了依次DOM,提高了程序的性能。
<body>
	<ul>
		<li>2333</li>
		<li>2333</li>
		<li>2333</li>
		<li>2333</li>
	</ul>
	<script>
		//事件委托的核心原理:给父节点添加监听器,
		//利用事件冒泡影响每一个子节点。
		var ul = document.querySelector('ul');
		ul.addEventListener('click', function(e) {
			//alert('2333');
			//e.target 可以得到我们点击的对象
			e.target.style.backgroundColor = 'pink';
		})
	</script>
</body>

鼠标事件对象

event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象mouseevent和键盘事件对象keyboardevent。
鼠标事件对象 说明
e.clientX 返回鼠标相对于浏览器窗口可视区的X坐标
e.clientY 返回鼠标相对于浏览器窗口可视区的Y坐标
e.pageX 返回鼠标相对于文档页面的X坐标 IE9+支持(常用
e.pageY 返回鼠标相对于文档页面的Y坐标 IE9+支持 (常用
e.screenX 返回鼠标相对于电脑屏幕的X坐标
e.screenY 返回鼠标相对于电脑屏幕的Y坐标


<style>
	img {
		position: absolute;
		top: 2px;
	}
</style>
<body>
	<img src=''>
	<script>
		var pic = document.querySelector('img');
		document.addEventListener('mousemove', function(e) {
		var x = e.pageX;
		var y = e.pageY;
		console.log(x, y);//输出x 和 y坐标
		//千万不要忘记给left和top添加px单位!
		pic.style.left = x + 'px';
		pic.style.top = y + 'px';
		});
	</script>
</body>

常用的键盘事件

键盘事件 触发条件
onkeyup 键盘上的某个按键被松开时触发
onkeydown 键盘上的某个按键被按下时触发
onkeypress 键盘上的某个按键被按下时触发,但是它不识别功能键 比如 ctrl shift 4个方向键等

注意:
1,如果使用addEventListener,就不需要加on
2,三个事件的执行顺序是: keydown-keypress-keyup

键盘事件对象

键盘事件对象 属性 说明
keyCode 返回该键的ASCII值

注意:onkeydown和onkeyup不区分字母大小写,onkeypress区分字母大小写。
在我们实际开发中,我们更多的使用keydown和keyup,它能识别所有的键(包括功能键)
Keypress不识别功能键,但是keyCode属性能区分大小写,返回不同的ASCII值。

注意:keydown和keyup在文本框里面的特点:他们两个事件触发的时候,文字还没有落入文本框中。keyup事件触发的时候,文字已经落入文本框里面了。因为键已经松开了。

案例:按下s键,搜索框获得焦点

<body>
	<input type="text">
	<script>
		//核心思路:检测用户是否按下了s键。
		//如果按下了s键,就把光标定位到搜索框里面。
		//使用键盘事件对象里面的keyCode,
		//判断用户按下的是否是s键。
		//搜索框获得焦点:使用js里面的focus()方法
		var sch = document.querySelector('input');
		document.addEventListener('keyup', function(e) {
			if(e.keyCode == 83) {
				sch.focus();
			}
		})
	</script>
</body>

--------------------DOM---end------------------------

BOM浏览器对象模型

什么是BOM?

BOM(Brower Object Model)即浏览器对象模型。它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window 。

BOM由一系列相关的对象构成,并且每个对象都提供了很多方法和属性。

BOM缺乏标准,JS语法的标准化阻止是ECMA,DOM的标准化组织是W3C,BOM最初是Netscape(就是网景公司)浏览器标准的一部分。

BOM构成
BOM比DOM更大,它包含DOM。

window对象是浏览器的顶级对象。它具有双重角色。
1,它是JS访问浏览器窗口的一个接口。
2,它是一个全局对象。定于在全局作用域中的变量和函数都会变成window对象的属性和方法。
在调用的时候可以省略window,前面学习的对话框都属于window对象方法,比如alert() ,prompt()等。
注意:window下的一个特殊属性 window.name

window对象的常用事件

窗口加载事件

这样就可以把js放在任何一个地方了,js代码都会执行了。
window.onload = function() { }
或者
window.addEventListener('load', function() { })(推荐使用,因为没有次数限制)

window.onload是窗口(页面)加载事件,当文档内容完全加载完成时会触发该事件(包括图像,脚本文件,css文件等),就会调用处理函数。
注意:
1,有了window.onload就阔以把JS代码写在页面元素的上方,因为onload是等页面内容全部加载完毕,再去执行处理函数的。
2,window.onload传统注册事件方式只能写一次,如果有多个,会以最后一个window.onload为准。
3,如果使用window.addEventListener则没有限制。
另一种情况:(加载较慢的情况)

document.addEventListener('DOMContenLoaded', function() { })

DOMContentLoaded事件触发时,仅当DOM加载完成时,不包括样式表,图片,flash等等。
IE9以上才支持。
如果页面的图片很多的话,从用户访问到onload触发可能需要较长的事件,交互效果就不能实现,必然影响用户的体验,此时用DOMContentLoaded事件比较合适。

调整窗口大小事件

window.onresize = function() {}
window.addEventListener('resize', function() {})

window.onresize是调整窗口大小加载事件,当触发时就调用的处理函数。
注意:
1,只要窗口大小发生像素变化,就会触发这个事件。
2,我们经常利用这个事件完成响应式布局。window.innerWidth是当前屏幕的宽度。

两种定时器

第一种定时器:setTimeout()定时器

window.setTimeout(调用函数,延迟的毫秒数);

setTimeout()方法用于设置一个定时器,该定时器在定时器到期后执行调用函数。
注意:
1,window可以省略。
2,这个调用函数可以直接写函数,或者写函数名, 或者 '函数名()'三种形式。但是不推荐最后一种写法。
3,延迟的毫秒数可以省略,默认是0,如果写,必须是毫秒数。不需要带单位。
4,因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。

//语法规范: window.setTimeout(调用函数,延迟时间);
//setTimeout(function() {
// console.log('午时已到');
//}, 2000);
function callback() {
	console.log('立即斩首');
}
setTimeout(callback, 3000);

回调函数 callback
window.setTimeout(调用函数,延迟的毫秒数);
setTimeout()这个调用函数,我们也称为回调函数callback
普通函数是按照代码顺序直接调用。
而这个函数,需要等待时间,时间到了才能取调用这个函数,因此我们称为回调函数。
简单理解:回调,就是回头调用的意思。上一件事干完,再回头调用这个函数。
以前讲的element.onclick = function() {}或者element.addEventListener(‘click’, fn);里面的函数也是回调函数。

停止定时器(让定时器停下来,别执行函数里的程序了)

clearTimeout(定时器名字);
window.clearTimeout(timeout ID)

注意:
1,window可以省略。
2,里面的参数就是定时器的标识符。

第二种定时器 setInterval()

window.setInterval(回调函数,间隔的毫秒数);

setInterval()方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。
这是与setTimeout()最大的不同。setTimeout()定时器只调用一次回调函数。
注意:
1,window可以省略。
2,这个调用函数可以直接写函数,或者函数名或者采用字符串 ’ 函数名() ’ 三种形式。
3,间隔的毫秒数可以省略,默认是0,如果写,必须是毫秒数,不用带单位。
4,因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。
案例:自动倒计时

<body>
	<div>
		<span class="hour">1</span>
		<span class="minute">2</span>
		<span class="second">3</span>
	</div>
	<script>
		//1,获取元素
		var hour = document.querySelector('.hour');
		var minute = document.querySelector('.minute');
		var second = document.querySelector('.second');
		var inputTime = +new Date('2019-5-1 18:00:00');//用户输入时间总的毫秒数
		countDown();//现调用一次函数,防止第一次刷新页面出现空白
		//2,开启定时器
		setInterval(countDown, 1000);
		function countDown() {
			var nowTime = +new Date();
			//返回的是当前时间总的毫秒数
			var times = (inputTime - nowTime) / 1000;
			//times是剩余需要倒计时的总的秒数
			var h = parseInt(times / 60 / 60 / % 24);//小时
			h = h < 10 ? '0' + h: h;
			//格式搞的好看一点
			hour.innerHTML = h ;
			//把倒计时的小时数给小时盒子
			var m = parseInt(times / 60 % 60);//分钟
			m = m < 10 ? '0' + m: m;
			minute.innerHTML = m;
			var s = parseInt(times % 60);//秒
			s = s < 10 ? '0' + s: s;
			second.innerHTML = s;
		}
	</script>
</body>

案例:发送短信验证

JS执行机制

JS是单线程:同一时间只做一件事。代码是从上到下一行一行的执行。

同步和异步: 最新的js可以创建多个任务了。

为了解决这个问题,利用多核CPU的计算能力,HTML5提出Web Worker 标准,允许JS脚本创建多个线程。于是,JS中 出现了同步和异步。

同步

前一个任务结束后再执行后一个任务,程序的执行顺序与任务排列顺序是一直的,同步的。比如做饭的同步做法:我们要烧水煮饭,等水开了(10分钟后),再去切菜,炒菜。

异步

在做一件事情时,因为这件事情会话费很长时间。在做这件事情的同时,还可以去处理其他事情。比如做饭的异步做法,在烧开水的同时,利用这10分钟,去切菜,炒菜。

同步任务

同步任务都在主线程上执行,形成一个执行线。

异步任务

JS的异步是通过回调函数实现的。 一般而言,异步任务有以下三种类型: 1,普通事件,如click,resize等 2,资源加载,如load,error等 3,定时器,包括setTimeout,setInterval等。

异步任务相关回调函数添加到任务队列中,任务队列也称为消息队列。

执行机制:任务分成同步任务和异步任务。先执行完同步任务,再去执行异步任务。

1,先执行 执行栈中的同步任务

2,异步任务(回调函数)放入任务队列中。

3,一旦执行栈中的所有同步任务执行完毕,系统就会按照次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。

由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环(event loop)

location对象

URL

统一资源定位符(Uniform Resource Locator,URL)是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

URL的一般语法格式为:
protocol://host[:port]/path/[?query]#fragment
如:
http://www.itcast.cn/index.html?name=andy&age=18#link
组成 说明
protocol 通信协议 常用的http, ftp, maito等
host 主机(即域名) 比如 www.itheima.com
port 端口号 可选, 省略时使用方案的默认端口 如http的默认端口为80
path 路径 由 零或多个’/'符号隔开的字符串,一般用来表示主机上的一个目录或文件地址
query 参数 以键值对的形式,通过&符号分隔开来
fragment 片段 #后面内容 常见于链接 锚点

location对象的属性

location对象的属性 返回值
location.href 获取或者设置 整个URL
location.host 返回主机(即域名)
location.port 返回端口号 如果未写 空字符串
location.pathname 返回路径
location.search 返回参数
location.hash 返回片段 #后面的内容 常见于链接 锚点

案例:获取URL参数数据:数据在不同网页中传递


第一个页面:输入信息的界面

<body>
	<form action="index.html">
		用户名:<input type="text" name="uname">
		<input type="submit" value="登录" />
	</form>
</body>

第二个页面:接收信息的界面

<body>
	<div></div>
	<script>
		console.log(location.search);//?uname=andy
		//1,先去掉? substr('起始位置', 截取几个字符);
		var params = location.search.substr(1);//uname=andy
		//2,利用 = 号把字符串分割为数组 split('=');
		var arr = params.split('=');
		console.log(arr);//["uname", "ANDY"]
		var div = document.querySelector('div');
		//3,把数据写入div中
		div.innerHTML = arr[1] + "欢迎您";
	</script>
</body>

location对象的方法

location对象的方法 返回值
location.assign() 跟href一样,可以跳转页面,也称为重定向页面
location.replace() 替换当前页面,因为不记录历史,所以不能后退页面
location.reload() 重新加载页面,相遇刷新按钮或者F5 如果参数为true 强制刷新 相当于ctrl + f5

navigator对象:知道用户用了什么浏览器

navigator对象包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent,该属性可以返回由客户机发送服务器的user-agent头部的值。

下面前端代码可以判断用户哪个中断打开的页面,实现跳转:

if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobild|BlackBerry|IEMobild|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) {
window.location.href = ""; //手机
} else {
	window.location.href = ""; //电脑
}
//把这个代码赋值到<script></script>里面就阔以了。
//要查哪个网页地址,就把地址补齐到href里。

window对象给我们提供了一个history对象,与浏览器历史纪录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL。

history对象的方法 作用
back() 可以实现后退功能
forward() 前进功能
go(参数) 前进后退功能 参数如果是1 前进1个页面 如果是-1 后退1个页面

history.back();
history.forward();
history.go(1);

PC网页端特效

知识点:
  1. offset
  2. client
  3. scroll
  4. 封装简单动画函数
  5. 网页轮播图

offset系列属性

offset翻译过来就是偏移量,我们使用offset系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
  • 获得元素举例带有定位父元素的位置
  • 获得元素自身的大小(宽度高度)
  • 注意:返回的数值都不带单位

offset系列常用属性:

offset系列属性 作用
element.offsetParent 返回作为该元素带有定位的父级元素,如果父级都没有定位 则返回body
element.offsetTop 返回元素相对带有定位父元素上方的偏移
element.offsetLeft 返回元素相对带有定位父元素左边框的偏移
element.offsetWidth 返回自身包括padding、边框、内容区的宽度,返回值不带单位
element.offsetHeight 返回自身包括padding、边框、内容区的高度,返回值不带单位

只有上和左,没有下和右。

offset和style的区别

案例:获取鼠标在盒子内的动态位置

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200427005033196.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3R1emkwMDdh,size_16,color_FFFFFF,t_70)

元素可视区client系列

client翻译过来就是客户端,我们使用client系列的相关属性来获取元素在可视区的相关信息。通过client系列的相关属性可以动态的得到该元素的边框大小、元素大小等。
client系列属性 作用
element.clientTop 返回元素上边看的大小
element.clientLeft 返回元素左边框的大小
element.clientWidth 返回自身包括padding、内容区的宽度,不含边框,返回值不带单位
element.clientHeight 返回自身包括padding、内容区的高度,不含边框,返回值不带单位

注意和offset的区别。clientWidth是不含边框的。

立即执行函数

<body>
	<script>
		//1,立即执行函数:不需要调用,立马能够子级执行的函数
		function fn() {
			console.log(1);
		}
		fn();
		//2,写法也可以传递参数进来
		//(function() {})()或者(function() {}())
		(function(a, b) {
			console.log(a + b);
			var num = 10;
		})(1, 2);//第二个小括号可以看作是调用函数
		(function sun(a, b) {
			console.log(a + b);
			var num = 10;//局部变量
		}(2, 3));
		//3,立即执行函数最大的作用就是 独立创建了一个作用域,
		//里面所有的变量都是局部变量,不会右命名冲突的情况。
	</script>
</body>

元素滚动scroll系列

scroll翻译过来就是滚动的,我们使用scroll系列的相关属性可以动态的得到该元素的大小、滚动距离等。
scroll系列属性 作用
element.scrollTop 返回被卷去的上侧距离,返回值不带单位
element.scrollLeft 返回被卷去的左侧距离,返回值不带单位
element.scrollWidth 返回自身实际的宽度,不含边框,返回值不带单位
element.scrollHeight 返回自身实际的高度,不含边框,返回值不带单位

常用的是 element.scrollTop和element.scrollLeft。

window.pageXOffset 和 window.pageYOffset属性,返回文档在窗口左上角水平和垂直方向滚动的像素。

pageXOffset设置或返回当前网页相对于窗口显示区左上角的X位置。pageYOffset设置或返回当前页面相对于窗口显示区左上角的Y位置。

pageXOffset 和pageYOffset属性相当于scrollX和scrollY属性。

这些属性是只读的。

页面被卷去 的头部兼容性解决方案

需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:
  1. 声明了DTD,使用document.documentElement.scrollTop
  2. 未声明DTD,使用document.body.scrollTop
  3. 新方法window.pageYOffset和window.pageXOffset , IE9开始支持。
function getScroll() {
	return {
	left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0,
	top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0,
	}
}
//使用的时候 
getScroll().left

动画函数封装

动画实现原理:

实现步骤:
  1. 获得盒子当前的位置
  2. 让盒子在当前位置加上1个移动距离
  3. 利用定时器不断重复这个操作
  4. 加一个结束定时器的条件
  5. 注意:此元素需要添加定位,才能使用element.style.left
    因为要让盒子脱离标准流,所以要添加定位。
    函数封装:
<script>
	//简单动画函数封装obj目标对象 target 目标位置
	function animate(obj, target) {
		var timer = setInterval(function() {
			if (obj.offsetLeft >= target) {
			//运动到一定距离,就停止计时器
				clearInterval(timer);
			}
			obj.style.left = obj.offsetLeft + 1 + 'px';
		}, 200);
	}
	var div = document.querySelector('div');
	//调用函数
	animate(div, 300);
</script>

动画函数给不同元素记录不同定时器

如果多个元素都使用这个动画函数,每次都要var声明定时器。我们可以给不同元素使用不同的定时器(自己专门用自己的定时器)

核心原理:利用JS是一门动态语言,可以很方便的给当前对象添加属性。
<script>
	//var obj = {};
	//obj.name = 'andy';
	//简单动画函数封装obj是目标对象 target 是目标位置
	//给不同的元素指定了不同的定时器
	function animate(obj, target) {
		obj.timer = setInterval(function() {
			if(obj.offsetLeft >= target) {
				clearInterval(obj.timer);
			}
				obj.style.left = obj.offsetLeft + 1 + 'px';
		}, 200);
	}
	var div = document.querySelector('div');
	var span = document.querySelector('span');
	//调用函数
	animate(div,300);
	animate(span, 200);
</script>

改进版:

<script>
	//当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
	//解决方案就是 让我们元素只有一个定时器执行
	//先清除以前的定时器,只保留当前一个定时器执行
	clearInterval(obj.timer);
	function animate(obj, target) {
		obj.timer = setInterval(function() {
			if(obj.offsetLeft >= target) {
				clearInterval(obj.timer);
			}
				obj.style.left = obj.offsetLeft + 1 + 'px';
		}, 200);
	}
	var div = document.querySelector('div');
	var span = document.querySelector('span');
	//调用函数
	animate(div,300);
	animate(span, 200);
</script>

案例:淘宝网页轮播图,也叫焦点图

节流阀

防止轮播图按钮连续点击造成播放过快。

节流阀目的:当 上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。

核心思路:利用回调函数,添加要给变量来控制,锁住函数和解锁函数。
//开始设置一个变量 
var flag = true;
if(flag) {
	flag = false;
	do something...//关闭水龙头
}
//利用回调函数,动画执行完毕后,
flag = true;//打开水龙头

案例:淘宝侧边栏的返回顶部

window.scroll(x,y) 整个窗口滚动到文档中的特定位置。

x是距离文档左边的距离,y是距离文档顶部的距离。x和y都不带单位。

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服