1、js基础(ECMAScript)
0.导读
1.转义符
转义符 | 说明 |
---|---|
“\n” | 换行符 |
“\t” | 缩进 |
2.基本弹窗
alter()
警示弹窗
prompt()
警示输入框
console.log()
打印
3.typeof
获取变量数据类型
<script>
var num = 10;
console.log(typeof num);//number
var str = '10';
console.log(typeof(str));//string
var flag = true;
console.log(typeof(true));//boolean
var vari = undefined;
console.log(typeof(vari)); //undefined
var timer = null;
console.log(typeof(null));//object对象
</script>
4..length
长度
在对象后面加.length
可以返回对象的长度。
例如
var arr1 = [1,2,'1',true];//数组中可以存放任意类型的数据
console.log(arr1.length);//4
1.(基础数据类型)原生数据类型
在计算机里不同的数据类型所占用的内存不同。
在js中定义的变量中,变量要通过等号右边的数据来进行判断,运行完毕之后变量就确定了数据类型。
js是动态的语言,变量的数据类型是可以变换的
1.Number
在js中变量可以是整数也可以是小数
<script>
var num = 10; //num数字型;
var pi = 3.14; //pi数字型
// 1.前面加零表示八进制;
var num1 = 010;
console.log(num1); //转化为十进制输出;
var num2 = 012;
console.log(num2);
//2.十六进制 0~9、 a~f; 0x表示十六进制;
var num3 = 0x10;
console.log(num3);
console.log(Number.MAX_VALUE); //javascript中数字型的最大值;
console.log(Number.MIN_VALUE); //javascript中数字型的最小值;
//3.无穷大和无穷小
console.log(Number.MAX_VALUE * 2); //Infinity javascript中数字型的无穷大值;
console.log(-Number.MIN_VALUE * 2); //-Infinity javascript中数字型的无穷小值;
//4.非数字型NaN
console.log('yangshilin' - 1); //字符串和数字相减为 NaN 非数字;
//5.isNaN是用来判断是否是非数字,是数字返回false,否则返回true;
console.log(isNaN(12));
console.log(isNaN('是你'));
</script>
2.String
-
字符串型可以是引号中的任意文本,其语法为双引号 “” 和单引号 ‘’
-
如果存在嵌套使用时则外双内单或者外单内双。
-
length
用于检测字符串的长度 -
字符串+任何类型 = 新字符串 (数值相加,字符相连)
<script>
var str1 = '我是一个"高富帅"程序员';//外双内单或者外单内双
var str2 = "我是一个'高富帅'\n程序员";
console.log(str1);
console.log(str2);
//length,用于检测字符串的长度。
var str3 = 'my name is andy';//15
console.log(str3.length);
//字符串的拼接
//字符串+任何类型 = 新字符串
console.log('12'+'1');
var age = 12;
console.log('我' + age +'岁');
var age = prompt('你是谁');
alert('我是'+ age );
var a = 'wosishei'
</script>
3.Boolean
<script>
var flag = true;//1,当布尔值进行加法运算时true是当作1来看的
var flag1 = false;//0,当布尔值进行加法运算时false是当作1来看的
console.log(flag + 1);//2
console.log(flag1 + 1);//1
</script>
4.Undefined和Null
<script>
//如果声明一个变量未给值,则输出为undefined 未定义数据类型;
var str;
console.log(str); //undefined
var lable = undefined;
console.log(lable + 'pink');//undefinedpink 字符
console.log(lable + 1);//NaN 非数值
//null 空值
var space = null;
console.log(space + 'pink'); //nullpink 字符
console.log(space + 1);//1
</script>
5.数据类型的转换
1.转换为字符串
方式 | 说明 | 案例 |
---|---|---|
toString() | 转成字符串 | var num = 10;console.log(num); console.log(num.toString()); |
String() | 转成字符串 | var num = 10;console.log(String(num)); console.log(typeof String(num)); |
加号拼接 | 于字符串进行拼接 | var num = 10;console.log(num + ‘’); onsole.log(typeof(num + ‘’)); |
2.转换为数字
方式 | 说明 | 案例 |
---|---|---|
parseInt(string)函数,重点 | 将string类型转换为整数数值型 | parselnt(“78”) |
parseFloat(string)函数,重点 | 将string类型转换为浮点数数值型 | parseFloat(“78.12”) |
Number()强制类型转换 | 将string转换为数值型 | Number(“12”) |
js隐式转换(* / -) | 利用算数运算隐式转换为数值型 | “12” - 0 |
<script>
//数据类型转换
//转换为字符串类型 toString(),String() 强制转换,字符拼接
//1.
var num = 10;
console.log(num);
console.log(num.toString());
console.log(typeof num.toString());
//2.
console.log(String(num));
console.log(typeof String(num));
//3.
console.log(num + '');
console.log(typeof(num + ''));
//转换为数字类型 parseInt(string)函数、parseFloat(string)函数、Number()强制类型转换、js隐式转换(- * /)、
var age = prompt('请输入你的年龄');
console.log(parseInt(age)); //只能得到整数。
console.log(parseInt('3.14')); //3
console.log(parseInt('120px')); //120,自动去掉单位
console.log(parseInt('rem120px')); //NaN
console.log(parseFloat('3.14')); //3.14
console.log(parseFloat('120px')); //120
console.log(parseFloat('rem120px')); //NaN
var str = '123.2';
console.log(Number(str)); //123.2
console.log('120' - 1); //119
console.log('120' * 1); //120
console.log('120' / 1); //120
</script>
3.转换为布尔型
方式 | 说明 | 案例 |
---|---|---|
Boolean()函数 | 其他类型转换为布尔值 | console.log(Boolean(‘’)); console.log(Boolean(0)); console.log(Boolean(NaN)); console.log(Boolean(null)); console.log(Boolean(undefined)) |
<script>
//代表否定,空的值会被转化为false ,例如下列五种,其余的都是true2
console.log(Boolean(''));//false
console.log(Boolean(0));//false
console.log(Boolean(NaN));//false
console.log(Boolean(null));//false
console.log(Boolean(undefined))//false
console.log(Boolean('xiaobai'));//true
console.log(Boolean(12));//true
</script>
6.运算符
-
算数运算符
运算符 描述 % 取余(5 % 2 = 1) 浮点数运算会有进度问题
运算符拥有优先级,先乘除再加减
-
递增和递减运算符
运算符 描述 ++i 前自增,先自增再运算 i++ 后自增,先运算再自增 –i 前自减 i– 后自减 <script> //1.自增 var age = 10; ++age; console.log(age);//11 类似于 age = age + 1; //2.先加1,后返回现在的值 var p = 10; console.log(++p + 10);//21 //1.自减 var num = 10; num++; console.log(num); //前置自增和后置自增单独使用效果一样,单独使用都是表达式 //后置自增 口诀:先返回原值,后自加1 var age1 = 10; console.log(age1++ + 10);//20 先返回原值 10 + 10 console.log(age1)//再自增 20 + 1 </script>
//练习 <script> var a = 10; ++a; var b = ++a + 2; console.log(b); //14 var c = 10; c++; var d = c++ + 2; console.log(d);//13 var e = 10; //返回值加返回值 var f = e++ + ++e;//1.e++返回值 = 10 e自增 = 11 2.++e自增 = 12 返回值e = 12; console.log(f);//22 </script>
-
比较运算符
运算符 描述 案例 返回值为true或false < > >= <= == 会将字符串的数据类型转换为数字,只要求值相等 18==“18” true != === 值和数据类型要一致 !== 要求值和数据类型一致 37===“37” false -
逻辑运算符
运算符 说明 && 与,and 两边都为true时才返回true,否则false || 或,or 有一边是true就返回true ! 非,not 逻辑中断:当有多个表达式(值)时,左边的表达式值可以确定结果时,就不再继续运算右边的表达式的值
//逻辑运算中的短路(逻辑中断) //与(且)逻辑中断 //如果表达式1结果为真 则返回表达式2 //如果表达式1结果为假 则返回表达式1 console.log(123 && 456); //123 =true 为真 、返回 456 console.log(123 && 456 && 789); //123 console.log(0 && 456); // 0 console.log(123 && 0); //0 console.log('' && 123); //如果有空的或者否定的为假 ( 0、''、null 、undefined、NaN、) 其余是真的 //或 逻辑中断 //如果表达式1结果为真 则返回表达式1 //如果表达式1结果为假 则返回表达式2 console.log(123 || 456); //123 console.log(0 || 456); //456 console.log(0 || 456 || 789); //456
-
赋运算符
//赋值运算符 var num = 10; //num = num + 1; num++; num = num + 2; //mun += 2; console.log(num);//12 var age = 2; age = age * 10;//age *= 10;
-
运算符的优先级
优先级 运算符 1.小括号 () 2.一元运算符 ++、–、! 3.算数运算符 先 * / % 后 + - 4.关系运算符 > >= < <= 5.相等运算符 == != === ! == 6.逻辑运算符 先 && 后 || 7.赋值运算符 = 8.逗号运算符 ,
2、流程控制
流程控制就是来控制我们的代码按照什么结构顺序来执行
1.顺序结构
顺序结构是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行,程序中大多数的代码都是这样执行的。
2.分支结构
1.if-else
由上到下执行代码的过程中,根据不同的条件,执行不同的路径代码(执行代码多选一的过程) , 从而得到不同的结果
if(条件表达式){
//执行表达式
}
//如果条件表达式为真,则执行表达式,为假则跳过执行下面的语句
分支语句是多选一,最终只会执行一句。
用prompt
输入时,age
保留的是字符型,在进行if
判断时,>=
会将字符串的数据类型转换为数字,只要求值相等.
<script>
//1.顺序结构2.分支结构3.循环结构
var age = prompt('请输入你的用户年龄!');
if(age >= 18){
alert('您的年龄可以上网!');
}
else if(age>=0 && age < 18){
alert('你的年龄不满足!');
}
else {
alert('你输入的年龄错误!');
}
</script>
2.三元表达式
语法结构:
条件表达式 ? 表达式1 : 表达式2 ;
//如果条件表达式结果为真,返回表达式1的值,为假返回表达式2的值
//例如:
var num = 5;
var result = num > 5 ? '是' : '否';
consele.log(result);
3.switch
switch
只适合在表达式比较固定时使用,如果表达式是范围就适合if-else
。
switch (表达式){
//表达式和value数据类型必须一致,不然无法被匹配上。
case value1:
alert("1");
break;
//如果当前case里没有break来跳出switch,还会执行下一条case语句,直到有break,或则结束。
case value2:
alert("2");
break;
case value3:
alert("3");
break;
.....
default:
alert("没有匹配!");
//不需要break
}
//列如
<script>
var num1 = prompt('请输入:') ;//输入的为字符
// var num2 = Number(num1);//转换为数字
switch (num1) {
case '苹果':
console.log('10');
break;
case '香蕉':
console.log('15');
break;
case '菠萝':
console.log('20');
break;
case '西瓜':
console.log('25');
break;
case '花生':
console.log('30');
break;
//执行过程,如果上述结果都没有匹配,就执行最后的default
default:
console.log('没有找到!');
}
</script>
3.循环结构
循环的目的是为了重复执行
1.for循环
for(变量初始化 ;条件表达式 ;操作表达式){
循环体;
}
循环打印1~100的累加和
var sum = 0;
for (var i = 1; i <= 100; i++){
sum += i;
}
console.log(sum);
2.双层for循环
案例:复杂数据类型 > 冒泡排序法
外层的for循环执行一次,里层的for循环执行全部
<script>
var i;
var j;
var sum = '';
for (i = 1; i <= 9; i++){
for( j = 1;j <= i; j++){
sum += j + '*' + i + '=' + j*i + '\t' ; // \t进行空格 使用空字符是因为字符拼接直接转化为字符
}
sum += '\n';// \n换行
}
console.log(sum);
</script>
3.while循环
while
循环体语法结构语法
while (条件表达式){
//循环体
}
//当条件表达式为真时执行循环体
当判断条件比较复杂时就使用while
循环
<script>
var i = 0;
//满足条件时进行循环,不满足时退出循环。
while(i <= 5){
i++;//计数器
console.log('haha!');
}
</script>
4.do-while循环
执行顺序
-
先执行一次循环,再判断条件
-
表达式为真时再次进行循环
do-while
至少会循环一次
//先执行一次循环,再判断条件
var i = 0;
do {
console.log('你好!');
i++;
} while (i <= 5 );//表达式为真时再次进行循环
5.continue
关键字
continue
关键字用于跳出本次循环,继续下一次循环
for (var i = 1; i <= 5; i++){
if(i == 3){
continue;//i == 3 时跳过循环;
}
console.log("打印" + i + "次");
}
6.break关键字
break
关键字用于打破当前循环,循环结束。
for (var j = 1; j <= 5; j++){
if(j == 3){
break;//i == 3 时打破循环;
}
console.log("打印!");
}
3、复杂数据类型
1.数组
1.数组创建
数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名 下的优雅方式。
-
new关键字创建数组
//1. 利用new创建数组 A要大写 var arr = new Array();//创建了一个空的数组
-
利用数组字面量创建数组
//2.利用数组字面创建数组 var arr = [];//创建了一个空的数组 var arr1 = [1,2,'1',true];//数组中可以存放任意类型的数据,数组里面的元素用逗号分开 arr1[3]是布尔值
-
数组的索引是从0开始与元素一一对应
-
例如得到第一个元素console.log(arr1[0])
-
输出的索引超过索引就是返回
undefined
-
遍历:就是把数组中的每个元素从头到尾都访问一次。
var arr = ['red','green','blue']; for(var i = 0;i <= arr.length-1; i++){ console.log(arr[i]); }
2.数组元素新增
//通过length长度新增数组元素
var array = ['red','green','blue','pink'];
array.length = 5;//将数组的长度修改成了5;
console.log(array[4]);//undefined
array[4] = 'ok';//追加数组元素
console.log(array);
3.删除数组指定元素
<script>
//将不是0的数添加到新数组
var array = [2,0,6,1,77,0,52,0,25,7,10];
var array1 = [];
for (let index = 0; index < array.length; index++) {
if(array[index] != 0){
array1[array1.length] = array[index];
}
}
console.log(array1);
</script>
4.筛选数组元素
<script>
//筛选出大于等于10的数组元素,并将他们放入新的数组中
//法1.
var array1 = [2,0,6,1,77,0,52,0,25,7,10];
var num = 0;
var array2 = [];
for (let index = 0; index < array1.length; index++) {
if(array1[index] >= 10){
array2[num] = array1[index];
num++;
}
}
console.log(array2);
//法2.
var array1 = [2,0,6,1,77,0,52,0,25,7,10];
var array2 = [];
//array2.length 刚开始没有数组,长度为零
for (let index = 0; index < array1.length; index++) {
if(array1[index] >= 10){
array2[array2.length] = array1[index];
}
}
console.log(array2);
</script>
5.数组翻转
<script>
var array = ['red','green','blue','pink'];
var array1 = [];
for (let index = 3; index >= 0; index--) {//固定长度
array1[array1.length] = array[index];
}
console.log(array1);
console.log(array1.length);
//2.
var array = ['red','green','blue','pink'];
var array1 = [];
for (let index = array.length-1; index >= 0; index--) {//不固定长度
array1[array1.length] = array[index];
}
console.log(array1.length);
</script>
6.冒泡排序法
双层for循环应用
- 外层循环管交换的趟数(
.length-1
) - 里层循环管交换的次数(
.length-i-1
)
<script>
//降序排列;
var array = [5,4,3,2,1];
//var array = [5,4,3,2,1,7];
for (let i = 0; i < array.length-1; i++) {//需要进行四次循环,外层循环管交换的趟数
for (let index = 0; index <= array.length-i-1; index++) {//每次交换两个,第一次循环要交换四次,里层循环管交换的次数
//大于是升序排列,小于是降序排列
if(array[index] > array[index+1]){ //第二次要交换三次
var temp = array[index]; //第三次要交换两次
array[index] = array[index+1]; //第四次要交换一次
array[index+1] = temp;
}
}
}
console.log(array);
</script>
2.函数
1.定义函数
函数,就是封装了一段可以重复执行调用的代码块,目的:可用来减少代码块的重复操作
函数的使用:
-
声明函数
- 利用函数关键字定义函数
- 利用函数表达式
-
调用函数(函数不调用不执行);
利用关键字声明函数
//1.利用关键字声明函数
// function 函数名( ) {//函数名一般是动词
// 函数体
// }
function hai() {
console.log('haha!');
}
// function 声明函数的关键字
//2.调用函数(函数不调用不执行);
hai();
利用函数表达式声明函数
//利用函数表达式声明函数
<script>
// fun是变量名,不是函数名、
// 函数表达式声明方式跟变量差不多、只不过变量里面存的是值 、函数表达式里面存的是函数、
var fun = function (aru){
console.log('函数表达式声明函数!');
console.log(aru);
}
//fun();//函数调用
fun('aru');
console.log(fun);//打印的是函数体
</script>
2.函数的参数
形参 实参
- function 函数名(形参1,形参2,…) {在声明函数的小括号里面的是 形参(形式上的参数用来接收实参 )}
- 调用:函数名(实参1,实参2,…)在函数调用的小括号里是实参(实际参数)
- 函数的参数可以有也可以没有,也可以没有个数限制
//形参和实参的执行过程
function cook(aru) {//形参是接收实参的 aru = '酸辣土豆丝' 形参类似于一个变量 不需要声明
console.log(aru);
}
cook('酸辣土豆丝!');
cook('大肘子');
//函数的参数可以有也可以没有,也可以没有个数限制
<script>
//函数形参实参个数匹配
function getSun (num1,num2,num3) {
console.log(num1 + num2 + num3);
}
//1.形参和实参一致
//getSun(1,2);
//2.实参 > 形参 形参有几个就接收几个实参,多余的实参不参与运算
//getSun(1,2,3);
//3.实参 < 形参 形参是不需要声明的变量,此时num3是undefined,1+2+undefined = NaN 非数字
//getSun(1,2);
</script>
参数个数 | 说明 |
---|---|
实参 = 形参 | 正常输出 |
实参 > 形参 | 只取形参个数,多余的形参不参与运算 |
实参 < 形参 | 形参是不需要声明的变量,此时多余的形参是undefined,Number + undefined = NaN 非数字 |
3.函数的返回值return
有的时候,我们会希望函数将值返回给调用者。此时通过使用return
语句就可以实现。
<script>
//函数的返回值格式
//(1)函数知识事项某种功能,最终结果会返回给调用者 函数名() 通过return 实现的
// (2) 只要函数遇到return 就把后面的结果返回给函数的调用者 函数名() = return后面的结果
// (3) 代码验证
function getresult(aru) {
return aru;//结果
}
console.log(getresult('大肘子'));//getresult('大肘子')相当于点菜
//求任意两个数的和 完整函数
function getsum(num1,num2) {
return num1 + num2;
}
console.log(getsum(1,2));
function getKongfu (str) {
return "傻逼";
}
console.log(getKongfu("智商"));//"傻逼"
</script>
var max = Number.MIN_VALUE;
function getarray(array) {
//array接收的是一个数组
for (let index = 0; index <= array.length-1; index++) {
if(array[index] >= max){
max = array[index];
}
}
return max;
}
console.log(getarray([5,2,99,101,67,77]));
4.return
终止函数
-
return
后面的代码不会被执行。<script> function getsum(num1,num2) { return num1 + num2; //return后面的代码不会被执行 alert('我是不会被弹出的!'); } console.log(getsum(1,2)); </script>
-
return
一次只能返回一个值,如果返回多个就只会返回最后一个值。可以使用数组来返回。<script> //返回多个值得方法 function getresult(num1,num2) { return [num1 + num2,num1 - num2,num1 * num2,num1 / num2]; //return 一次只能返回一个值,如果返回多个就只会返回最后一个值。使用数组可以返回多个值。 } console.log(getresult(2,3)); </script>
-
如果函数有
return
则返回 return 后面的值,如果函数没有 return 则返回undefined
<script> //如果函数有return 则返回 return 后面的值,如果函数没有 return 则返回undefined function fun1() { return 666; } console.log(fun1());//666 function fun2() { } console.log(fun2);//undefined </script>
5.break
,continue
,return
的区别
- break : 结束当前的循环体(如for. while )。
- continue :跳出本次循环,继续执行下次循环(如for. while )。
- return : 不仅可以退出循环,还能够返回return语句中的值,同时还可以结束当前的函数体内的代码。
6.函数的相互调用
//函数调用另一个函数
function fn1() {
console.log(11);
fn2();
}
function fn2() {
console.log(22);
}
fn1();
==注意:==在函数的调用中,要注意实参的类型转换,例如空字符串是false,等等
7.js的两种作用域,变量
js作用域:就是代码名字、(变量)在某个范围作用和效果 目的是为了提高程序的可靠性更加重要的是减少命名冲突
-
全局作用域 全局变量
整个script标签 或者是一个单独的js文件
var num = 10;//全局变量 //例如将变量定义在script标签中
-
局部作用域 局部变量
在函数内部就是局部作用域,这个代码只在函数内部起效果和作用
函数的形参是局部变量
如果在函数内使用未声明的变量也称之为全局变量
//全局作用域 var num = 10;//全局变量 console.log(num);//10 function fn(){ //局部作用域 num3 = 30;//如果在函数内使用未声明的变量也称之为全局变量 var num = 20;//局部变量 console.log(num);//20 //在不同的作用域下变量的命名不会产生冲突 }
3.从执行效率来看全局变量和局部变量
(1).全局变量只有在浏览器关闭的时候才会销毁,比较占内存
(2).局部变量在程序执行完毕后就会销毁,比较节约内存
8.作用域链
作用域链:内部函数访问外部函数的变量,采取的是链式查找的方式来决定取那个值(从里到外),这种结构我么称作链域。
var Num = 10;
function fn1() {
var Num = 55;
function fn2() {
console.log(Num);
//此时会去访问最近的Num,如果没有就逐渐往上层查找。
//先查找fn1里面的Num = 55; 如果没有就去查找全局作用域里面的Num = 10;
}
fn2();//不调用不执行
}
fn1();
9.js的预解析机制
1.js引擎运行js分为两步:预解析 代码执行
(1).预解析 js引擎会把js里面所有的var还有function提升到当前作用域的最前面
(2).代码执行 按照代码书写的顺序从上往下执行
2.预解析分为 变量预解析(变量提升) 和 函数预解析(函数提升)
(1)变量声明 就是把所有的变量声明提升到当前的作用域最前面 不提升赋值操作
(2)函数提升 就是把所有的函数声明提升到当前作用域的最前面 不调用函数
1.变量提升机制
console.log(num);//undefined
var num;
//变量预解析详情:
// var num;
// console.log(num);
// num = 10;
//这种方法定义的函数不会被提前加载,必须执行到函数定义的语句才会加载这个函数,所以只能在函数后调用
fun();//fun is not a function
var fun = function () {
console.log(22);
}
//函数表达式 调用必须写在函数表达式的后面
//变量预解析详情:
//var fun;
//fun();
//fun = function(){console.log(22);}
var fun = function () {
console.log(22);
}
fun();//22
//变量预解析详情:
//var fun;
//fun = function(){console.log(22);}
//fun();
2.函数提升机制
//这种方式定义函数他会提前被加载,所以调用语句可以卸载函数之前
fn();//可以被调用
function fn() {
console.log(11);
}
fn();//可以被调用
// 函数提升解析详情:
// function fn(){console.log(11);}
// fn();
3.案例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//1.案例:
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
//1.案例执行过程
var num;
function fun() {
var num;
console.log(num);
num = 20;
}
num = 10;
fun();
//2.案例
var num = 10;
function fn(){
console.log(num);
var num = 20;
console.log(num);
}
fn();
//2.案例执行过程
var num;
function fn() {
var num;
console.log(num);
num = 20;
console.log(num);
}
num = 10;
fn();
//3.案例
function f1(){
var a = b = c = 9;
//相当于 var a = 9; b = 9; c = 9;b,c未进行变量声明,当作全局变量来看
console.log(a);//9
console.log(b);//9
console.log(c);//9
}
f1();
console.log(a);//a is not defined
console.log(b);//9
console.log(c);//9
</script>
</body>
</html>
10.arguments
当我们不确定有多少个参数传递的时候.可以用arguments
来获取。在JavaScript
中,arguments
实际上它是当前函数的一个内置对象。 所有函数都内置了一个arguments对象, arguments对象中存储了传递的
所有实参
。
伪数组并不是正真意义上的数组,使用arguments
不需要形参
- 具有数组的
length
属性 - 按照索引的方式存储的
- 它没有真正数组的一些方法
pop()
,push()
等等 - 只有函数才有
Arguments
对象
function fn() {
console.log(arguments);//Arguments[1,2,3]
for (let index = 0; index <= arguments.length-1; index++) {
console.log(arguments[index]);//
}
fn(1,2,3);
Arguments案例:
function fu() {
var max = Number.MIN_VALUE;
for (let index = 0; index < arguments.length; index++) {
if (arguments[index] >= max) {
max = arguments[index];
}
}
return max;
}
console.log(fu(1,5,8,9));
console.log(fu(8,99,87,101,102,99));
3.对象
在JavaScript中,对象是一组无序的相关属性
和方法的集合
,所有的事物都是对象,例如字符串、数值、数组、函数等。
对象是由属性
和方法
组成的。
●属性:事物的特征,在对象中用属性来表示(常用名词)
●方法:事物的行为,在对象中用方法来表示(常用动词)
保存一个值时,可以使用变量,保存多个值( 一组值)时,可以使用数组。如果要保存一个人的完整信息使用对象。
1.对象的创建和调用:
-
利用 字面量 创建对象 ,就是 花括号 {} 里面包含了表达这个具体事物 (对象)的属性和方法。
var obj = { uname: '张三丰', age: 18 , sex: '男' , sayHi:function (){ console.log('hi~'); } }; //(1). 里面的属性或者方法我们采取键值对的形式 键 属性名 :值 属性值 //(2). 多个属性或者方法中间用逗号隔开的 //(3). 方法冒号后面跟的是一个匿名函数 //2.使用对象 //(1). 调用对象的属性 我们采取 对象名.属性名 console.log(obj.uname); //(2). 对象名['属性名'] console.log(obj['age']); //(3). 调用对象的方法 sayHi 对象名.方法名(); 记得添加小括号; obj.sayHi();
-
利用
new object
创建对象var obj = new Object();//空对象 obj.uname = '张三疯'; obj.age = 18 ; obj.sex = '男'; obj.sayHi = function () { console.log('hei~'); }; //(1) 我们是利用 等号 = 赋值的方法 添加对象的属性和方法 //(2) 每个属性和方法之间用 分号结束 console.log(obj.age); console.log(obj['sex']); obj.sayHi()
-
利用 函数 创建对象
//因为我们一次创建一个对象,里面很多的属性和方法是大量相同的 我们只能复制
//因此我们可以利用函数的方法 重复这些相同的代码 我们就把这个函数称为 构造函数
//在函数里面封装对象;
//构造函数 就是把我们对象里面一些相同的属性和方法抽象出来封装到函数里面
//属性和方法前面必须添加 this
function Obj(uname,age,sex) {
this.uname = uname;
this.age = age;
this.sex = sex;
this.sayHi = function (sing) {
console.log(sing);
}
};
var ldh = new Obj('刘德华', 18 ,'男',);//调用
console.log(ldh.uname);
console.log(ldh['age']);
ldh.sayHi('冰雨!');
//构造函数不需要 return 就可以返回结果
// new 关键字执行过程
//1. new 构造函数可以在内存中创建了一个空的对象
//2. this 就会指向刚才创建的空对象
//3. 开始执行构造函数里面的代码 给这个空对象添加属性和方法
//4. 返回这个对象
●构造函数,如Stars() ,抽象了对象的公共部分,封装到了函数里面,它泛指某一大类( class )。
●创建对象, 如new Stars(),特指某一个,通过new关键字创建对象的过程我们也称为对象实例化。
new在执行时会做四件事情:
1.在内存中创建一个新的空对象。
2.让this指向这个新的对象。
3.执行构造函数里面的代码,给这个新对象添加属性和方法。
4.返回这个新对象(所以构造函数里面不需要return.
2.遍历对象
for in 遍历对象
for in 里面的变量 我们喜欢写 k 或者 key
<script>
var obj = {
name: 'pink',
age: 18 ,
sex:'男',
}
//for in 遍历对象
//for in 里面的变量 我们喜欢写 k 或者 key
for(var k in obj){
console.log(k);//name age sex 得到属性名
console.log(obj[k]);// pink 18 男 得到属性值
}
</script>
3.js内置对象
●JavaScript中的对象分为3种:自定义对象、内置对象、浏览器对象
●前面两种对象是JS基础内容,属于ECMAScript; 第三个浏览器对象属于我们JS独有的,我们JS API内容
●内置对象就是指JS语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是 最基本而必要的功能(属性和方法)
1.Math对象
1.math使用
Math | 描述 |
---|---|
Math.PI | 圆周率 |
Math.floor() | 向下取整 |
Math.ceil() | 向上取整 |
Math.round() | 四舍五入 |
Math.random() | 随机数方法(不跟参数) |
Math.max(),Math.min() | 求最大值,最小值 |
Math.abs() | 绝对值 |
console.log(Math.PI);//3.141592653589793
console.log(Math.max(1,2,99,101));//101
console.log(Math.max(-1,-10));//-1
console.log(Math.max(1,99,'pink老师'));//非数字 NaN
console.log(Math.max());// -Infinity
//取绝对值得方法
console.log(Math.abs(-1));//abs 绝对值 1
console.log(Math.abs('-1'));// 隐式转换 1
//取整数的方法
//Math.floor()
console.log(Math.floor(-3.9));// 向下取整 -4
console.log(Math.floor(3.9));// 3
//Math.ceil()
console.log(Math.ceil(1.9));//向上取整 2
console.log(Math.ceil(1.1));// 2
//Math.round()
console.log(Math.round(1.1));//四舍五入 1
console.log(Math.round(1.5));// 2
console.log(Math.round(-1.1));// -1
console.log(Math.round(-1.5));//-1 只会在两个整数间取最大值 -2 -1
//随机数方法 random() 范围[0.1)
console.log(Math.random());//不跟参数
2.随机数方法
//随机数方法 random() 范围[0.1)
console.log(Math.random());//不跟参数
我们想要得到两个数之间的随机整数 并且包含这两个整数
Math.floor(Math.random()*(max - min + 1)) + min;
function Getrandom(min,max){
return Math.floor(Math.random()*(max - min + 1)) + min;
}
console.log(Getrandom(1,10));
2.Date对象
1.概述
Data()
日期对象 是一个构造函数 必须使用new 来调用创建我们的日期对象
-
使用Date() 如果没有跟参数 返回当前系统的当前时间
var date = new Date(); console.log(date);//输出当前时间
-
参数常用的写法 数字型 2019 ,10 ,01 或者是字符串型 ‘2019-10-1 8:8:8’
var date1 = new Date(2019,10,01); console.log(date1);//返回的是11月 不是 10月 var date2 = new Date('2019-10-1 8:8:8'); console.log(date2);//返回10月 重点使用这种方法
●Date 对象和Math对象不一-样,他是一个构造函数,所以我们需要实例化后才能使用
●Date 实例用来处理日期和时间
2.日期格式化
方法名 | 说明 | 代码 |
---|---|---|
getFulYear() | 获取当年 | dObj.getFllYear() |
getMonth() | 获取当月(0-11)常在后面加一 | dObj.getMonth() |
getDate() | 获取当天日期 | dObj.getDate() |
getDay() | 获取星期几(周日0 到周六6) | dObj.getDay0) |
getHours() | 获取当前小时 | dObj.getHours() |
getMinutes() | 获取当前分钟 | dObj.getMinutes() |
getSeconds() | 获取当前秒钟 | dObj.getSeconds() |
var date = new Date();
console.log(date.getFullYear());//返回当前日期的年
console.log(date.getMonth() + 1);//返回月份小1个月 记得月份+1 (0-11)
console.log(date.getDate());//返回的是 几号
console.log(date.getDay());//周日返回为0 周一为1 周二为2 周六为6
console.log(date.getHours());//时
console.log(date.getMinutes());//分
console.log(date.getSeconds());//秒
3.时间戳
获得Date总的毫秒数(时间戳) 不是当前时间的毫秒数 而是距离1970年1月1号过了多少毫秒数
var date = new Date();
//通过valueOf() getTime()
//1.
console.log(date.valueOf());//现在时间距离1970 1 1 的毫秒数
//2.
console.log(date.getTime());
var date = new Date();
//3.
var date1 = + new Date();//返回的是总的毫秒数
console.log(date1);
//4.
//H5 新增的方法,获取毫秒数
console.log(Date.now());
4.倒计时案例
转换公式如下:
-
parseInt 截取为整数
-
d = parseInt(总秒数/60/60/24) //计算天数
-
h = parseInt(总秒数/60/60%24) //计算小时
-
m = parseInt(总秒数/60%60) //计算分钟
-
s = parseInt(总秒数/60) //计算秒数
function getNewdate(time) { var newdate = new Date(time); var date = new Date(); date.valueOf(); newdate.valueOf(); var nowdate = newdate.valueOf() - date.valueOf(); nowdate = nowdate/1000;//得到秒数 var dates = parseInt(nowdate / (60*60*24)); dates = dates < 10 ? '0' + dates : dates; var hours = parseInt(nowdate / (60*60)%24); hours = hours < 10 ? '0' + hours :hours; var minus = parseInt(nowdate /60 %60); minus = minus < 10 ? '0' + minus : minus; var seconds = parseInt(nowdate %60); seconds = seconds < 10 ? '0' + seconds : seconds; return '倒计时为:' + dates + '天' + hours + '时' + minus + '分' + seconds + '秒'; } console.log(getNewdate('2022-11-11 00:00:00'));
3.Array对象
1.概述
- 关键字创建数组
var arr = new Array();
var arr = new Array(2);
创建长度为2,内容为空的数组var arr = new Array(1,2);
创建一个数组,等价于[1,2]
2.数组检测
//1. instanceof 运算符 它可以用来检测是否为数组
var arr = [];
var obj = {};
console.log(arr instanceof Array);//true
console.log(obj instanceof Array);//false
//2.Array.isArray(参数);
console.log(Array.isArray((1)));//false
console.log(Array.isArray([1,2]));//true
console.log(Array.isArray(arr));//true
console.log(Array.isArray(obj));//false
3.数组方法增删,翻转,排序,索引
方法 | 描述 | 返回值 |
---|---|---|
push(); | 在数组末尾添加一个或多个数组元素 | 返回新数组长度 |
unshift() | 在数组开头添加一个或者多个元素 | 返回新数组长度 |
pop() | 删除数组最后一个元素,一次只能删除一个元素 | 你删除的是那个元素就返回那个元素 |
shift() | 删除数组第一个元素,一次只能删除一个元素 | 你删除的是那个元素就返回那个元素 |
reveser() | 翻转数组 | 返回新数组 |
sort(function(a,b){return a - b}) | 数组排序(升序(a - b),降序(b - a)) | 返回子新数组 |
indexOf() ;str.indexOf(‘要查找的字符’,‘起始位置’); | 数组索引的方法 从前面往后查找 | 如果数组中有两个或以上时 只返回第一个索引 如果没有该元素则返回 -1; |
lastIndexOf() | 从后面往前查找 |
<script>
//1. push(); 在数组末尾添加一个或多个数组元素
var arr = [1,2,3];
console.log(arr.push(4,'pink')); //返回长度
console.log(arr);
//push完后 返回的是数组的长度 5
//push() 是可以直接写参数,参数是数组元素,同时给数组追加新的元素
//2. unshift() 在数组开头 添加一个或者多个元素
console.log(arr.unshift('121','pop'));//返回长度
console.log(arr);
//3. pop() 删除数组最后一个元素
arr.pop();
console.log(arr.pop());//你删除的是那个元素就返回那个元素
console.log(arr);
//4. shift() 删除数组最后一个元素
arr.shift();
console.log(arr.shift());你删除的是那个元素就返回那个元素
console.log(arr);
//5. reveser() 翻转数组
console.log(arr.reverse());
console.log(arr);//[3,2,1]
//6. sort() 数组排序(升序)
var arr = [13,4,77,1,7];
arr.sort(function (a,b){
return a - b ;
//return b - a;降序排列;
}) ;//升序排列
console.log(arr);//[ 1, 4, 7, 13, 77 ]
console.log(arr.sort());//[ 1, 13, 4, 7, 77 ]
//因为sort遇到十位数后,先看最左边的1,然后再看右边
console.log(arr);//[ 1, 13, 4, 7, 77 ]
//7. indexOf() 数组索引的方法 从前面往后查找
var arr = ['red','green','blue','pink']
console.log(arr.indexOf('blue'));//2 如果数组中有两个或以上相同元素时 只返回第一个索引 如果没有该元素则返回 -1;
//8. lastIndexOf() 从后面往前查找
</script>
4.数组转化为字符串并拼接
方法 | 描述 | 返回值 |
---|---|---|
toString() | 字符串 | |
join(‘分隔符’) | 字符串拼接,没有参数默认为逗号 | 字符串 |
<script>
//1. toString()
var arr = [1,2,3];
console.log(arr.toString());
console.log(arr.length);//1,2,3
//2. join()
var arr1 = ['green','blue','pink'];
console.log(arr1.join());//默认逗号
console.log(arr1.join('-'));//green-blue-pink
</script>
4.String对象
0.概述
基本数据类型
var str = 'andy';
console.log(str.length);//4
-
对象才有和复杂数据类型才有 属性和方法
-
简单数据类型拥有length属性是因为对基本的数据类型进行了包装
-
基本包装类型:就是把简单的数据类型包装为复杂数据类型
-
例如:
var str = 'andy'; 代码解析。 // 把 简单数据类型 包装成 复杂数据类型 //(1)将简单数据类型包装成复杂数据类型 var temp = new String('andy'); //(2)吧零时变量的值给 str str = temp; //(3)销毁零时变量 temp = null;
1.字符串的不可变
//字符串的不可变
//因为字符串的不可变,所以不要大量的拼接字符串
var str = '';
for(var i = 0;i < 5;i++){
//当循环的次数过大时就会出现卡顿,因为需要开辟新空间
str += 1;
}
console.log(str)
//看起来是将新的字符串赋值给了str 但是之前的字符串所占用的空间并没有被销毁,每产生一个新字符串就会重新开辟内存。
2.根据字符返回位置
方法 | 使用 | 描述 |
---|---|---|
indexOf() | str.indexOf(‘要查找的字符’,‘起始位置’) | 适用于字符串里面有多个重复字符时使用,默认重零开始查找 |
lastIndexOf() |
案例:
var str = 'abcoefoxyozzopp';
var num = 0;
var index = str.indexOf('o');
while (index !==-1) {
console.log(index);
num++;
index = str.indexOf('o',index+1);
//每次查找都会重零开始,所以要 +1 ,跃过被查找过的字符
}
console.log(num);
3.根据位置返回字符
方法 | 说明 | 描述 |
---|---|---|
charAt(index) | 返回指定位置的字符(index字符串的索引号) | str.charAt(0) |
charCodeAt(index) | 获取指定位置处字符的ASCII码(index索引号)| | str.charCodeAt(0) |
str(index) | 获取指定位置处字符 | HTML5, IE8+支持 和charAt)等效 |
案例:
<script>
//1.
//charAt(index) 根据位置返回字符
var str = 'abcoefoxyozzopp';
console.log(str.charAt(0));
for(var i = 0;i < str.length;i++){
console.log(str.charAt(i));
}
//2.charCodeAt()
//返回相应字符的ASCII码 目的:判断用户按的哪一个按键
console.log(str.charCodeAt(0));//97
//3.str[index] h5新增
console.log(str[5]);//f
</script>
案例:
<script>
//核心算法是charAt() 遍历整个数组
//把每个字符存储给对象 如果对象没有该属性,就为1存在就+1.
//遍历对象,得到最大值和字符
var str = 'abcoefoxyozzopp';
var o = {};//对象
var i = 0;
while (i < str.length) {
var chars = str.charAt(i);
if(o[chars]){
//判断对象属性是否存在,
o[chars]++;
}else{
//不存在
o[chars] = 1;
}
i++;
}
console.log(o);
var max = 0;
var ch = '';
for (var k in o){
if ( o[k] > max) {
max = o[k];
ch = k;
}
}
console.log('最多的字符是:' + k + '\t' + '出现次数为:' + max);
</script>
4.字符串的操作方法
方法 | 说明 | 使用 |
---|---|---|
substr() | 截取字符 | substr(‘截取的起始位置’,‘截取几个字符’); |
concat() | 拼接字符 | concat(‘字符串1’,‘字符串2’) |
replace() | 替换字符 | replace(‘被替换的字符’,‘替换的新字符’) ,一次只会替换一个 |
split() | 字符转换为数组 | split(‘分隔符’) |
案例:
<script>
//1. 拼接字符
//concat('字符串1','字符串2')
var str = 'I';
str = str.concat('Love','You');
console.log(str);
//2. 截取字符
//substr('截取的起始位置','截取几个字符');
var str1 = '改革春风吹满地';
str1= str1.substr(0,2);
console.log(str1);
//3. 替换字符
//replace('被替换的字符','替换的字符') 一次只会替换一个字符
var str = 'andy andy';
str = str.replace('a','b');
console.log(str);//改革
//案例 将 o 替换为 *
var str = 'abcoefoxyozzopp';
while (str.indexOf('o') !== -1) {
str = str.replace('o','*');
}
console.log(str);
//4.字符转换为数组
//split('分隔符')
var str = 'abcoe,foxyozz&opp';
console.log(str.split('&'));
//"abcoe,foxyozz"
//"opp"
console.log(str.split(','));
//"abcoe"
//"foxyozz&opp"
</script>
5.大小写转换
方法 | 说明 | 使用 |
---|---|---|
toUpperCase() | 转换为大写 | |
toLowerCase() | 转换为小写 |
案例
4.数据类型问题
1.数据类型
●值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型string,number,boolean,undefined,Null
//简单数据类型 null 返回的是一个空对象 object
var timer = null;
console.log(timer)//Object
//如果有一个变量我们以后打算存储为对象,暂时没有想好放啥,这个时候就给null值。
●引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用) ,因此叫做引用数据类型通过new关键字创建的对象(系统对象、自定义对象) , 如Object, Array. Date等
- 栈(操作系统):由操作系统自动分配释放存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈;简单数据类型存放到栈里面
- 堆(操作系统):存储复杂的数据类型(对象),一般是由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型存放到堆里面
// 1. 简单数据类型 是存放在栈里面 里面直接开辟一个空间存放的是值
// 2. 复杂数据类型 首先在栈里面存放地址 十六进制表示 然后这个地址指向堆里面的数据
2.传参问题
1.简单数据类型传参
函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时 ,其实是把变量在栈空间里的值复制了一份给形参 ,那么在方法内部对形参做任何修改,都不会影响到的外部变量。
// 简单数据类型传参
function fn(a) {
a++;
console.log(a);
}
var x = 10;
fn(x);
console.log(x);
2.复杂数据类型传参
函数的形参也可以看做是一个变量 ,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同-一个堆地址,所以操作的是同一个对象。
// 复杂数据类型传参
function Person(name) {
this.name = name;
}
function f1(x) { // x = p
console.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. 这个输出什么 ? 张学友
2、DOM结构基础(文档对象模型)
1.简介
文档对象模型( Document Object Model ,简称DOM )
![](images/DOM.png)
-
文档:一个页面就是一个文档,DOM中使用Document表示
-
元素:页面中所有标签都是元素。DOM中使用element表示
-
节点:网页中的所有内容都是节点(标签,属性,文本,注释),DOM中使用node表示
DOM把以上内容都看做是对象(对象拥有属性和方法)
2.DOM基础
1.获取页面元素
console.dir();//可以打印我们返回的元素对象 更好的查看里面的属性和方法。
获取网页的几种方法:
-
根据id获取
getElementById();
如果当前文档中拥有特定id的元素不存在则返回null。
id是大小写敏感的字符串,代表了所有要查找的元素的唯一ID。
返回的是一个元素对象。
-
根据标签获取
getElementsByTagName(“标签名”);
返回的是获取过来的元素对象的集合 以伪数组的形式存在。(没有数组的方法,push,pop等)
如果页面没有这个元素,返回的是空的伪数组。
element.getElementsByTagName(“标签名”);
获取某元素下面的子元素,返回的是一个伪数组,伪数组是不能作为父元素的,父元素必须是单个的对象,指明是哪一个元素对象,获取的时候不包括父元素自己 -
通过html5新增的方法获取
getElementsByClass(“类名”);
根据类名获取某些元素集合
返回的值还是 以伪数组的形式显示
querySelector(“选择器”);
返回指定选择器的第一个元素对象集合
选择器要加 # .
querySelectorAll(“选择器”);
返回指定选择器的所有元素对象集合
-
特殊元素获取
-
获取body标签
-
获取html标签
-
<script>
//获取body标签
var bodyele = document.body;
console.log(bodyele);
console.dir(bodyele);
//获取html标签
var htmlele = document.documentElement;
console.log(htmlele);
console.dir(htmlele);
</script>
2.鼠标事件
事件是触发响应的一种机制
常见 鼠标 事件
事件是由三部分组成 事件源 事件类型 事件处理程序
事件 | 描述 |
---|---|
onclick | 鼠标点击触发 |
onmouseover | 鼠标移入触发 |
onmouseout | 鼠标移出触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
案例:
<button id="btn">唐伯虎</button>
<script>
//<!-- //触发响应的一种机制; -->
//常见 鼠标 事件
// onclick 鼠标点击触发
// onmouseover 鼠标移入触发
// onmouseout 鼠标移出触发
// onfocus 获得鼠标焦点触发
// onblur 失去鼠标焦点触发
// onmousemove 鼠标移动触发
// onmouseup 鼠标弹起触发
// onmousedown 鼠标按下触发
//事件是由三部分组成 事件源 事件类型 事件处理程序
//事件源 事件被触发的对象 谁 按钮
var btn = document.getElementById('btn');
//事件类型 如何触发 什么事件 比如鼠标点击(onClick) 还是鼠标经过 还是键盘按下
//事件处理程序 通过一个函数赋值的方式 完成
btn.onclick = function () {
alert('点秋香!');
}
</script>
3.元素操作
1.普通元素内容修改
1.element.innerText
从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去掉
2.element.innerHTML
从起始位置到终止位置的内容,但它包含html标签,同时空格和换行也会保留
input
两种方法都不能使用
区别
innerText 不识别html标签 非标准 去除空格和换行
innerHTML 识别html标签 w3c标准 保留空格和换行
2.普通元素修改属性
-
先获取元素对象
-
对象.属性 = “”;
案例:
<button id="ht">
胡桃
</button>
<button id="qq">
七七
</button>
</br>
<img id="tp" src="../images/0000.jpeg" alt="" title="胡桃">
<script>
var btn = document.querySelector('#ht');
var btn1 = document.querySelector('#qq');
var img = document.querySelector('#tp');
btn.onclick = function () {
img.src = '../images/0000.jpeg';
img.title = '胡桃';
}
btn1.onclick = function () {
img.src = '../images/0001.png';
img.title = '七七'
}
</script>
3.表单元素修改属性
-
获取元素
-
元素对象.value = “”;
this.disabled = true
禁用按钮(点一次之后被禁用)
<button id="btn">点击</button>
<input id="input" type="text" value="输入内容!">
<script>
//操作表单元素
//获取元素
var btn = document.getElementById('btn');
var input = document.getElementById('input');
btn.onclick = function () {
input.value = '123456';
//如果想要某个表单被禁用 不能被点击了 disabled 我们想要这个按钮 button 禁用
btn.disabled = true;//点一次之后被禁用 等同于 this.disabled = true; this指向事件函数的调用者
}
console.log(input.value);
</script>
4.元素样式修改
1.概述
- 先获取元素对象
- 对象.style.样式 = “”;
<style>
div{
width: 300px;
height: 200px;
background-color: pink;
}
</style>
<div>
</div>
<script>
var div = document.querySelector('div');
div.onclick = function () {
this.style.backgroundColor = 'red';
this.style.width = '100px';
//this指向调用者(div)
}
</script>
2.for循环精灵图样式设置
注意56行坐标的使用
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
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/sprite.png) no-repeat;
}
</style>
</head>
<body>
<div class="box">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<script>
// 获取所有元素
var lis = document.querySelectorAll('li');
for(var i = 0;i <= lis.length-1;i++){
// 让索引号 乘以 44 就是每个li 的背景y坐标 index就是我们的y坐标
var index = i * 44;
lis[i].style.backgroundPosition = '0 -' + index + 'px';//x y 坐标;
}
</script>
</body>
</html>
5.样式属性修改
- element.style 行内样式修改
- element.className 类名样式操作
this.className = 'change';
//首先将change类名定义好,并且写好css样式
//然后通过className获取CSS样式
//适用于样式较多或者功能复杂的情况
//className 会直接更改元素的类名,并且覆盖原先的类名
//如果想要保留原先的样式,写法为
this.className = 'first change'//多类名选择器
//first为原来的样式类名,change为现在的样式类名
3.DOM基础案例
1.for循环排它思想(属性)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>按钮</button>
<button>按钮</button>
<button>按钮</button>
<button>按钮</button>
<button>按钮</button>
<script>
var btns = document.getElementsByTagName('button');
for(var i = 0; i < btns.length ; i++){
//执行过程
//外层循环给每各一个li都绑定了点击事件
btns[i].onclick = function () {
for (var i = 0;i < btns.length;i++) {
//内层循环给每一个li清除样式
btns[i].style.background = '';
}
//改变自己的颜色
this.style.background = 'red';
}
}
</script>
</body>
</html>
2.点击元素更换背景(路径)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
body{
background: url(../images/0000.jpeg) no-repeat center center;
}
li{
list-style: none;
float: left;
margin-left: 2px;
}
.baidu img{
width: 100px;
}
.baidu{
overflow: hidden;
margin: 100px auto;
background-color: #fff;
width: 410px;
padding-top: 3px;
}
</style>
</head>
<body>
<ul class="baidu">
<li><img src="../images/0000.jpeg" alt=""></li>
<li><img src="../images/0001.png" alt=""></li>
<li><img src="../images/0003.png" alt=""></li>
<li><img src="../images/0004.jpeg" alt=""></li>
</ul>
<script>
var imga = document.getElementsByClassName('baidu');
var imgs = imga[0].querySelectorAll('img');
var bodyele = document.body;
for(var i = 0;i < imgs.length;i++){
imgs[i].onclick = function () {
bodyele.style.backgroundImage = 'url('+ this.src +')';
}
}
</script>
</body>
</html>
3.鼠标悬停表格变色(className)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</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;
font-size: 12px;
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>003526</td>
<td>农银金穗3个月定期开放债券</td>
<td>1.075</td>
<td>1.079</td>
<td>1.074</td>
<td>+0.047%</td>
</tr>
<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>003526</td>
<td>农银金穗3个月定期开放债券</td>
<td>1.075</td>
<td>1.079</td>
<td>1.074</td>
<td>+0.047%</td>
</tr>
<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>003526</td>
<td>农银金穗3个月定期开放债券</td>
<td>1.075</td>
<td>1.079</td>
<td>1.074</td>
<td>+0.047%</td>
</tr>
</tbody>
</table>
<script>
var tbd = document.getElementsByTagName('tbody');
var trs = tbd[0].getElementsByTagName('tr');
for(var i = 0;i < trs.length;i++){
trs[i].onmouseover = function () {
this.className = 'bg';
}
trs[i].onmouseout = function (){
this.className = '';
}
}
</script>
</body>
</html>
4.表格的全选和取消
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
* {
padding: 0;
margin: 0;
}
.wrap {
width: 300px;
margin: 100px auto 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #c0c0c0;
width: 300px;
}
th,
td {
border: 1px solid #d0d0d0;
color: #404060;
padding: 10px;
}
input{
margin-left: 50%;
transform: translateX(-50%);
}
th {
background-color: #09c;
font: bold 16px "微软雅黑";
color: #fff;
}
td {
font: 14px "微软雅黑";
}
tbody tr {
background-color: #f0f0f0;
}
tbody tr:hover {
cursor: pointer;
background-color: #fafafa;
}
</style>
</head>
<body>
<div class="wrap">
<table>
<!-- theader默认内容居中显示 -->
<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>iPad Pro</td>
<td>5000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPad Air</td>
<td>2000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>Apple Watch</td>
<td>2000</td>
</tr>
</tbody>
</table>
</div>
<script>
//获取元素的id
var j_cbAll = document.getElementById('j_cbAll');
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input');
//注册事件
//1.全选按钮影响子按钮
j_cbAll.onclick = function(){
//console.log(this.checked);
//思路:
//打印判断按钮的状态是true 或则是false 然后将此状态赋值给下面的子按钮
for(var i = 0;i < j_tbs.length;i++){
j_tbs[i].checked = this.checked;
}
}
//2.子按钮影响全选按钮
//思路:
//点击一次子按钮就循环一次按钮的选中状态 如果有按钮的状态为false,即不选中全选按钮
for(var i = 0;i < j_tbs.length;i++){
j_tbs[i].onclick = function(){
var flag = true;
for(var i = 0;i < j_tbs.length;i++){
if(!j_tbs[i].checked){
//状态是否为false
flag = false;
break;
//只要有一个没有选中,就跳出循环
}
}
j_cbAll.checked = flag;//?????
}
}
</script>
</body>
</html>
4.自定属性
1.获取自定义属性值
1.获取属性值的方法
●element.属性 获取属性值。
●element.getAttribute('属性');
<div id="demo" index = "1" class="footer"></di>
var div = document.querySelector('div');
//1. element.属性
console.log(div.id);
//2. element.getAttribute('属性'); get得到获取 Attribute 属性的意思 我们程序员自定义属性 我们称之为自定义属性
console.log(div.getAttribute('id'));//demo
//index是自定义属性
console.log(div.getAttribute('index'));//1
区别:
●element.属性获取内置属性值(元素本身自带的属性)
●element.getAttribute('属性');
主要获得自定义的属性 ( 标准)我们程序员自定义的属性
2.设置元素属性值
设置属性和值elemen.setAttribute('属性','值');
<div id="demo" index = "1" class="footer"></di>
var div = document.querySelector('div');
//1.element.属性 = '值'
div.id = 'test';
console.log(div.id);//test
div.className = 'navs';
//2.elemen.setAttribute('属性','值'); 主要针对自定义属性
div.setAttribute('index',3);
div.setAttribute('class' , 'footr');//在标签中查看,已经成功
console.log(div.getAttribute('index'));
3.移除自定义属性
移除属性element.removeAttribute('属性');
自定义属性的作用:
- 保存自定义属性
- 使用自定义属性
<div id="demo" index = "1" class="footer"></di>
var div = document.querySelector('div');
div.removeAttribute('index');
案例:选项卡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
.tab {
width: 978px;
margin: 100px auto;
}
.tab_list {
height: 39px;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
.tab_list li {
float: left;
height: 39px;
line-height: 39px;
padding: 0 20px;
text-align: center;
cursor: pointer;
}
.tab_list .current {
background-color: #c81623;
color: #fff;
}
.item {
display: none;
}
</style>
</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;">
1
</div>
<div class="item">
2
</div>
<div class="item">
3
</div>
<div class="item">
4
</div>
<div class="item">
5
</div>
</div>
</div>
<script>
var tab_list = document.querySelector('.tab_list');
var lis = tab_list.querySelectorAll('li');
var items = document.querySelectorAll('.item');
for (var i = 0;i < lis.length;i++){
//开始给五个小li 设置索引
lis[i].setAttribute('index', i);
lis[i].onclick = function () {
//1.选项模块
for (var i = 0;i < lis.length;i++){
//lis[i].style.backgroundColor= '';
lis[i].className = '';
}
//this.style.backgroundColor= 'red';
this.className = 'current';
//2.显示模块
var index = this.getAttribute('index');
console.log(typeof index);
for(var i = 0;i < items.length;i++){
items[i].style.display = 'none';
}
items[index].style.display = 'block';
}
}
</script>
</body>
</html>
5.H5自定义属性
自定义属性规范以data-
开头
<div data-index="20"></div>
//h5新增的获取 自定义 的属性方法
//dataset是一个集合里面存放了所有以data开头的自定义属性
//Ie 十一以上才能使用
//data-inde
//获取对象的两种方法
console.log(div.dataset);
console.log(div.dataset['inde']);
console.log(div.dataset.inde);
//data-list-name 获取
//如果自定义属性里面有多个-链接单词,我们获取时就采用 驼峰命名法
console.log(div.dataset.listName);//listName 采用驼峰命名法
console.log(div.dataset['listName']);
5.节点操作
1.概述
节点:网页中的所有内容都是节点(标签,属性,文本,注释),DOM中使用node表示节点。
HTML DOM树中的所有节点均可通过JavaScript进行访问,所有HTML元素(节点)均可被修改,也可以创建或删除。
- 利用DOM提供的方法获取元素
document.getElermentByld();
document.getElementsByTagName();
document.querySelector();
- 逻辑性不强、 繁琐
-
利用节点层级关系获取元素
- 利用父子兄节点关 系获取元素
- 逻辑性强,但是兼容性稍差
一般地 ,节点至少拥有nodeType (节点类型)、nodeName (节点名称)和nodeValue (节点值)这三个基本属性。
- 元素节点nodeType为1
- 属性节点nodeType为2
- 文本节点nodeType为3 (文本节点包含文字、空格、换行等)
Node.nodeType
2.节点层级
1.父级节点
node.parentNode('');
//paren 父亲 Node 节点
<div class="demo">
<div class="box">
<span class="erweima">×</span>
</div>
</div>
//父节点 parentNode
var erweima = document.querySelector('.erweima');
erweima.parentNode;
//erweima.parentNode 等价于 var box = document.querySelectorAll
//得到离元素最近的父级节点(亲爸爸) 如果找不到父节点返回为空;
console.log(erweima.parentNode);
2.子节点
parentNode.childNodes//标准
parentNode.childNode//非标准
parentNode.Children//标准,返回伪数组,可使用下标获取子元素的节点
parentNode.childNodes
返回包含指定节点的集合(即伪数组的形式存在,且包含所有子节点 空格 换行),该集合为即时更新的集合
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
//子节点获取 childNodes
var ul = document.querySelector('ul');
//console.log(ul.childNodes);//9个 包含所有子节点 空格 换行(9个节点包含的5个换行和四个元素)
console.log(ul.children);//children 只获取所有元素节点 是我们实际开发常用的
//获取ol里面第一个孩子和最后一个孩子
var ol = document.querySelector('ol');
console.log(ol.children[0]);//开发中使用的是这种,解决兼容性问题,获取父元素第一个子元素节点
console.log(ol.children[ol.children.length - 1]);//获取父元素最后一个子元素节点
3.获取第一个和最后一个元素节点
注意:获取的第一个子节点,包括文本节点
parentNode.firstChild//获取第一个子节点
parentNode.lastChild//获取最后一个子节点
注意:获取的是元素节点,找不到返回Null
parentNode.firstElementChild//获取的是元素节点,找不到返回Null
parentNode.lastElementChild//获取的是元素节点
<ol>
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
</ol>
//获取ol里面第一个孩子和最后一个孩子
var ol = document.querySelector('ol');
console.log(ol.children[0]);//开发中使用的是这种,解决兼容性问题
console.log(ol.children[ol.children.length - 1]);
//parentNode.firstChild 获取第一个子节点
//console.log(ol.firstChild);//获取的第一个子节点,包括文本节点
//parentNode.firstElementChild ie9 以上可用
console.log(ol.firstElementChild);//获取的是元素节点
//parentNode.lastChild 获取最后一个子节点
//parent.lastElenmentChild
console.log(ol.lastElementChild);
4.兄弟节点
node.nextSibling//当前节点的下一个兄弟节点 包括文本解节点或者元素节点 找不到返回null
ndoe.previousSibling//当前元素的上一个兄弟节点 包括文本解节点或者元素节点 找不到返回null
node.nextElementSibling//当前节点的下一个元素节点
node.previousElementSibling//当前节点的上一个元素节点
<div>我是div</div>
<span>
我是span
</span>
<script>
//1.nextSibling previousSibling
var div = document.querySelector('div');
console.log(div.nextSibling);//当前元素的下一个兄弟节点 包括文本解节点或者元素节点 找不到返回null
console.log(div.previousSibling);//当前元素的上一个兄弟节点 包括文本解节点或者元素节点 找不到返回null
//2.nextElementSibling previousElementSibling IE9以上支持
console.log(div.nextElementSibling);//返回下一个元素节点
console.log(div.previousElementSibling);//返回上一个兄弟节点
</script>
5.解决兼容性的函数
function getNextElementSibling(element){
var el = element;
while (el = el.nextSibling){
if (el.nodeType === 1){
return el;
}
}
return null;
}
6.创建,添加节点
1.创建节点
document.createElement('tagName')
document.createElement()
方法创建由tagName指定的HTML 元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点.
2.添加节点
node.appendchild(child)//添加到默认子节点的末尾
//node 父节点 child 子节点
node . appendchild()
方法将一个节点添加到指定父节点的子 节点列表末尾类似于css里面的after伪元素。
node.insertBefore(child,指定元素);//添加节点
//node 父元素, insertBefore 插入, child子元素, 指定元素 下标。
如果想要页面添加一个新元素:
- 创建元素
- 添加元素
<ul>
<li>123</li>
</ul>
<script>
//创建节点的方法
//document.createElement('tagName');
//1.创建节点
var li = document.createElement('li');
//2.添加节点 node.appendChild(child) node 父级 child 是子级 在子级后面追加元
var ul = document.querySelector('ul');
ul.appendChild(li);
//3.添加节点 node.insertBefore(child,指定元素);
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
</script>
7.删除节点
node.removeChild(Child)
方法从DOM中删除一个子节点,返回删除的节点。
node.removeChild(child)//node 父节点,removeChild 移除子节点
<button>
删除
</button>
<ul>
<li>
熊大
</li>
<li>
熊二
</li>
<li>
光头强
</li>
</ul>
<script>
//node.removeChild(Child)
var btn = document.querySelector('button');
var ul = document.querySelector('ul');
btn.onclick = function () {
if (ul.children.length == 0) {
//当ul.children长度为0时点击按钮被禁用
this.disabled = true;
}
else {
ul.removeChild(ul.children[0]);
}
}
</script>
8.克隆节点
node.cloneNode()
node.cloneNode()
方法返回调用该方法的节点的一个副本,也称为克隆节点。
复制节点(克隆节点)
node.cloneNode()
如果参数为空或者为false,则为浅拷贝,即只克隆复制节点本身,不克隆里面的子节点
node.cloneNode(true)
如果参数为true,则为深拷贝
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
//复制节点(克隆节点)
//node.cloneNode() 如果参数为空或者为false,则为浅拷贝,即只克隆复制节点本身,不克隆里面的子节点
//node.cloneNode(true) 如果参数为true,则为深拷贝
var ul = document.querySelector('ul');
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);
</script>
9.案例(动态生成表格)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</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:'javascript',
score:100
},{
name:'弘历',
subject:'javascript',
score:98
},{
name:'傅恒',
subject:'javascript',
score:99
},{
name:'明玉',
subject:'javascript',
score:88
},{
name:'海',
subject:'javascript',
score:89
}];
//2.往tbody里添加行:有几个人就添加几个行
var tbody = document.querySelector('tbody');
for(var i = 0;i<datas.length;i++){
var tr = document.createElement('tr');
tbody.appendChild(tr);
//创建行里面的单元格,
for(var k in datas[i]){
//遍历行,然后遍历每一行内的对象
var td = document.createElement('td');
console.log(datas[i][k]);//获得属性值
td.innerHTML = datas[i][k];
tr.appendChild(td);
}
//创建有删除的单元格
var td = document.createElement('td');
td.innerHTML = "<a href = 'javascript:;'>删除</a>";
tr.appendChild(td);
}
var as = document.querySelectorAll('a');
for(var i = 0;i <as.length;i++){
as[i].onclick = function () {
tbody.removeChild(this.parentNode.parentNode);
//this.parentNode为td 所在单元格
//this.parendNode.parentNode为tr 所在行
}
}
</script>
</body>
</html>
6.三中创建元素的区别
document.write()
创建标签
document .write
是直接将内容写入页面的内容流,但是如果文档流执行完毕,再调用它则会导致页面全部重绘
//1.document.write()创建元素
var btn = document.querySelector('button');
btn.onclick = function(){
document.write('<div>123</div>');
}
//document .write是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
// document.write('<div>000</div>')
innerHTML
创建标签
innerHTML使用的字符串的开辟方式来进行的,需要开辟新的空间,需要使用大量的时间,
//2.innerHTML创建元素
function fn1(){
var inner = document.querySelector('.inner');
var b1 = +new Date();
for(var i = 0;i < 1000;i++){
inner.innerHTML += '<a href="#">百度</a>';
}
var b2 = +new Date();
console.log(b2 - b1);
}
fn1();
//innerHTML使用的字符串的开辟方式来进行的,需要开辟新的空间,需要使用大量的时间
节省时间可以采用数组对字符进行拼接
document.createElement()
创建标签
//3.document.createElement()创建元素
function fn2(){
var create = document.querySelector('.create');
var c1 = +new Date();
for(var i = 0;i < 1000;i++){
var a = document.createElement('a');
create.appendChild(a);
}
var c2 = +new Date();
console.log(c2 - c1);
}
fn2();
//使用的变量赋值方法,不需要开辟新空间,节省了很多时间
区别:
document.write
是直接将内容写入页面的内容流,但是文档流执行完毕, 则它会导致页面全部重绘。innerHTML
是将内容写入某个DOM节点,不会导致页面全部重绘。innerHTML
创建多个元素效率更高(不要拼接字符串,采取数组形式拼接) , 结构稍微复杂。createElement()
创建多个元素效率稍低一点点 ,但是结构更清晰。
7.总结
1.创建
document.write
innerHTML
createElement
2.增
appendChild
insertBefore
3.删
removerChild
4.改
主要修改Dom的元素属性,dom元素内容,属性和表单元素
- 修改元素属性:
src
,href
,title
等 - 修改普通元素内容:
innerHTML
,innertext
- 修改表单元素:
value
,type
,disabled
等 - 修改元素样式:
style
,className
5.查
主要查询DOM元素
- DOM提供的API方法:
getElementbyId
,getElementsByTagName
(不推荐) - H5提供的方法:
querySelector
,querySelectorAll
(推荐) - 利用节点操作获取元素: 父(
parentNode
),子(Children
),兄(previousElementSibling
,nextElementSibling
) (提倡)
6.属性操作
自定义属性
setAttribute
:设置DOM的属性值getAttribute
:得到DOM的属性值removeAttribute
:移除属性
3、DOM结构核心
1.注册(监听)事件
1.导读
给元素添加事件,称为注册事件或者绑定事件
注册事件的两种方式:传统方法和方法监听注册方式
1.传统事件注册方式
- 利用 on开头的事件onclick
<button onclick= "alert("hi~")" > </button>
- btn.onclick = function(){}
- 特点: 注册事件的唯一性
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
2.方法监听注册方式
- w3c 标准推荐方式
addEventListener()
它是一个方法- IE9之前的IE不支持此方法,可使用
attachEvent
代替 - 特点: 同一个元素同一个事件可以注册多个监听器
- 按注册顺序依次执行
addEventListener
事件监听方式
eventTarget.addEventListener(type,listener[,useCapture])
eventTarget.addEventListenter()
方法将指定的监听器注册到eventTarget(目标对象)
上,当该对象触发指定的事件时,就会执行事件处理函数。
该方法接收三个参数:
type
:事件类型字符串,比如click
.mouseover
, 注意这里不要带on
。listener
:事件处理函数,事件发生时,会调用该监听函数。useCapture
:可选参数,是一个布尔值,默认是false
。
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>IE9 attachEvent</button>
<script>
//1.传统方式注册事件
var btns = document.querySelectorAll('button');
btns[0].onclick = function(){
alert('hi');
}//后面的注册事件会覆盖前面的事件
btns[0].onclick = function(){
alert('hao are you');
}
//2.事件监听注册事件
//同一个元素 同一个事件可以添加多个监听器(事件处理程序)
btns[1].addEventListener('click',function(){
alert('22');
});
btns[1].addEventListener('click',function(){
alert('33');
});
//3.attachEvent(了解)
btns[2].attachEvent('onclick',function(){
alert('00');
});//报错是因为不兼容
</script>
2.删除事件
1.传统删除事件
eventTarget.onclick = null;
2.方法监听删除事件
eventTarget.removeEventListener(type,listener[,useCapture]);
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
//1.
divs[0].onclick = function(){
alert('121');
//1.传统方式删除事件
divs[0].onclick = null;
}
//2.
divs[1].addEventListener('click', fn);//里面的fn不需要加小括号
function fn(){
alert('22');
divs[1].removeEventListener('click',fn);
}
//3.
divs[2].attachEvent('onclick', fn1);
function fn1(){
alert('0000');
divs[2].detachEvent('onclick', fn1);
}//报错是因为不兼容
</script>
</body>
</html>
3.DOM事件流
0.概论
- 事件流描述的是从页面中接收事件的顺序。
- 事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
比如我们给一个div 注册了点击事件:
DOM事件流分为3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
- 事件冒泡: IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到DOM最顶层节点的过程。
- 事件捕获:网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
![](./images/QQ截图20221030202253.png)
我们向水里面扔一块石头,首先它会有一个下降的过程, 这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点(最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡。
1.事件梳理
注意:
- Js代码中只能执行捕获或者冒泡其中的一个阶段。
onclick
和attachEvent
只能得到冒泡阶段。addEventListener(type,listener[,useCapture])
第三个参数如果是true ,表示在事件捕获阶段调用事仰处理程序;如果是false (不写默认就是false ) , 表示在事件冒泡阶段调用事件处理程序。- 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
- 有些事件是没有冒泡的,比如
onblur
,onfocus
,onmouseenter
,onmouseleave
- 事件冒泡有时候会带来麻烦,有时候又会帮助很巧妙的做某些事件。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.father {
overflow: hidden;
width: 300px;
height: 300px;
margin: 100px auto;
background-color: pink;
text-align: center;
}
.son {
width: 200px;
height: 200px;
margin: 50px;
background-color: purple;
line-height: 200px;
color: #fff;
}
</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 -> document
// var 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>
4.事件对象
0.导读
- event 就是一个事件对象 写到我们监听函数的小括号里面 当形参来看
- 事件对象只有有了事件才会存在,它是系统自动创建的,不需要我们传递参数
- 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击里面就包含鼠标相关的信息,鼠标坐标,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键
- 这个事件对象我们可以自己命名 比如
event
、evt
、e
- .事件对象也有兼容性问题 IE678 通过
window.event
div {
width: 100px;
height: 100px;
background-color: pink;
}
<div>123</div>
var div = document.querySelector('div');
div.onclick = function(e){
//console.log(e);
//console.log(window.event);//IE678
e = e || window.event;//兼容性问题解决方案。
console.log(e);
}
1.常见属性和方法
事件对象属性方法 | 说明 |
---|---|
e.target | 返回触发事件的对象 标准 |
e.srcElement | 返回触发事件的对象 非标准ie6-8使用 |
e.type | 返回事件的类型比如click mouseover 不带on |
e.cancelBubble | 该属性阻止冒泡非标准ie6 8使用 |
e.returnValue | 该属性阻止默认事件(默认行为)非标准ie6-8使用比如不让链接跳转 |
e.preventDefault() | 该方法阻止默认事件(默认行为)标准比如不让链接跳转 |
e.stopPropagation() | 阻止冒泡标准 |
this
与e.target
区别:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div>123</div>
<ul>
<li>abc</li>
<li>abc</li>
<li>abc</li>
</ul>
<script>
// 常见事件对象的属性和方法
// 1. e.target 返回的是触发事件的对象(元素) this 返回的是绑定事件的对象(元素)
// 区别 : e.target 点击了那个元素,就返回那个元素; this 那个元素绑定了这个点击事件,那么就返回谁
var div = document.querySelector('div');
div.addEventListener('click', function(e) {
console.log(e.target);
console.log(this);
})
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// 我们给ul 绑定了事件 那么this 就指向ul
console.log(this);
console.log(e.currentTarget);
// e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
console.log(e.target);
})
// 了解兼容性
// div.onclick = function(e) {
// e = e || window.event;
// var target = e.target || e.srcElement;
// console.log(target);
// }
// 2. 了解 跟 this 有个非常相似的属性 currentTarget ie678不认识
</script>
</body>
</html>
阻止默认事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
</style>
</head>
<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>
// 常见事件对象的属性和方法
// 1. 返回事件类型
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);
function fn(e) {
console.log(e.type);
}
// 2. 阻止默认行为(事件) 让链接不跳转 或者让提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
e.preventDefault(); // dom 标准写法
})
// 3. 传统的注册方式
a.onclick = function(e) {
// 普通浏览器 e.preventDefault(); 方法
// e.preventDefault();
// 低版本浏览器 ie678 returnValue 属性
// e.returnValue;
// 我们可以利用return false 也能阻止默认行为 没有兼容性问题 特点: return 后面的代码不执行了, 而且只限于传统的注册方式
return false;
alert(11);
}
</script>
</body>
</html>
2.阻止冒泡事件
<style>
.father {
overflow: hidden;
width: 300px;
height: 300px;
margin: 100px auto;
background-color: pink;
text-align: center;
}
.son {
width: 200px;
height: 200px;
margin: 50px;
background-color: purple;
line-height: 200px;
color: #fff;
}
</style>
<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(); // stop 停止 Propagation 传播
e.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
document.addEventListener('click', function() {
alert('document');
})
</script>
注意:如果给子元素添加阻止冒泡事件,点击子元素会阻止冒泡,但是点击父元素还是会进行冒泡。
5.事件委托
事件委托的原理
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
<ul>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
</ul>
<script>
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// alert('知否知否,点我应有弹框在手!');
// e.target 这个可以得到我们点击的对象
e.target.style.backgroundColor = 'pink';
})
</script>
6.鼠标事件
1.禁止鼠标右键菜单
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
document.addEventListener('contextmenu',function(e){
e.preventDefault();
})
2.禁止鼠标选中(selectstart 开始选中)
document.addEventListener('selectstart',function(e){
e.preventDefault();
})
7.鼠标事件对象(MouseEvent)
鼠标事件对象 | 描述 |
---|---|
e.clientX | 返回鼠标相对于浏览器窗口可视区的X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
e.pageX | 返回鼠标相对于文档页面的X坐标IE9+ 支持 |
e.pageY | 返回鼠标相对于文档页面的Y坐标1E9+支持 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的Y坐标 |
<script>
//鼠标事件对象 MouseEvent
document.addEventListener('mousemove', function(e) {
//client 返回可视区域x,y坐标
console.log(e.clientX);
console.log(e.clientY);
//page 返回页面文档的x,y坐标
console.log(e.pageX);
console.log(e.pageY);
//screen 鼠标在电脑屏幕的x,y坐标
console.log(e.screenX);
console.log(e.screenY);
});
</script>
8.键盘事件对象(KeyboardEvent)
1.键盘事件
事件 | 触发条件 |
---|---|
onkeyup | 某个键盘按键被松开时触发 |
onkeydown | 某个键盘按键被按下时触发 不松开会一直触发 |
onkeypress | 某个键盘按键被按下时触发但是它不识别功能键 比如ctrl shift 箭头 等 不松开会一直触发 |
keyup
和keydown
事件不区分大小写 例如:A和a得到的都是65。keypress
事件区分大小写
三个事件的执行顺序:
keydown - - keypress - - keyup(与代码顺序无关)
2.键盘对象
键盘事件对象属性 | 说明 |
---|---|
key | |
keyCode | 返回该键ASCII码的值 |
keyup
和keydown
事件不区分大小写 例如:A和a得到的都是65。keypress
事件区分大小写。
<script>
document.addEventListener('keyup',function(e){
console.log('keyup:' + e.keyCode);
if(e.keyup == 65){
console.log('你按的是A/a键');
}
else{
console.log('你按的不是A/a键');
}
});
//1.keyup keydown 事件不区分大小写 ASCII A和a都是65
//2.keypress 事件区分大小写字母 ASCII 码不相同 A 97 a 65
document.addEventListener('keypress',function(e){
console.log('keypress:' + e.keyCode);
});
</script>
4、BOM结构(浏览器对象模型)
0.导读
BOM ( Browser Object Model )
即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window.
1.DOM与BOM的区别
1.DOM
-
文档对象模型
-
DOM就是把[文档」当做一个「对象」来看待
-
DOM的顶级对象是document
-
DOM主要学习的是操作页面元素
-
DOM是W3C标准规范
2.BOM
- 浏览器对象模型
- 把「浏览器」当做一个「对象」来看待
- BOM的顶级对象是window
- BOM学习的是浏览器窗口交互的一些对象
- BOM是浏览器厂商在各自浏览器上定义的,兼容性较差
2.Window的构成
0.概述
- 它是js访问浏览器窗口的一个接口
- 它是一个全局对象,定义在全局作用域中的变量,函数都会变成window对象的属性和方法,在调用的时候可以省略window,前面学习的对话框都属于window对象的方法,如
alert()
,prompt()
。
3.窗口加载事件
1.window.onload
window.onload = function (){
}
window.addEventLiatener('click', function(){
})
window.onload
是窗口(页面)加载事件,当文档内容完全加载完会触发改事件(包括图像,脚本文件,CSS文件等),就调用的处理函数- 有了
window.onload
就可以把JS代码写到页面元素的上方,因为onload
是等页面内容全部加载完毕,再去执行处理函数。 window.onload
传统注册事件方式只能写一次,如果有多个,会以最后一个window.onload
为准。- 如果使用
addEventListener
则没有限制
2.DOMContentLoaded
document.addEventListener('DOMContentLoaded', function(){
})
DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片, flash等等。
3.区别
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
//window.onload 是窗口(页面)加载事件,当文档内容完全加载完会触发改事件(包括图像,脚本文件,CSS文件等),就调用的处理函数
//有了window.onload 就可以将js放到任何地方
//缺点:window.onload传统注册事件方式只能写一次,如果有多个,会以最后一个window.onload为准
// window.onload = function(){
// var btn = document.querySelector('button');
// btn.addEventListener('click', function () {
// alert('点击我');
// })
//}
//js的执行顺序是先加载元素,再从上往下执行,所以js事件要写到后面
//改为:
window.addEventListener('load',function(){
var btn = document.querySelector('button');
btn.addEventListener('click', function () {
alert('点击我');
})
})
window.addEventListener('load',function(){
alert('22');
})
document.addEventListener('DOMContentLoaded',function(){
alert('33');
})
//load 事件是等页面内容全部加载完毕,包含DOM元素 图片 flash CSS等
//DOMContentLoaded 是DOM 加载完毕,不包含图片 flash css 等就可以执行 加载速度比load更快一些
</script>
</head>
<body>
<button>点击</button>
</body>
</html>
1.load
事件是等页面内容全部加载完毕,包含DOM元素 图片 flash CSS等
2.DOMContentLoaded
是DOM 加载完毕,不包含图片 flash css 等就可以执行 加载速度比load更快一些
4.调整窗口大小事件
window.onresize
是调整窗口大小的加载事件,当触发时就调用的处理函数
window.onresize = function(){
}
window.addEventener('resize',function(){
})
注意:
- 只要窗口大小发生像素变化,就会触发这个事件
window.innerWidth
当前屏幕的宽度;window.innerHeight
当前屏幕的高度。
<script>
window.addEventListener('resize', function(){
console.log('宽度:' + window.innerWidth);
console.log('高度:' + window.innerHeight);
})
</script>
5.定时器(setTimeout();setInterval())
window
对象给我们提供了两个 定时器
1.setTimeout();
1.setTimeout使用
window.setTimeout(调用函数,'延迟的毫秒数')
setTimeout()
方法用于设置一个定时器,该定时器在定时器到期后执行调用函数
<script>
//1.setTimeout
//语法规范: window.setTimeout(调用函数,延时器);
//1.这个window 在调用的时候可以省略
//2.这个延时时间单位是毫秒 但是可以省略,如果省略默认的是0
//3.调用函数可以直接写函数 也可以写函数名
//4.页面中可能有很多的定时器,我们经常给定时器加标识符(名字)
//例一
setTimeout(function(){
console.log('时间到了!');
},2000);
//例二
function fn(){
console.log('爆炸了!');
}
setTimeout(fn,2000);
setTimeout(fn(),2000);
setTimeout('fn()',2000);
//三种方法都可以调用
var times1 = setTimeout(fn,2000);
var times1 = setTimeout(fn,5000);
</script>
- window可以省略。
- 这个调用函数可以 直接写函数,或者 写函数名 或者采取 ‘字符串函数名()’,三种形式。 第三种不推荐
- 延迟的毫秒数省略默认是0,如果写.必须是毫秒。
- 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符。
- setTimeout()这个调用函数我们也称为回调函数callback
普通函数是按照代码顺序直接调用。而这个函数,需要等待时间,时问到了才去调用这个函数,因此称为回调函数。 - 简单理解:回调,就是回头调用的意思。上一 件事干完,再回头再洞用这个函数。
- 以前我们讲的
element.onclick = function()
或者element.addEventListener("click", fn);
里面的函数也是回调
函数。
2.停止setTimeout()定时器
window.clearTimeot(timeoutID)
参数timeoutID
是定时器的标识符
<button>点击停止定时器</button>
<script>
var times = setTimeout(function(){
console.log('121');
},5000)
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
clearTimeout(times);
})
</script>
2.setInterval();
window.setInterval(回调函数,间隔的毫秒数);
setInterval()
方法重复调用一个函数,每间隔这个时间就会调用一次函数。
1.倒计时案例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
div {
/* width: 200px; */
/* border: 1px solid red; */
margin: 200px auto;
text-align: center;
}
span {
display: inline-block;
width: 40px;
height: 40px;
background-color: #333;
font-size: 20px;
color: red;
text-align: center;
line-height: 40px;
}
</style>
</head>
<body>
<div>
<span class="dates">00</span>
<span class="hour">00</span>
<span class="minute">00</span>
<span class="second">00</span>
</div>
<script>
setInterval(function(){
var dates = document.querySelector('.dates');
var hour = document.querySelector('.hour');
var minute = document.querySelector('.minute');
var second = document.querySelector('.second');
var stopTime = new Date('2022-11-11 00:00:00');
var nowTime = +new Date();
var newTime = (stopTime - nowTime)/1000;
var d = parseInt(newTime/60/60/24);
d = d >= 10 ? d : '0' + d;
var h = parseInt(newTime/60/60%24);
h = h >= 10 ? h : '0' + h;
var m = parseInt(newTime/60%60);
m = m >= 10 ? m : '0' + m;
var s = parseInt(newTime%60);
s = s >= 10 ? s : '0' + s;
dates.innerHTML = d;
hour.innerHTML = h;
minute.innerHTML = m;
second.innerHTML = s;
},1000)
</script>
</body>
</html
2.停止setInterval()定时器
window.clearsetInterval(timeoutID);
案例:
<button class="begin">开始定时器</button>
<button class="stop">停止定时器</button>
<script>
var begin = document.querySelector('.begin');
var stop = document.querySelector('.stop');
var times = null;//全局变量 null是一个空对象
begin.addEventListener('click',function(){
times = setInterval(function(){
console.log('121');
},1000)
},);
stop.addEventListener('click',function(){
clearInterval(times);
});
</script>
案例:
<input type="text"><button>发送</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
var i = 5;
this.disabled = true;
var times = setInterval(function(){
if(i != 0){
btn.innerHTML = '还剩' + i + '秒再次点击';
i--;
}
else{
btn.innerHTML = '发送';
btn.disabled = false;
console.log(1);
clearInterval(times);
//因为setInterval的顶级对象是window,this会指向window,所以改用btn
}
},1000)
})
</script>
6.this指向问题
this
的指向在定义函数的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终指向的是那个调用它的对象。
-
全局作用域或者普通函数中this指向全局 对象
window
(注意定时器里面的this
指向window
)//1.全局作用域或者普通函数中的this指向全局对象Window(定时器里面的this指向的window) console.log(this);//window function fn(){ console.log(this); } fn();//window //window.fn(); window.setInterval(function(){ console.log(this);//window },1000)
-
方法调用中谁调用,this指向谁
<button>点击</button> //2.方法调用中谁调用,this指向谁 var o = { sayHi:function(){ console.log(this);//this指向 o 这个对象 } } o.sayHi(); var btn = document.querySelector('button'); btn.onclick = function () { console.log(this);//this指向的是btn这个按钮对象 }
<button>点击</button> btn.addEventListener('click',function(){ console.log(this);//this指向的是btn这个按钮对象 })
-
构造函数中的this指向构造函数的实例
//3.构造函数中的this指向构造函数的实例
function Fun(){
console.log(this);//a
}
var a = new Fun();
7.js同步和异步
0.概述
JavaScript
语言的一大特点是单线程,也就是说,同一个时间只能做一件事,这是因为JavaScript
这门脚本语言诞生的使命所致,JavaScript
是为处理页面中的用户交互,以及操作DOM而诞生的,比如我们对某一个DOM元素进行操作和删除,不能同时进行,应该先进行添加,之后再删除。
1.单线程问题
单线程就意味着所有任务需要排队,前一个任务结束,才会执行后一个任务,这样所导致的问题就是:如果js执行时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。
<script>
//第一个问题
console.log(1);
setTimeout(function(){
console.log(3);
},10000);
console.log(2);
//如果按照单线程执行 先打印1 等待10秒再打印3 之后再打印2
</script>
未解决这个问题,利用多核CPU的计算能力,HTML5提出了Web Worker标准,允许JavaScript脚本创建多个线程,于是出现了同步和异步。
2.同步
前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的。
3.异步
如果执行一件事所需时间过长,在做这件事的同时,还可以去处理其他事情。
1.同步、异步任务
1.同步任务
同步任务都在主线程上执行,形成一个执行栈,执行栈中存放了同步任务队列
2.异步任务
js的异步是通过回调函数实现的。
常见三种异步任务:
- 普通事件,
click
、resize
。 - 资源加载,
load
、error
。 - 定时器,
setTimeout
、setInterval
。
异步任务相关的回调函数添加到异步任务队列中
3.js的执行机制
- 先执行执行栈中的同步任务。
- 异步任务(回调函数)放入异步任务队列中。
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取异步任务队列中的异步任务,于是读取的异步任务结束等待状态,进入执行栈,开始执行。
执行机制解读:
<script>
console.log(1);
document.onclick = function(){
console.log('click');
}
console.log(2);
setTimeout(function(){
console.log(3);
},3000);
</script>
![](images/QQ截图20221102230608.png)
![](images/QQ截图20221102230932.png)
//1. 先打印1
//2. document.onclick = function 属于异步任务,先提交给异步进程,等待点击鼠标,只有点击鼠标才会放入异步任务队列中。不点击不会放入异步任务队列中。
//3. 再打印2
//4. setTimeout属于异步任务,也是先放到异步任务进程,当3秒时间到了就放入异步任务队列,等同步任务执行完后就将执行异步任务放入执行栈中执行 再打印3
//5.此时点击,触发点击事件 将异步进程放入异步任务队列,然后执行栈检查同步任务是否执行完,执行完后执行点击事件(如果在三秒之前点击就先执行点击事件)
//6.再次点击 将异步进程放入异步任务队列,然后执行栈检查同步任务是否执行完,执行完后执行点击事件
// 尽管同步任务执行完,但是他还是会回到异步任务队列检查是否有异步任务,有,就执行异步任务
// 整个过程称之为任务循环
8.location对象
window
对象给我们提供了一个location
属性用于获取或设置窗体的URL,并且用于解析URL,因为这个属性返回的是一个对象,多一我们将这个属性也称为location
对象
0.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 | 片段 #后面内容 常见于链接 锚点 |
1.location对象常见属性
location对象属性 | 返回值 |
---|---|
location.href | 获取或者设置整个URL |
location.host | 返回主机(域名)www.itheima.com |
location.port | 返回端口号 如果未写返回空字符串 |
location.pathname | 返回路劲 |
location.search | 返回参数 |
location.hash | 返回片段 #后面内容 常见于链接 |
2.location对象的方法
location对象方法 | 返回值 |
---|---|
location.assign() | 跟href一样,可以跳转页面 |
location.replace() | 替换当前页面,因为不记录历史,所以不能后退页面 |
location.reload() | 重新加载页面,相当于刷新按钮或者f5如果参数为true强制刷新Ctrl+f5 |
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
//1.记录浏览历史,可以实现后退
// location.assign('http://www.baidu.com');
//2.不记录浏览历史,不可后退
// location.replace('http://www.baidu.com');
//3.刷新,true是强制刷新,强制刷新是重新替换图片等;false是普通刷新,缓存的内容不会被替换
location.reload(true);
})
</script>
9.navigator对象
navigator对象包含浏览器的信息,它有很多属性,我们最常用的是userAgent,该属性可以返回由客户机发送给服务器的user-agent头部的值
if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
window.location.href = ''; //手机
}
else {
window.location.href = '';//电脑
}
10.history对象
window对象给我们提供了一个history对象,与浏览器历史记录进行交互,该对象包含用户(在浏览器窗口中)访问过的URL。
history对象方法 | 作用 |
---|---|
back() | 后退功能 |
forward() | 前进功能 |
go(参数) | 前进后退功能 参数是1前进一个页面,如果是 -1 后退一个页面。 |
5.PC端网页特效
1.元素偏移量offset
1.概述
offset
偏移量,我们使用offset系列相关属性可以动态的得到该元素的位置(偏移),大小等
-
获得元素距离带有定位父元素的位置
-
获得元素自身的大小(宽度高度)
-
注意,返回的数值都不带单位
offset常见属性:
offset系列属性 | 作用 |
---|---|
element.offsetParent | 返回作为该元素带有定位的父级元素如果父级元素都没有定位则返回body |
element.offsetTop | 返回元素相对带有定位父元素上方的偏移量 |
element.offsetLeft | 返回元素相对带有定位父元素左边框的偏移量 |
element.offsetWidth | 返回自身包括padding、边框、内容区的宽度、返回数值不带单位 |
element.offsetHeight | 返回自身包括padding、边框、内容区的高度、返回数值不带单位 |
注意:父元素没有定位就返回到body的偏移量
2.offset与style的区别
1.offset
- 可以得到任意样式表中的样式(行内,内嵌,外部引用)
- 获得的参数没有单位
offsetWidth
包含padding+border+width
offsetWidth
等属性是只读属性,只能获取不能赋值- 所以获取元素大小和位置红offset更合适
2.style
- 只能得到行内样式表中的样式
- style.width获取的是带有单位的字符串
- style.width获得不包含padding和border的值
- style.width是可读写属性,可以获取也可以赋值
- 所以,给元素更改值,则style更合适
3.案例:
1.模拟框拖拽:
<!DOCTYPE html>
<html>
<head lang="zh-CN">
<meta charset="UTF-8">
<title></title>
<style>
.login-header {
width: 100%;
text-align: center;
height: 30px;
font-size: 24px;
line-height: 30px;
}
ul,
li,
ol,
dl,
dt,
dd,
div,
p,
span,
h1,
h2,
h3,
h4,
h5,
h6,
a {
padding: 0px;
margin: 0px;
}
.login {
display: none;
width: 512px;
height: 280px;
position: fixed;
border: #ebebeb solid 1px;
left: 50%;
top: 50%;
background: #ffffff;
box-shadow: 0px 0px 20px #ddd;
z-index: 9999;
transform: translate(-50%, -50%);
}
.login-title {
width: 100%;
margin: 10px 0px 0px 0px;
text-align: center;
line-height: 40px;
height: 40px;
font-size: 18px;
position: relative;
cursor: move;
}
.login-input-content {
margin-top: 20px;
}
.login-button {
width: 50%;
margin: 30px auto 0px auto;
line-height: 40px;
font-size: 14px;
border: #ebebeb 1px solid;
text-align: center;
}
.login-bg {
display: none;
width: 100%;
height: 100%;
position: fixed;
top: 0px;
left: 0px;
background: rgba(0, 0, 0, .3);
}
a {
text-decoration: none;
color: #000000;
}
.login-button a {
display: block;
}
.login-input input.list-input {
float: left;
line-height: 35px;
height: 35px;
width: 350px;
border: #ebebeb 1px solid;
text-indent: 5px;
}
.login-input {
overflow: hidden;
margin: 0px 0px 20px 0px;
}
.login-input label {
float: left;
width: 90px;
padding-right: 10px;
text-align: right;
line-height: 35px;
height: 35px;
font-size: 14px;
}
.login-title span {
position: absolute;
font-size: 12px;
right: -20px;
top: -30px;
background: #ffffff;
border: #ebebeb solid 1px;
width: 40px;
height: 40px;
border-radius: 20px;
}
</style>
</head>
<body>
<div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div>
<div id="login" class="login">
<div id="title" class="login-title">登录会员
<span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span>
</div>
<div class="login-input-content">
<div class="login-input">
<label>用户名:</label>
<input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
</div>
<div class="login-input">
<label>登录密码:</label>
<input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
</div>
</div>
<div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
</div>
<!-- 遮盖层 -->
<div id="bg" class="login-bg"></div>
<script>
//1.获取元素
var login = document.querySelector('.login');
var mask = document.querySelector('.login-bg');
var link = document.querySelector('#link');
var closeBtn = document.querySelector('#closeBtn');
var title = document.querySelector('#title');
//2.点击弹出
link.addEventListener('click', function () {
mask.style.display = 'block';
login.style.display = 'block';
});
//3.点击closebtn隐藏
closeBtn.addEventListener('click', function () {
mask.style.display = 'none';
login.style.display = 'none';
});
//4.拖拽事件
//1.鼠标按下并且移动之后松开鼠标
//2.触发事件:1.mousedown鼠标按下 2.mousemove鼠标移动 3.mouseup鼠标松开
//3.鼠标的坐标减去鼠标在盒子内的坐标,才是模态框真正的位置。
//(1)
title.addEventListener('mousedown', function (e) {
var x = e.pageX - login.offsetLeft;
var y = e.pageY - login.offsetTop;
console.log(x,y);
document.addEventListener('mousemove', move)
function move(e) {
login.style.left = e.pageX - x + 'px';
login.style.top = e.pageY - y + 'px';
}
document.addEventListener('mouseup',function(){
document.removeEventListener('mousemove',move)
})//这个函数不能写在move函数里面,如果点击就弹起,不进行鼠标移动,然后移动鼠标,就是一直发生拖拽,无法停止,因为没有调用移除事件监听
})
</script>
</body>
<script>
</script>
</html>
2.仿京东放大镜
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.preview_img {
position: relative;
top: 0;
left: 0;
width: 398px;
height: 398px;
border: 1px solid #ccc;
}
.mask {
display: none;
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 300px;
background-color: #fede4f;
opacity: .5;
}
.big {
display: none;
position: absolute;
left: 410px;
top: 0;
width: 500px;
height: 500px;
background-color: pink;
z-index: 999;
border: 1px solid #ccc;
overflow: hidden;
}
.big img {
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div class="preview_img">
<img src="../images/s3.png" alt="">
<div class="mask"></div>
<div class="big">
<img src="../images/big.jpg" alt="" class="bigImg">
</div>
</div>
<script>
var preview_img = document.querySelector('.preview_img');
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
var bigImg = document.querySelector('.bigImg');
//1.鼠标移入显示
preview_img.addEventListener('mouseover', function () {
mask.style.display = 'block';
big.style.display = 'block';
});
preview_img.addEventListener('mouseout', function () {
mask.style.display = 'none';
big.style.display = 'none';
});
//2.将鼠标在父元素内的坐标给遮挡层
preview_img.addEventListener('mousemove', function (e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
//遮罩在x,y轴的范围
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
//遮罩最大移动距离
var maskxMAx = preview_img.offsetWidth - mask.offsetWidth;
if (maskX <= 0) {
maskX = 0;
}
else if (maskX >= maskxMAx) {
maskX = maskxMAx;
}
if (maskY <= 0) {
maskY = 0;
}
else if (maskY >= maskxMAx) {
maskY = maskxMAx;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
//3.大图片的移动距离 = 遮罩移动距离 * 大图最大移动距离 / 遮罩的最大移动距离;
//大图片的最大移动距离
var bigMax = bigImg.offsetHeight - big.offsetHeight;
var bigX = maskX * bigMax / maskxMAx;
var bigY = maskY * bigMax / maskxMAx;
console.log(bigX,bigY);
bigImg.style.top = -bigY + 'px';
bigImg.style.left = -bigX + 'px';
});
</script>
</body>
</html>
2.元素可视区client
client
翻译过来就是客户端,我们使用client
系列的相关属性来获取元素可视区的相关信息。通过client
系列的相关属性可以动态的得到该元素的边框大小、元素大小等。
client系列属性 | 作用 |
---|---|
element.clientTop | 返回元素上边框的大小 |
element.clientLeft | 返回元素左边框的大小 |
element.clientWidth | 返回自身(盒子)包含padding、内容区的宽度、不含边框、返回的数值不带单位 |
element.clientHeight | 返回自身(盒子)包含padding、内容区的高度、不含边框、返回的数值不带单位 |
3.立即执行函数
立即执行函数最大的作用就是独立创建了一个作用域 避免命名冲突 在独立作用域中所有的变量在执行完后都会立即被销毁,所以不会产生命名冲突。
<script>
//1.立即执行函数:不需要调用,立马就能够自己执行的函数
function fn(){
console.log(1);
}
fn();
//2.写法:
//(function(){})(); 或者 (function(){}());
//1.
(function(a,b){
console.log(a + b);
var num = 10;
console.log(num);
})(1,2);//第二个小括号可以看做调用函数
//2.
(function(a,b){
console.log(a + b);
var num = 10;
console.log(num);
}(2,3));
//3.立即执行函数最大的作用就是独立创建了一个作用域 避免命名冲突 在独立作用域中所有的变量在执行完后都会立即被销毁,所以不会产生命名冲突。
</script>
4.scroll系列
scroll
相关属性可以动态得到该元素的大小,滚动距离.
scroll系列属性 | 作用 |
---|---|
element.scrollTop | 返回被卷上去的上侧距离盒子上边框数值,不带单位 |
element.scrollLeft | 返回被卷上去的左侧距离盒子左边框数值,不带单位 |
element.scrollWidth | 返回自身(内容)的实际宽度,含padding,不含边框,不带单位 |
element.scrollHeight | 返回自身(内容)实际的高度,含padding,不含边框,不带单位 |
注意:有内容且内容没有溢出盒子时,返回的是盒子的高度,内容溢出盒子时返回的是内容的高度。
案例:仿京东滚动条案例
- 需要用到页面滚动事件
scroll
,因为是页面滚动,所以事件源是document - 滚动到某个位置,就是判断页面被卷去的部分值
- 页面被卷去的头部:可以通过window.pageYOffset获得,如果被卷去的左侧,window.pageXOffset
- 注意,元素被卷去的头部是element.scrollTop,如果是页面被卷去的头部则是window.pageYOffset
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.slider-bar {
position: absolute;
left: 50%;
top: 300px;
margin-left: 600px;
width: 45px;
height: 130px;
background-color: pink;
}
.w {
width: 1200px;
margin: 10px auto;
}
.header {
height: 150px;
background-color: purple;
}
.banner {
height: 250px;
background-color: skyblue;
}
.main {
height: 1000px;
background-color: yellowgreen;
}
span {
display: none;
position: absolute;
bottom: 0;
}
</style>
</head>
<body>
<div class="slider-bar">
<span class="goBack ">返回顶部</span>
</div>
<div class="header w">头部区域</div>
<div class="banner w">banner</div>
<div class="main w">主体部分</div>
<script>
//1.获取元素
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
var main = document.querySelector('.main');
var span = document.querySelector('span');
var sliderbarOffsetTop = sliderbar.offsetTop;
var bannerOffsetTop = banner.offsetTop;
var mainOffsetTop = main.offsetTop;
//2.页面滚动事件 scroll
document.addEventListener('scroll',function(){
// console.log(window.pageYOffset);
//3.当我们页面被卷去的头部大于等于172,此时侧边栏就要改为固定定位
if(window.pageYOffset >= bannerOffsetTop){
sliderbar.style.position = 'fixed';
sliderbar.style.top = sliderbarOffsetTop - bannerOffsetTop + 'px';
}
else{
sliderbar.style.position = 'absolute';
sliderbar.style.top = '300px';
}
// console.log(main.offsetTop);
//大于main 区域 span元素显示出来
if(window.pageYOffset >= mainOffsetTop){
span.style.display = 'block';
}
else{
span.style.display = 'none';
}
});
</script>
</body>
</html>
5.mouseenter和mouseover的区别
- 当鼠标移动到元素上时就会触发
mouseenter
事件 - 类似
mouseover
,它们两者之间的差别是mouseover
鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter
只会经过自身盒子触发 - mouseenter不会冒泡
mouseenter
鼠标进入,mouseleave鼠标离开。
6.js动画原理
核心原理:通过定时器setInterval()
不断移动盒子位置。
实现步骤:
- 获得盒子当前位置
- 让盒子在当前位置加上1个移动距离
- 利用定时器不断重复这个操作
- 加一个结束定时器的条件
- 注意此元素需要添加定位,才能使用
element.style.left
1.动画函数封装,单独添加定时器,清除重复的定时器
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: absolute;
left: 0;
width: 100px;
height: 100px;
background-color: pink;
}
span {
position: absolute;
left: 0;
top: 150px;
display: block;
width: 150px;
height: 150px;
background-color: purple;
}
</style>
</head>
<body>
<button>点击执行函数</button>
<div></div>
<span></span>
<script>
var div = document.querySelector('div');
var span = document.querySelector('span');
var btn = document.querySelector('button');
//简单动画函数封装 obj目标对象 target目标位置
function animate(obj, target) {
//先清除定时器,再添加定时器
clearInterval(obj.timer);
//给不同元素指定定时器(对象,属性)
obj.timer = setInterval(function fn() {
if (obj.offsetLeft >= target) {
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 100);
}
//调用函数
animate(div, 400);
btn.addEventListener('click', function () {
animate(span, 200);
//此时每点击一次,元素的偏移速度就会加快,解决办法就是先清楚定时器,再添加定时器。
})
</script>
</body>
</html>
2.缓动动画效果原理
缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来。
思路:
- 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
- 核心算法: (目标值 - 现在的位置(offsetLeft)) / 10做为每次移动的距离步长。
- 停止的条件是:让当前盒子位置等于目标位置就停止定时器
匀速动画就是盒子是当前的位置 + 固定的值
缓动动画就是盒 子当前的位置 + 变化的值((目标值-现在的位置) / 10)
注意:缓动动画里目标距离会差一小部分,因为除法有小数,可采用取整来解决。负数向下取整,正数向上取整。
3.回调函数
将函数作为实参传递给形参,然后再调用的方法
<script>
var div = document.querySelector('div');
var span = document.querySelector('span');
var btn = document.querySelector('button');
//简单动画函数封装 obj目标对象 target目标位置
function animate(obj,target,callback) {
//先清除定时器,再添加定时器
clearInterval(obj.timer);
//给不同元素指定定时器(对象,属性)
obj.timer = setInterval(function () {
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
//前进向上取整,后退向下取整;
if (obj.offsetLeft >= target) {
//停止动画
clearInterval(obj.timer);
//回调函数写到定时器结束里面
//判断形参是否存在。
if(callback){
//调用函数
callback();
}
}
obj.style.left = obj.offsetLeft + step + 'px';
}, 100);
}
//调用函数
animate(div, 400);
btn.addEventListener('click', function () {
//回调函数作为实参 传递给形参,然后再调用
animate(span, 200,function(){
console.log('end')//
});
//此时每点击一次,元素的偏移速度就会加快,解决办法就是先清楚定时器,再添加定时器。
})
</script>
7.轮播图
8.节流阀
防止轮播图按钮连续点击造成播放过快。
节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画, 让事件无法连续触发。
核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
//开始设置一个变量
var flag = true;
if(flag){
flag = false;//关闭节流阀
animate(obj,target,function(){
flag = true;//打开节流阀
});
};
6.移动端特效
移动端的浏览器有较好的兼容性,所以不需要考虑浏览器的兼容性并且移动端没有鼠标事件取代的是触摸事件touch
touch事件 | 说明 |
---|---|
touchstart | 手指触摸到一个DOM元素触发 |
touchmove | 手指在DOM元素上移动时触发 |
touchend | 手指在DOM元素上离开时触发 |
1.触摸事件对象touchEvent
touchstart
,touchmove
,touchend
三个事件都会有各自的事件对象
touchstart事件对象
事件 | 说名 |
---|---|
touches | 返回正在触摸屏幕的所有手指的一个列表 |
targetTouches | 返回触摸当前DOM元素上的手指的一个列表 |
changedTouches | 返回手指状态发生改变的列表,从无到有,从有到无变化 |
手指离开屏幕后不会有touches和targetTouches,但是会有changedTouches。
2.移动端拖动元素
- touchstart. touchmove. touchend 可以实现拖动元素
- 但是拖动元素需要当前手指的坐标值我们可以使用targetTouches[0]里面的pageX和pageY
- 移动端拖动的原理:手指移动中 ,计算出手指移动的距离。然后用盒子原来的位置+手指移动的距离
- 手指移动的距离:手指滑动中的位置 减去手指刚开始触摸的位置
拖动元素三步曲:
(1)触摸元素touchstart;获取手指初始坐标,同时获得盒子原来的位置
(2)移动手指touchmove;计算手指的滑动距离,并且移动盒子
(3)离开手指touchend;
注意:手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动e.preventDefault();
触摸事件
<div>
</div>
<script>
var div = document.querySelector('div');
div.addEventListener('touchstart',function(e){
console.log('触摸事件');
// touches 正在触摸所有屏幕的手指列表
console.log(e.targetTouches[0]);
// 返回正在触摸元素的手指信息,比如手指的坐标等
});
div.addEventListener('touchmove',function(){
console.log('滑动事件');
});
div.addEventListener('touchend',function(){
console.log('移动事件');
})
</script>
元素拖拽
<div></div>
<script>
// 1.触摸元素touchstart 获取手指的初始坐标,同时获得盒子原来的位置
// 2.移动手指touchmove 计算手指的滑动距离,并且移动盒子
// 3.离开手指touchend
var div = document.querySelector('div');
// 触摸点的初始坐标
var startX = 0;
var startY = 0;
// 盒子的初始坐标
var x = 0;
var y = 0;
div.addEventListener('touchstart',function(e){
startX = e.targetTouches[0].pageX;
startY = e.targetTouches[0].pageY;
x = this.offsetLeft;
y = this.offsetTop;
});
div.addEventListener('touchmove',function(e){
var moveX = e.targetTouches[0].pageX - startX;
var moveY = e.targetTouches[0].pageY - startY;
this.style.left = moveX + x + 'px';
this.style.top = moveY + y + 'px';
});
</script>
3.classList
classList:返回元素的类名
该属性用于在元素中添加,移除以及切换css类,有以下方法
.bg{
background-color: black;
}
<div class="one tow"></div>
<button>开关灯</button>
<script>
// classList 返回元素的类名 以伪数组的形式存在
var div = document.querySelector('div');
console.log(div.classList);
console.log(div.classList[0]);
console.log(div.classList[1]);
// 1.添加类名 在后面添加类名
div.classList.add('three');
console.log(div.classList);
// 2.移除类名
div.classList.remove('one');
console.log(div.classList);
// 3.切换类 有这个类就清除,没有这个类就添加
var btn = document.querySelector('button');
btn.addEventListener('click',function(){
document.body.classList.toggle('bg');
});
</script>
4.click延时问题
1.禁止页面的缩放。浏览器禁用默认的双击缩放行为,并且去掉300ms的点击延时。
<meta name = 'viewport' content ='user-scalable=no'>
2.touch封装
3.利用fastclick插件解决
7.本地存储
1.本地存储的特性
1、数据存储在用户浏览器中
2.设置、读取方便、甚至页面刷新不丢失数据
3、容量较大,sessionStorage约5M、localStorage约20M
4、只能存储字符串,可以将对象JSON.stringify()编码后存储
2.window.sessionStorage
1.生命周期为关闭浏览器窗口
2.在同一个窗口(页面)下数据可以共享
3.以键值对的形式存储使用
存储数据
sessionStorage.setItem(key,value);
sessionStorage.setItem('uname',val);
获取数据
sessionStorage.getItem(key);
sessionStorage.getItem('uname');
删除单个数据
sessionStorage.removeItem(key);
sessionStorage.removeItem('uname');
删除所有数据
sessionStorage.clear();
3.window.localStorage
1.生命周期永久生效,除非手动删除否则关闭页面也会存在
2.可以多窗口(页面)共享(同一浏览器可以共享)
3.以键值对的形式存储使用
存储数据
localStorage.setItem(key,value);
localStorage.setItem('uname',val);
获取数据
localStorage.getItem(key);
localStorage.getItem('uname');
删除单个数据
localStorage.removeItem(key);
localStorage.removeItem('uname');
删除所有数据
localStorage.clear();