2022最新JavaScript+jQuery笔记
初识JavaScript
浏览器执行js简介
- 渲染引擎:解析css和html
- js引擎:编译js代码,逐行解析
- js是基于对象和事件驱动的松散性,解释性语言。
<script type="null">
alert('我是编程语言,用来控制电脑网页弹出你好'); alert('我是编程语言,用来控制电脑网页弹出你好');
</script>
各个浏览器的js引擎也不相同,所以也会有兼容行问题。
js组成
- EcmaScript:JavaScript基本语法
- DOM:页面文档对象模型(对页面中的文档进行操作)
- BOM:浏览器对象模型(对浏览器窗口做出操作)
书写位置
- 行内式
<!-- 1.行内式的js 直接写到元素内部 -->
<input type="button" value="唐伯虎" onclick="alert('秋香姐')">
- 内嵌式
- 最好放到html下部分
<script>
// alert('沙漠骆驼');
</script>
- 外部
- 结构更加易读。
<!-- 3.外部js写法 双标签 -->
<script src="my.js"></script>
javascript标签中无需写代码,否则会被忽略!
思维导图
JS中 let和var的区别
- ES6 新增了
let
命令,用来声明局部变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束。
先看个var的常见变量提升的面试题目:
题目1:
var a = 99; // 全局变量a
f(); // f是函数,虽然定义在调用的后面,但是函数声明会提升到作用域的顶部。
console.log(a); // a=>99, 此时是全局变量的a
function f() {
console.log(a); // 当前的a变量是下面变量a声明提升后,默认值undefined
var a = 10;
console.log(a); // a => 10
}
// 输出结果:
undefined
10
99
ES6可以用let定义块级作用域变量
在ES6之前,我们都是用var来声明变量,而且JS只有函数作用域和全局作用域,没有块级作用域,所以{}限定不了var声明变量的访问范围。
例如:
{
var i = 9;
}
console.log(i); // 9
ES6新增的let,可以声明块级作用域的变量。
{
let i = 9; // i变量只在 花括号内有效!!!
}
console.log(i); // Uncaught ReferenceError: i is not defined
let 配合for循环的独特应用
let
非常适合用于 for循环内部的块级作用域。JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,用let声明的变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。看一个常见的面试题目:
for (var i = 0; i <10; i++) {
setTimeout(function() { // 同步注册回调函数到 异步的 宏任务队列。
console.log(i); // 执行此代码时,同步代码for循环已经执行完成
}, 0);
}
// 输出结果
10 共10个
// 这里面的知识点: JS的事件循环机制,setTimeout的机制等
如果把 var改成 let声明:
// i虽然在全局作用域声明,但是在for循环体局部作用域中使用的时候,变量会被固定,不受外界干扰。
for (let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i); // i 是循环体内局部作用域,不受外界影响。
}, 0);
}
// 输出结果:
0 1 2 3 4 5 6 7 8 9
let没有变量提升与暂时性死区
用let声明的变量,不存在变量提升。而且要求必须 等let声明语句执行完之后,变量才能使用,不然会报Uncaught ReferenceError错误。
console.log(aicoder); // 错误:Uncaught ReferenceError ...
let aicoder = 'aicoder.com';
// 这里就可以安全使用aicoder
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
let变量不能重复声明
let不允许在相同作用域内,重复声明同一个变量。否则报错:
Uncaught SyntaxError: Identifier 'XXX' has already been declared
例如:
let a = 0;
let a = 'sss';
// Uncaught SyntaxError: Identifier 'a' has already been declared
总结
ES6的let让js真正拥有了块级作用域,也是向这更安全更规范的路走,虽然加了很多约束,但是都是为了让我们更安全的使用和写代码。
字面量
在计算机科学中,字面量(Literal)是在计算机中描述 事/物
javascript是否写分号结尾
- 根据具体情况实际选择
- 写和不写都可以
javaScript输入输出语句
方法 | 说明 | 归属 |
---|---|---|
alert(msg) | 浏览器弹出警示框 | 浏览器 |
console.log(msg) | 浏览器控制台打印输出信息 | 浏览器 |
prompt(info) | 浏览器弹出输入框,用户可以输入 | 浏览器 |
doucument.write() | 页面输出内容,识别标签 | 浏览器 |
注意:
alert
主要用来显示消息给用户,console.log()用来给程序员查看自己运行时的消息。
prompt取过来的值是字符类型的
变量
- 属性值:var(variable的缩写)
- 装数据的盒子
变量语法拓展
- 更新变量:变量值以最后一次赋的值为准
- 同时声明多个变量:声明一个变量后,中间用逗号隔开
- let声明变量
let即关键字(let:允许,许可,让,要),所谓关键字是系统专门提供的用来声明的变量的词语
var myfirstname = 99,
kjlj = 54;
声明变量的特殊情况
情况 | 说明 | 结果 |
---|---|---|
var age;console.log(age); | 只声明不赋值 | undefined(未定义) |
console.log(age); | 不声明,不赋值,直接使用 | 报错 |
age = 10;console.log(age); | 不声明,只赋值 | 10 |
变量的命名规范
- 由
字母,数字,下划线,美元符号
组成 - 严格区分大小写
- 不能以数字开头。18age是错误的
- 不能是
关键字,保留字
命名:var,fo,while - 变量名必须有意义
- 遵循
驼峰命名
,首字母小写,后面单词的首字母大写:myFirstName
- 推荐翻译网站:
有道
常量
- 概念:使用const声明的变量为‘常量’
- 使用场景:当一个变量永远不会改变的时候,使用 const来声明,而不是let.
- 命名规范:和变量一致
注意:常量不允许重新赋值,声明的时候必须赋值(初始化)
小技巧:不需要重新赋值的数值用const
变量声明关键字总结
let - 现在实际开发的声明方式(2022)
var - 以前的声明变量的方式,会有很多问题(2019)
const -类似于let ,但是变量值无法被修改
数据类型
- js的变量数据类型是只有程序在运行过程中,根据等号右边的值来确定的。
- js是动态语言,变量的数据类型是可以变化的。
- typeo检测变量的数据类型
- 可以通过控制台输出的字体颜色来判断到底是哪个字符类型(蓝色,数字;黑色,字符串;灰色 ,未定义)
数据类型的分类
简单数据类型(Number,String,Boolean,Underfined,Null)
引用数据类型(object)
简单数据类型(栈)
简单数据类型 | 说明 | 默认值 | typeof结果 |
---|---|---|---|
Number | 数字型,包含整型值和浮点型值,如:21,0.21 | 0 | |
Booolean | 布尔值类型,如true,false,等价于0,1 | false | |
symbol | 定义的值具有唯一性 | ||
string | 字符串类型 | “” | |
Undefined | var a;声明了变量a,但没有给值,此时a=undefined | undefined | undefined |
Null | var a= null;声明了变量a为空值 | null | object |
数字型Number
- 可以是整数,小数,正数,负数。
- 最常见的有二进制,八进制,十六进制。
isNaN()
:这个方法用来判断非数字,并且返回一个值,如果是数字返回 false ,如果不是返回的是true。
特殊值
Infinity
,无穷大-Infinity
, 无穷小Number.Max_Value
,数字型最大值Number.Min_Value
,数字型最小值NaN
,缩写:not a number,代表一个非数值
//1.八进制 0~7
var num1 = 010;
console.log(num1);
//2.十六进制 0~9 a~f
var num2 = 0x9;
console.log(num2);
//数字型最大值
console.log(Number.MAX_VALUE);
//无穷大
console.log(Number.MAX_VALUE * 2); //Infinity
//数字型的最小值
console.log(Number.MIN_VALUE);
//无穷小
console.log(Number.MIN_VALUE * 2); //-Infinity
//非数字 NaN
NaN代表一个计算错误。它是一个不正确的或者未定义的数学操作所到的的结果
NaN是
粘性
的。任何对NaN的操作都会返回NaN
在Js中八进制前面加
0
,十六进制前面加0X
未定义类型(undefined)
未定义是比较特殊的类型,只有一个值 undefined.
- 什么情况下出现未定义类型
只声明变量,不赋值的情况下,变量默认值为 undefined,一般很少【直接】为某个变量赋值为
字符串型String
- 字符串可以是引导中的任意文本,其语法为双引号(“ ”),和单引号(' ')或反引号包裹的数据( ``` `)
html
使用双引号,js推荐使用单引号- 字符串嵌套(外单内双)
| 转义符 |解释说明|
|:-----😐:------😐
| \n | 换行符|
| \ |斜杠|
| '|'单引号|
| ''|''双引号|
| \t|tab缩进|
| \b|空格,b是blank的意思|
注意事项:
- 引号必须成对出现
- 单引号和双引号可以相互嵌套,口诀
外双内单,或者外单内双
- 必要时可以使用转义符
\
,输出单引号或双引号
引用数据类型(堆)
- 包括:
1、对象(Object)类型,是一组由键、值组成的无序集合;数据类型 object
2、数组(Array)类型,是一组按顺序排列的数据的集合;数据类型 object
3、函数(Function)类型,是一段具有特定功能的代码块。数据类型 function
字符串拼接
引号拼接字符串(ES5)
场景:+运算符可以实现字符串的拼接。
口诀:数字相加,字符相连
<script>
//1.检测获取字符串的长度 length
var str = 'my name is andy';
console.log(str.length); //15
//2.字符串拼接+,'数值相加,字符相连'
console.log('沙漠' + '骆驼');
console.log('小李' + 18 + '岁');
var age = 18;
console.log('小李' + age + '岁');
console.log(24 + 24); //48
</script>
模板字符串(ES6)
- 使用场景:
拼接字符串和变量
在没有它之前,要拼接字符串比较麻烦 - 语法
反引号··
内容拼接变量时,用${}
包住变量
<script>
let age = 18
document.write(`我今年${age}岁了`)
var nan = 10 ,nv = 44;
console.log(`本班男生${nan}人,女生${nv}人,共计${nan + nv}人`);
</script>
数据类型的转换
隐式转换
某些运算符(除加法四则运算),if条件
被执行时,系统内部自动将数据类型进行转换,这种转换称为隐式转换。
- 规则:
+
号两边只要有一个是字符串,就会把另外一个转成字符串(拼接
)
除了+以外的算术运算符,比如 - * /等都会把数据转换成数据类型。 - 缺点
转换类型不明显,靠经验总结 - 小技巧
+
号作为正号解析可以转换成字符串类型
任何数据和字符串相加的结果都是字符串
加法:操作数是number型;
操作数是undefined,null,boolean,隐式调用
Number()进行数据类型的转换
强制转换
转换为字符串
方式 | 说明 | 案例 |
---|---|---|
toString() | 转换成字符串 | var vm = 1;alert(num.toString()) |
String()强制转换 | 转换成字符串 | var num =1;slert(String(num)); |
加号 拼接字符串 | 和字符串拼接的结果都是字符串 | var num =1;alert(num+"我是字符串") |
<script>
// 1.把数字类型转换为字符串型 变量.toString()
var num = 10;
var str = num.toString();
console.log(str);
console.log(typeof str);
// 2.利用String(变量)
console.log(String(num));
//3.利用+拼接字符串的方法实现转换效果,隐式转换
console.log(num + '');
</script>
转换为数字型(重点)
方式 | 说明 | 案例 |
---|---|---|
parselnt(string) | 将stirng类型转成整数数值型 | parselnt('78') |
parseFloat(string) | 将string类型转换成浮点数数值型 | parseFloat('78.21') |
Number()强制转换函数 | 将string类型转换成数值型 | Number('12') |
js隐式转换(. * / ) | 利用算数运算隐式转换为数值型 | '12'-0 |
转换为布尔型
- 代表
空,否定的值
会被转换成false
,如''(空字符串)
,0
,NAN
,null
,underfined
- 其余值都会转换成true
- 隐式转换:
- 有字符串的加法
""+1
,结果是"1"
- 减法 - (像大多数运算一样)只能用于数字,它会使空字符串""转换为 0
- null经过数字转换后会变为
0
- underfined经过数字转换后会变为
NaN
| 方式 |说明|案例|
|:-----😐:------😐:------😐
| Boolean()函数|其他类型转换成布尔值|Boolean('true')|
运算符
前置递增
- 变量先加一,然后返回结果
var num = 0
++num
后置递增
- 先表达式返回原值,后面变量再自加一
var num = 0
num++
比较运算符
运算符名称 | 说明 | 案例 | 结果 |
---|---|---|---|
== | 判断号(会转型) | 37 == 37 | true |
=== !== | 全等要求值和数据类型都一致 | 37 === ‘37’ | false |
逻辑运算符
逻辑运算符号 | 说明 | 案例 |
---|---|---|
&& | 逻辑与,and | true&&false |
|| | 逻辑或,or | true||or |
! | 逻辑非,not | !true |
逻辑中断
- 短路运算的原理:当有多个表达式时,左边的表达式可以确定结果时,就不再继续运算右边表达式的值;
逻辑与
- 语法:表达式1&&表达式2
- 如果第一个表达式值为真,则返回表达式2
- 如果第一个表达式值为假,则返回表达式1
逻辑或
- 语法:表达式1 | | 表达式2
- 如果第一个表达式值为真,则返回表达式1
- 如果第一个表达式值为假,则返回表达式2
赋值运算符
- 概念:用来把数据赋值给变量的运算符
| 赋值运算符号 |说明|案例|
|:-----😐:------😐:------😐
| = |直接赋值|var user='sss'|
| +=,-= |加,减一个数后再赋值|var age=10;age+=5;//5|
| * =,/=,%= |乘,除,取模后赋值|var age=2;age * =5//10 |
运算符优先级
优先级 | 运算符 | 顺序 |
---|---|---|
1 | 小括号 | () |
2 | 一元运算符 | ++,-,! |
3 | 算数运算符 | 先 * / %后+ - |
4 | 关系运算符 | > >= < <= |
5 | 相等运算符 | == != === !== |
6 | 逻辑运算符 | **先&& 后 |
7 | 赋值运算符 | = |
8 | 逗号运算符 | . |
注意:
&&
的权重比||
高
不同数字类型运算符之间的操作
比较运算符 : > ,< >= , <= ,== ,!=, =, !,返回值是布尔类型
- 都是number型,大小进行比较
- 都是string型,按位按照
ASCII表
[1]进行比较- number,string :隐式调用Number()把string 转为number进行计算
==
:值相等===
:值相等,数据类型相同
console.log(2 > "100"); //false "100"转为 100 与2进行比较
console.log("234" > "100"); //true 这种比较为ASCII码比较,依次取每个字符,字符转为ASCII码进行比 较
console.log("15" > "9"); //false
console.log(15 > 9); //ture
console.log(12 == "12"); //true
console.log(1 == true); //ture Number(true)转换成1
console.log(0 === false); //false
console.log(0 == undefined); //false Number(undefined)转换成NaN
console.log(0 == ""); //true
console.log(0 == " "); //true
算术运算符:+,-,*,/,%,++,--,**
console.log(1 + 133); //134
console.log(1 + "133"); //1133
console.log(1 - "133"); //-132
console.log(1 - "abc"); //NAN 直接是非数字类型
逻辑运算符:隐式调用Boolean()判断真假
0
,false
,null
,undefined
,NaN
,""
这些为假&&
:返回第一个假值,运用(短路原则)
会返回第一个假值||
: 返回第一个真值(短路原则)
var num = 10, bool = true, str = "abc";
console.log(num && bool && 0); //0
console.log(num && str); //"abc"
console.log(bool && str); //"abc"
console.log(0 && str); //0
console.log(false && num); //false
console.log(undefined && num); //undefined
console.log(str && false); //false
console.log(0 && ""); //0
console.log("" && 0); // ""
console.log(num || bool || 0); //10
console.log(num || str); //10
console.log(bool || str); //true
console.log(0 || str); //"abc"
console.log(false || num); //10
console.log(undefined || num); //10
console.log(str || false); //10
console.log(0 || ""); //"" 没真值,只能返回第二个
console.log("" || 0); //0
取反:!
真变假
,假变真
var num = 10, bool = true, str = "abc";
console.log(!true); //false
console.log(!0); //true
console.log(!str); //false
短路的代码不会执行
console.log(str && num++); //10 && 期望返回第一个假值,没有假值,就返回最后一个真值,两个都是真值,返回第二个num++
console.log(num); //11
console.log(false && ++num); //false
console.log(num); //11 被短路的代码不运行了,所以还是11
console.log(num++ || 0); //11 最后做自增运算 12
console.log(0 || ++num); //13
console.log(0 || str > num); //fales 返回 str>num 的结果NaN
console.log(num); //13
表达式和语句
- 表达式:
表达式是可以被求值的代码,javaScript引擎会计算出一个结果
let x = 7
3+4
num++
- 语句;
语句是一段可以执行的代码。
比如:prompt( )可以弹出一个输入框,还有if语句 for循环语句等等
区别:
表达式:表达式可以被求值,所以它可以写在赋值语句的右侧
语句:而语句不一定有值,比如alert()for 和break等语句就不能用于赋值。
流程控制
- 顺序结构
- 分支结构
- 根据不同的条件,执行不同的路径,得到不同的结果。
if语句
<script>
//1. if 的语法结构
// if (条件表达式) {
// //执行语句
// }
if (3 > 5) {
alert('沙漠骆驼');
}
</script>
案例(判断闰年)
- 算法:可以被4整除且不能整除100的为润年或者可以被400整除的就是润年
三元表达式
条件表达式?表达式1:表达式2
- 如果条件表达式结果为正,则返回表达式一的值,否则返回表达式二的值
数字补零案例
<script>
var time = prompt('输入数字')
var resule = time < 10 ? '0' + time : time;
alert(resule);
</script>
switch语句
- switch语句是多分支语句,可以实现多对一。
<script>
switch (表达式) {
case value1:
执行语句1;
break;
case value2:
执行语句2;
break;
default:
执行最后的语句
}
在判断条件中,条件为真的情况
- 如果是数字:0是否,1是真
- 如果是字符串:字符串不空是真,字符串空是假
if/else和switch的区别
- 一般情况下可以相互替换
- switch...case语句通常在处理case为比较确定值的情况,而if...else..语句更加灵活,通常用与范围判断(大于,等于某个范围)
- switch语句进行条件判断后直接执行程序的条件语句,效率更高是。而if...else.语句有几种条件,就得判断多次。
- 分支比较小的情况下,if...else语句执行效率比switch高。
- 分支比较多的情况下,switch语句执行效率高,而且结构清晰。
- 循环结构
- 执行规律任务,重复执行多次语句
for循环
掌握 for 循环语句,让程序具备重复执行能力
for
是 JavaScript 提供的另一种循环控制的话句,它和 while
只是语法上存在差异。
for语句的基本使用
- 实现循环的 3 要素
<script>
// 1. 语法格式
// for(起始值; 终止条件; 变化量) {
// // 要重复执行的代码
// }
// 2. 示例:在网页中输入标题标签
// 起始值为 1
// 变化量 i++
// 终止条件 i <= 6
for(let i = 1; i <= 6; i++) {
document.write(`<h${i}>循环控制,即重复执行<h${i}>`)
}
</script>
-
变化量和死循环,
for
循环和while
一样,如果不合理设置增量和终止条件,便会产生死循环。 -
跳出和终止循环
<script>
// 1. continue
for (let i = 1; i <= 5; i++) {
if (i === 3) {
continue // 结束本次循环,继续下一次循环
}
console.log(i)
}
// 2. break
for (let i = 1; i <= 5; i++) {
if (i === 3) {
break // 退出结束整个循环
}
console.log(i)
}
</script>
结论:
JavaScript
提供了多种语句来实现循环控制,但无论使用哪种语句都离不开循环的3个特征,即起始值、变化量、终止条件,做为初学者应着重体会这3个特征,不必过多纠结三种语句的区别。- 起始值、变化量、终止条件,由开发者根据逻辑需要进行设计,规避死循环的发生。
- 当如果明确了循环的次数的时候推荐使用
for
循环,当不明确循环的次数的时候推荐使用while
循环
注意:
for
的语法结构更简洁,故for
循环的使用频次会更多。
循环嵌套
利用循环的知识来对比一个简单的天文知识,我们知道地球在自转的同时也在围绕太阳公转,如果把自转和公转都看成是循环的话,就相当于是循环中又嵌套了另一个循环。
实际上 JavaScript 中任何一种循环语句都支持循环的嵌套,如下代码所示:
// 1. 外面的循环 记录第n天
for (let i = 1; i < 4; i++) {
document.write(`第${i}天 <br>`)
// 2. 里层的循环记录 几个单词
for (let j = 1; j < 6; j++) {
document.write(`记住第${j}个单词<br>`)
}
}
记住,外层循环循环一次,里层循环循环全部
倒三角
// 外层打印几行
for (let i = 1; i <= 5; i++) {
// 里层打印几个星星
for (let j = 1; j <= i; j++) {
document.write('★')
}
document.write('<br>')
}
九九乘法表
样式css
span {
display: inline-block;
width: 100px;
padding: 5px 10px;
border: 1px solid pink;
margin: 2px;
border-radius: 5px;
box-shadow: 2px 2px 2px rgba(255, 192, 203, .4);
background-color: rgba(255, 192, 203, .1);
text-align: center;
color: hotpink;
}
javascript
// 外层打印几行
for (let i = 1; i <= 9; i++) {
// 里层打印几个星星
for (let j = 1; j <= i; j++) {
// 只需要吧 ★ 换成 1 x 1 = 1
document.write(`
<div> ${j} x ${i} = ${j * i} </div>
`)
}
document.write('<br>')
}
while循环
- 条件为true,执行循环语句,否则推出循环
do while循环
- do while循环其实是while循环的一个变体,该循环会先执行一次代码块,然后对条件表达式进行判断,如果为真,就会重复执行循环体,否则退出循环。
continue关键字
- 用于立即跳出本次循环,继续下一次循环(本次循环中,continue之后的代码就会少执行一次)
break关键字
- 立即跳出整个循环(循环结束)
数组(Array)
知道什么是数组及其应用的场景,掌握数组声明及访问的语法。
- 数组就是一组数据的集合,存储在单个变量下的优雅方式。
- 数组里面的数据一定要逗号隔开
- 数组里面的数据比如,1,2,我们称为数组元素。
- 任意数据类型都可以放入
- 数组在 JavaScript 中并不是新的数据类型,它属于对象类型。
<script>
// 1. 语法,使用 [] 来定义一个空数组
// 定义一个空数组,然后赋值给变量 classes
// let classes = [];
// 2. 定义非空数组
let classes = ['小明', '小刚', '小红', '小丽', '小米']
</script>
通过 []
定义数组,数据中可以存放真正的数据,如小明、小刚、小红等这些都是数组中的数据,我们这些数据称为数组单元,数组单元之间使用英文逗号分隔。
创建数组
- 利用new 创建数组
<script>
var arry = new Array(); //创建了个一空数组
</script>
- 利用数组字面量创建数组
<script>
var arr = []; //创建了一个空数组
var arr1 = [1, 2, 'pingk老师', true];
//数组里面的数据一定要逗号隔开
//数组里面的数据比如,1,2,我们称为数组元素。
</script>
- 进阶
<script>
var arr = new Array(2);//这个2表示数组长度为2,里面有两个空值
var arr1 = new Array(2,3);//等价于[2,3]
console.log(arr1);
</script>
获取数组元素
1.数组的索引
- 下标:用来访问数组元素的序号(数组下标从零开始)
console.log(arr1[2]);
检测数组方法
- Instanceof 运算符 它可以用来检测是否是数组
<script>
var arr = [];
var obj ={};
console.log(arr instanceof Array);//true
console.log(ogj instanceof Array);//false
</script>
- Array.isArray(参数);H5新增的方法,ie9以上版本支持
console.log(Array.isArray(arr));//true
遍历数组
<script>
var arr = ['red', 'green', 'blue'];
for (var i = 0; i <= 2; i++) {
console.log(arr[i]);
}
</script>
案例(求数组最大值)
<script>
var max = 1;
var arr = [1, 2, 3, 66, 78, 234, 123, 12, 345, 435];
for (var i = 0; i <= arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
console.log(max);
案例(数组转换为分割字符串)
<script>
var str = '';
var arr = ['red', 'blue', 'green'];
var step = '|'
for (var i = 0; i < arr.length; i++) {
str += arr[i] + step;
}
console.log(str);
</script>
数组长度
- 数组名后面加.length属性可以得到数组长度;
- 数组长度是元素个数,不要跟索引号混淆;
- arr.length是动态检测数组元素的个数;
<script>
var arr = ['red', 'green', 'blue'];
for (var i = 0; i <= arr.length; i++) {
console.log(arr[i]);
}
</script>
数组新增元素
- 可以通过修改length长度新增数组元素。
<script>
var arr = ['red', 'blue', 'green'];
console.log(arr.length);
arr.length = 5; //数组长度修改为5
console.log(arr);//修改后最后两个元素没有给值,所以是undefined
</script>
- 可以通过修改数组索引新增数组元素(追加数组元素)
<script>
var arr1 = ['red', 'blue', 'green'];
arr1[3] = 'pink';
console.log(arr1);
arr1[0] = 'yellow'; //替换原来的数组元素
</script>
筛选数组
- 方法一
<script>
var arr = [2, 0, 1, 22, 121, 454, 3, 35, 435, 45];
var newArry = [];
var j = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] >= 10) {
newArry[j] = arr[i];
j++;
}
}
console.log(newArry);
</script>
- 方法二
- 注意:方法二用新数组的长度来代替方法一中的j变量;
<script>
var arr1 = [2, 0, 1, 22, 121, 454, 3, 35, 435, 45];
var newArry1 = [];
for (var i = 0; i < arr.length; i++) {
if (arr1[i] >= 10) {
newArry1[newArry1.length] = arr[i];
}
}
console.log(newArry1);
</script>
操作数组
数组做为对象数据类型,不但有 length
属性可以使用,还提供了许多方法:
- push 动态向数组的尾部添加一个单元
- unshit 动态向数组头部添加一个单元
- pop 删除最后一个单元
- shift 删除第一个单元
- splice 动态删除任意单元
使用以上4个方法时,都是直接在原数组上进行操作,即成功调任何一个方法,原数组都跟着发生相应的改变。并且在添加或删除单元时 length
并不会发生错乱。
<script>
// 定义一个数组
let arr = ['html', 'css', 'javascript']
// 1. push 动态向数组的尾部添加一个单元
arr.push('Nodejs')
console.log(arr)
arr.push('Vue')
// 2. unshit 动态向数组头部添加一个单元
arr.unshift('VS Code')
console.log(arr)
// 3. splice 动态删除任意单元
arr.splice(2, 1) // 从索引值为2的位置开始删除1个单元
console.log(arr)
// 4. pop 删除最后一个单元
arr.pop()
console.log(arr)
// 5. shift 删除第一个单元
arr.shift()
console.log(arr)
</script>
冒泡排序
- 是一种算法,把一系列的数据按照一定的顺序进行排列显示(从小到大,或者从大到小),一次比较两个元素,如果顺序错误就把他们交换过来,走访数列的工作是重复进行的,直到没有需要再交换,也就是说该数列已经排序完成。
<body>
<script>
let arr = [6, 23, 1, 56, 78, 86]
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
//开始交换
if (arr[j] > arr[j + 1]) {
//交换两个变量
let temp = arr[j + 1]
arr[j + 1] = arr[j]
arr[j] = temp
}
}
}
console.log(arr);
</script>
</body>
注意:一共需要的趟数是 arr. length-1,每一趟需要交换的次数是 arr.length -i - 1。i是外侧循环
数组重要方法操作
<script>
var arr = [1, 2, 3, 4, 5]
console.log(arr);
// forEach 遍历
arr.forEach(function (v, i) {
// console.log(v);
// console.log(i);
})
//push向数组末尾添加一个或者多个元素,会改变原数组
arr.push("a", "b", "10")
console.log(arr);
//every() 当元素全部满足条件的时候返回true,有一个不满足就会返回false
var result = arr.every(function (v, i) {
return v > 5;
})
//some()只要有一个满足就返回true
console.log(result);
var result1 = arr.some(function (v, i) {
return v > 5;
})
console.log(result1);
//splice(位置(元素下标),删除的元素个数) 删除 会影响原数组
arr.splice(2, 2)
console.log(arr);
//findIndex返回满足条件的元素,首次出现的位置 ,如果没有就返回-1
var result2 = arr.findIndex(function (v, i) {
return v == 5;
})
console.log(result2);
//join() 把数组转换成字符串,不会影响原数组
console.log(arr.join("-"));
//filter() 过滤 返回满足条件的元素,构成新数组
var result3 = arr.filter(function (v, i) {
return v < 5;
})
console.log(result3);
//map() 映射
var result4 = arr.map(function (v, i) {
return v * 4
})
console.log(result4);
</script>
函数
- 封装了一段可以重复执行的代码块
- 实例(求num1~num2的累加和)
<script>
//函数
function getSum(num1, nmu2) {
var sun = 0;
for (var i = num1; i <= nmu2; i++) {
sun += i;
}
console.log(sun);
}
getSum(1, 100)//调用函数
</script>
函数分类
具名函数
funcation fn(){}
fn()
匿名函数
没有名字的函数,无法直接使用。
使用方式:
- 函数表达式
将匿名函数赋值给一个变量,并且通过变量名称进行调用,我们称这个为函数表达式
。
语法:
let fn = function(){
//函数体
}
- 立即执行函数
场景介绍:避免全局变量之间的污染
语法:
//方式一
(function () { console.log(11); }());
//方式二
(function () { console.log(11); })();
//不需要调用,立即执行
(function (x, y) { console.log(x + y); })(1, 2);
注意:多个立即执行函数需要用分号
;
隔开
注意:
函数表达式和具名函数不同,如果是具名函数,那它的调用
可以用在任何位置
(函数体上下都可以)
函数表达式不行,因为let
的关系,只能在声明
后才可以调用
。
函数使用
- 声明函数
<script>
function 函数名() {
函数体
}
</script>
- funcation是声明函数的关键字,全部小写
- 函数是做某件事情,函数名一般是动词
- 函数不调用自己不执行
- 调用函数
- 调用函数时,一定不要忘记添加小括号!
函数名();
函数的参数
形参
- 在声明函数的小括号里面是形参(形式上的参数)
- 形参是用来接受实参的,形参类似于变量(不用声明的变量)
function 函数名(形参1, 形参2...) {
}
实参
- 在函数调用的小括号里是实参(实际的参数)
函数名(实参1, 实参2...);
函数形参和实参匹配问题
<script>
function getSum(num1, nmu2) {
console.log(num1 + num2);
}
getSum(1, 2); //实参个数和形参个数一致,正常输出结果
getSum(1, 2, 3); //实参个数多于形参的个数,会取到形参的个数
getSum(1); //形参可以看作是不用声明的变量, num2是一个变量但是没有接收值 结果就是undefined
</script>
注意:
- 实参多于形参, 多的不参与运算,多的会保存到
arguments对象
中(数组类型
)- 实参少于形参,少的就时undefined
retuen语句
- 函数只是实现某种功能,最终的结果需要返回函数的调用者,通过return实现的
retuen 终止函数,retuen后面的代码不会被执行
。
function 函数名() {
return 需要返回的结果;
}
function fn() {
return 20;
}
console.log(fn())
注意:当函数(fn)调用时,相当于调用者 fn( ) = 返回值
console.log( fu( ) )才能拿着到20
函数有返回值时,就返回该值,没有返回值就返回 undefined
arguments使用
- arguments对象中存储了传递过来的实参。
- argunmets是伪数组:1.具有数组的length属性,按照索引的方式进行存储。
- 可以按照数组的方式遍历arguments
作用域
- javaScript作用域:就是代码名字在某个范围内起作用和效果,是为了提高程序的可靠性,更重要的是减少命名冲突。
作用域(es5)分为两种
-
全局作用域:整个script标签,或者是单独的js文件
全局有效
-
局部作用域(函数作用域):在函数内部就是局部作用域,这个代码的名字就只在函数内部起效果。
局部有效
注意:
变量有一个坑
如果函数内部,变量没有声明,直接赋值,也会当全局变量来看,但是强烈不推荐。
变量的作用域
- 全局变量:在全局作用下的变量分为
用var声明
的和不用var声明的(不推荐)
- 局部变量:在局部作用域下的变量,后者在函数内部的变量就是局部变量,
形参属于局部变量
执行效率
全局变量
只有浏览器关闭时才会销毁
,比较占用内存资源
局部变量
当程序执行完毕就会销毁
,节约内存
资源
块级作用域
- 现阶段我们js,我们没有块级作用域(2015年已经有了ES6)
- es6后新增块级作用域
作用域链(就近原则
)
- 内部函数访问外部函数的变量,采取的是链式查找的方式来决定值,这种结构我们称为作用域链
变量的访问原则
- 只要是代码,就至少有一个作用域
- 写在函数内部的局部作用域
- 如果函数中还有函数,那么在这个作用域中就可以诞生一个作用域
- 访问原则:
在能够访问到的情况下,先局部,局部没有在找全局
js预解析
- 我们js引擎运行js分为两步:
预解析
代码执行
- 预解析:js引擎会把js里面所有的
var
还有funcation提升到当前作用域的最前面
,进行提前声明和定义. - 代码执行:按照代码书写顺序从上往下执行
- 预解析分为变量预解析(变量提升)和函数预解析(函数提升)
- 变量提升:就是把所有变量的声明提升到当前作用域的最前面,不提升赋值操作
- 函数提升:就是把所有
函数声明提升
到当前作用域提升前面,不调用函数。
<script>
console.log(num); //错误
var num = 10;
//相当于执行以下代码
var num;
console.log(num);
num = 10;
</script>
<script>
fun(); //错误
var fun = function() {
console.log(22);
}
//相当于执行以下代码
var fun;
fun();
fun = function() {
console.log(22);
}
</script>
<script>
//案例一
var num = 10;
fun();
function fun() {
console.log(num);//undefined
var num = 20;
}
//相当于执行以下操作
var num;
function fun() {
var num;
console.log(num);
num = 20;
}
num = 10;
fun();
</script>
<script>
//案例二
var num = 10;
function fn() {
console.log(num);
var num = 20;
console.log(num);
}
fun();
//相当于执行以下操作
var num;
function fn() {
var num;
console.log(num); //undefinde
num = 20;
console.log(num); //20
}
num = 10;
fun();
</script>
alert(a); //a函数
var a = 1;
alert(a); //1
function a() {
return false;
}
//相当于执行
var a;
function a(){
return false;
}
alert(a);
a = 1;
alert(a);
注意:
同级时,
函数的优先级高于变量
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a); //undefined
console.log(b); //9
var a = '123';
}
//相当于执行
var a ;
funcation f1(){
var b;
var a;
b = 9;
console.log(a);
console.log(b);
a = '123';
}
f1();
面试题(价值高)
<script>
//案例四
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);
}
//相当于执行以下操作
function f1() {
var a;
a = b = c = 9;
//相当于 var a=9 ; b = 9 ; c = 9 ;b和c没有 var声明,当全局变量来看
//集体声明 var a = 9 ,b =9, c = 9;
console.log(a); //9
console.log(b); //9
console.log(c); //9
}
f1();
console.log(c); //9
console.log(b); //9
console.log(a); //报错 undefined
</script>
js对象
- 什么是对象:对象是一个具体的事物。
- 在js中,对象是一组无序的相关属性和方法的集合
创建对象的三种方式
- 利用字面量创建对象
- 就是用
花括号{}
里面包含了表达这个具体事物的对象和方法。
<script>
var obj = {
uname: '李宇',
age: 18,
sex: '男',
sayHi: function drink() {
console.log('drink');
}
}
console.log(obj.age);
</script>
- 利用
new object
创建对象
- 利用等号赋值的方法,添加对象的属性和方法。
- 每个属性和方法之间用分号结束。
var obj1 = new Object();
obj1.uname = 'zzkj';
obj1.age = 18;
ocj1.sex = 'bna';
obj1.sayh = function() {
console.log(hi);
}
console.log(obj1.uname);
console.log(obj1['sex']);
obj1.sayh();
- 创建对象实例
function Star(uname, sex) {
this.uname = uname;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
var ldh = new Star('刘德华', '男'); //调用函数返回对象。
ldh.sing('并与');
- 利用
构造函数
创建对象
- 为啥需要用到构造函数?:以上两种方法一次只能创建一个对象。
- 构造函数就是把对像里面的相同的属性和方法抽象出来封装到函数里面。
- 规范:
构造函数首字母要大写
。 - 构造函数不需要return,就可以返回结果。
function 构造函数名() {
this.属性 = 值;
this.方法 = function() {}
}
new 构造函数名();
变量,属性,函数,方法的区别
- 存储位置有区别,变量的基本数据类型存储在栈内存、变量的函数和对象存储在堆内存(存疑)
- 变量:单独声明赋值,单独存在
- 属性:对象里面的变量称为属性,不需要声明,用来描述该对象的特征
- 函数:单独存在的了,通过“函数名()”的方法就可以调用,方法用来描述该对象的行为和功能。
new 关键字
new在执行时会做的四件事情
<script>
//1.构造函数在内存中创建了一个空的对象
//2.this 就会指向刚才创建的空对象
//2.执行构造函数里面的代码,给这个空对象添加属性和方法。
//4.返回这个对象。
function Star(uname, sex) {
this.uname = uname;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
var ldh = new Star('刘德华', '男'); //调用函数返回对象。
ldh.sing('并与');
</script>
遍历对象
- 使用for in遍历
<script>
var obj = {
name: 'pink老师',
age: 18,
sex: '男',
fn: function() {}
}
// for in 遍历我们的对象
for (var k in obj) {
console.log(k); //k代表的属性名,方法名
console.log(obj[k]); //得到的是里面的属性值
}
</script>
内置对象
javaScript中的对象
- 分三种:自定义对象,内置对象,浏览器对象
- 前两种对象是js基础内容,属于EcMAScript;第三个浏览器对象属于我们js独有的,我们JSAPI讲解
什么是内置对象
- 内置对象就是指Js语言里面自带的一些对象,这些对象供给开发者使用,并提供了一些常用的或是最基本而必要的功能(属性或者方法)
- 内置对象最大的优点就是帮助我们快速开发
- javaScript提供了多种内置对象:Math,Date,Array,String等
查阅文档
exec 内置对象
exec() 方法用于检索字符串中的正则表达式的匹配。
如果字符串中有匹配的值返回该匹配值,否则返回 null。
- 语法
RegExpObject.exec(string)
参数 | 描述 |
---|---|
string | Require The string to be searched |
- 实例
var str="Hello world!";
//查找"Hello"
var patt=/Hello/g;
var result=patt.exec(str);
document.write("返回值: " + result);
//查找 "RUNOOB"
patt=/RUNOOB/g;
result=patt.exec(str);
document.write("<br>返回值: " + result);
- 输出
Returned value: Hello
Returned value: null
Math内置对象
- Math对象是一个静态对象,不用new ,直接使用就可以。
<script>
console.log(Math.PI); //圆周率
console.log(Math.max(1, 9, 3, 4)); //9
console.log(Math.max(-1, -10)); //-1
console.log(Math.max(-1, 'pingk')); //NAN
console.log(Math.max()); //-Inginity
</script>
封装自己的数学对象(最大最小值案例)
<script>
var Mymath = {
PI: 3.141592653,
max: function() {
var max = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
},
min: function() {
var min = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] < min) {
min = arguments[i];
}
}
return min;
}
}
console.log(Mymath.PI);
console.log(Mymath.max(1, 5, 9));
console.log(Mymath.min(1, 5, 9));
</script>
Math绝对值和三个取整方法
Math.abs绝对值
console.log(Math.abs(1)); //1
console.log(Math.abs(-1)); //1
console.log(Math.abs('-1')); //隐式转换,会把字符串型-1转换成1
console.log(Math.abs('pink')); //NAN
Math.floor()向下取整 往小了的取值
Math.floor() //向下取整 往小了的取值
Math.ceil()向上取整,往最大了取值
Math.ceil() //向上取整,往最大了取值
Math.round()四舍五入
- 注意:其他数字都是四舍五入,但是 .5 特殊,它往大了取。
console.log(Math.round(1.9)); //2
console.log(Math.round(-1.5)); //这个结果是-1
console.log(Math.round(-1.6)); //这个结果是-2
Math.random()随机数
- 返回一个随机的小数 0=< x <1
- 这个方法不需要参数
- 代码验证
console.log(Math.random());
取两个数之间的随机整数,包括这两个数(重要)
- 公式:Math.floor(math.random() * (max - min + 1)) + min;
<script>
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));
//5.随机点名
var arr = ['这姑娘三', '里斯', '李书记', '时看见立刻'];
console.log(arr[getRandom(1, 3)]);
</script>
猜数字游戏(案例)
<script>
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var random = getRandom(1, 10);
while (true) {
//死循环
var num = prompt('你来猜');
if (num > random) {
alert('你猜大了');
} else if (num < random) {
alert('你猜小了');
} else {
alert('你猜对了!');
break;//跳出循环
}
}
Date日期对象
- 注意:Date() 日期对象,是一个构造函数,必须使用new 来调用创建我们的日期对象
- date处理日期和时间
- 获取当前时间必须实例化
var arr = new Array(); //创建了一个数组对象
var obj = new Object(); //创建了一个对象实例
//1. 使用Date,没有参数,返回当前系统的当前时间
var date = new Date();
console.log(date);
- Date()构造函数的参数
- 如果括号里面有时间,就返回参数里面的时间。例如日期格式字符串为'2019-5-1',可以写成new Date('2019-5-1')或者new Date('2019/5/1')
//2. 参数常用写法,数字型 2019 ,10 , 01或者是 字符串类型 '2019-10-1 8:8:8'
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);
Date.getFullYear():年
- 返回当年
Date.getMonth():月
- 获取当月(0-11)
- 返回的月份小一个月
console.log(date.getMonth() + 1);
Date.getDate():日
- 返回的是几号
var datas = date.getDate();
Date.getDay():星期几
- 返回周几(周0到周六)
var day = date.getDay();
- 显示当前时间(案例)
var date = new Date();
//2022年3月9日星期三
var year = date.getFullYear();
var moth = date.getMonth() + 1;
var datas = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六', ];
var day = date.getDay();
console.log('今天是:' + year + '年' + moth + '月' + datas + '日 ' + arr[day]);
- 输出效果
今天是:2022年3月9日星期三
Date.getHours():时
Date.getMinutes():分
Date.getSeconds():秒
返回当前时分秒案例:格式 08:08:08
function getTime() {
var time = new Date();
var h = time.getHours();
var h = h < 10 ? '0' + h : h;
var m = time.getMinutes();
var m = m < 10 ? '0' + m : m;
var s = time.getSeconds();
return h + ':' + m + ':' + s;
var s = s < 10 ? '0' + s : s;
}
console.log(getTime());
Date总的毫秒数(时间戳)
- 获得Date总的毫秒数(时间戳),不是当前时间的毫秒数,而是距离1970年1月1日过了多少毫秒数
- 通过ValueOf( ) getTIme()
倒计时案例
- 核心分析:输入时间减去现在时间就是剩余时间,即倒计时,但是不能拿着时分秒相减,比如05分减去25分,结果会是负数。
- 用时间戳来做,用户输入时间总毫秒减去现在时间的总毫秒数,得到的就是剩余时间的毫秒数。
- 把剩余时间总毫秒数转换成天,时,分,秒
- 转换公式
| 计算公式 |解释说明|
|:-----😐:------😐
| d = parselnt(总秒数/60/60/24)| 计算天数|
| h = parselnt(总秒数/60/60%24) |计算小时|
| m = parselnt(总秒数/60%60)|计算分数|
| s = parselnt(总秒数%60)|计算当前秒数|
<script>
function conutDown(time){
var nowTime = +new Date();//返回当前时间总毫秒数
var inputTime = +new Date(time);//返回用户输入时间总的毫秒数
var times = (inputTime - nowTime)/1000;//剩余时间总的秒数
var d = parseInt(times/60/60/24);
d = d<10?'0'+d:d;
var h = parseInt(times/60/60%24);
h = h<10?'0'+h:h;
var m = parseInt(times/60%60);
m = m<10?'0'+m:m;
var s = parseInt(times%60);
s = s<10?'0'+s:s;
return d+'天'+h+'时'+m+'分'+s+'秒';
}
console.log(conutDown('2022-3-10 22:00:00'));
</script>
数组对象
添加删除数组元素的方法(重点)
方法名 | 说明 | 返回值 |
---|---|---|
push(参数1...) | 末尾添加一个或者多个元素,注意修改原数组 | 并返回新的长度 |
pop() | 删除数组最后一个元素,把数组长度减1无参数,修改原数组 | 返回它删除的元素的值 |
unshift(参数1...) | 向数组的开头添加一个或者多个元素,注意修改原数组 | 并返回新的长度 |
shift() | 删除数第一个元素,把数组长度减1无参数,修改原数组 | 并返回第一个元素的值 |
var arr = [1,2,3];
// 尾添加
// arr.push(4,'liyu');//push添加末尾
console.log(arr.push(4,'liyu'));//5
console.log(arr);//输出数组
//头添加
console.log(arr.unshift('red','purple'));
// arr.unshift('red','purple');
console.log(arr);
//尾删除,一次只能删除一个元素
//返回删除的那个元素
console.log(arr.pop());
console.log(arr);
//头删除,一次只能删除一个元素
console.log(arr.shift());
console.log(arr);
筛选数组(案例,运用数组对象)
- 代码
<script>
var arr= [1500,1200,2100,1800];
var newArry = [];
for (var i = 0;i<arr.length;i++){
if(arr[i]<2000){
newArry.push(arr[i]);
}
}
console.log(newArry);
</script>
- 输出结果
(3) [1500, 1200, 1800]0: 15001: 12002: 1800length: 3[[Prototype]]: Array(0)
数组排序
方法名 | 说明 | 是否修改原数组 |
---|---|---|
reverse() | 颠倒数组中元素的顺序,无参数 | 该方法会改变原来数组,返回新数组 |
sort() | 对数组元素进行排序 | 该方法会改变原来数组,返回新数组 |
<script>
//翻转数组
var arr = ['pink','red','pink']
arr.reverse();
console.log(arr);
//数组排序(冒泡排序)
var arr1=[1,3,4,2,5,6];
arr1.sort(function(a,b){
// return a - b;//按照升序排序
return b - a;//按照降序排序
});
console.log(arr1);
</script>
注意:当使用 b-a 时,说明后面的大,是降序。使用a-b时,说明前面大,是升序(默认)
数组索引方法
方法名 | 说明 | 返回值 |
---|---|---|
indexOf() | 数组中查找给指定元素的第一个索引 | 如果存在,返回索引号,如果不存在,则返回-1 |
lastIndex() | 在数组中的最后一个索引 | 如果存在返回索引号 如果不存在,则返回-1 |
<script>
//它只返回第一个满足条件的索引号
var arr = ['red','blue','pink','blue']
console.log(arr.indexOf('blue'));//返回1
console.log(arr.indexOf('green'));//返回-1
console.log(arr.lastIndexOf('blue'));//返回3
console.log(arr.lastIndexOf('green'));//返回-1
</script>
数组去重(重点案例)
- 目标:把旧数组里面不重复的元素选取出来放到新数组中,重复的元素只留一个,放到新数组中去重。
- 核心原理:遍历旧数组,然后拿着旧数组元素去查询新数组,如果该元素在新数组没有,则添加
<script>
// var arr = ['c','a','x','a','c','b','z','c','c'];
function unique(arr){
var newArry = [];
for (var i = 0;i< arr.length;i++){
if(newArry.indexOf(arr[i]) === -1){
newArry.push(arr[i]);
}
}
return newArry;
}
var demo = unique(['c','a','x','a','c','b','z','c','c'])
console.log(demo);
</script>
数组转换成字符串
方法名 | 说明 | 返回值 |
---|---|---|
toString() | 把数组转换成字符串,逗号分隔没一项 | 返回一个字符串 |
join('分隔符') | 方法用于把数组中得到所有元素转换成一个字符串 | 返回一个字符串 |
- 代码示例
<script>
//1.toString数组转换为字符串
var arr = [1,2,3];
console.log(arr.toString());//1,2,3
//2.join(分隔符)
console.log(arr.join('-'));
</script>
- 输出结果
1,2,3
数组转换为字符串.html:13 1-2-3
基本包装类型
- 把简单数据类型包装为复杂数据类型,基本数据类型就有了属性和方法。
- 下面代码有什么问题?
//基本包装类型
var str = 'andy';
console.log(str.length);
//对象才有属性和方法,复杂数据类型里才有属性和方法
//简单数据类型里为何有length属性呢?
- 实际执行过程
//(1)把简单数据类型包装为复杂数据类型
var temp = new String('andy');
//(2)把临时变量值给str
str = temp;
// (3) 销毁这个临时变量
temp = null;
字符串对象
字符串不可变
- 指的是里面的值不可变,虽然看似可以改变内容,但其实地址变了,内存中开辟了一个内存空间.
- 因为我们字符串的不可变,所以不要大量拼接字符串.
根据字符返回位置
方法名 | 说明 |
---|---|
indexOf('要查找的字符',开始的位置) | 返回指定内容,在元字符串中的位置,如果找不到就返回-1,开始的位置是Index索引号 |
LastIndexOf() | 从后往前找,只找第一个匹配的 |
<script>
//字符串对象 根据字符串返回位置 str.indexOf('要查找的字符串',[起始位置])
var str = '改革春风吹满地,春天来了';
console.log(str.indexOf('春'));//2
console.log(str.indexOf('春',3));//8
</script>
返回字符位置(案例)
- 返回字符串"scjlkdodfsooadsjosdfa''中所有o出现的位置以及次序.
- 核心算法:
- 先查找第一个o出现的位置
- 然后只要indexOf()返回的结果不是-1,就继续往后查找
- 因为IndexOf只能查找第一个,所以后面查找,利用第二个参数,当前索引加1,从而继续查找.
<body>
<script>
var str = "abscedsljposdfosdsof";
var index = str.indexOf('o');
console.log(index);
while(index != -1){
console.log(index);
str.indexOf('o',index+1);
}
</script>
</body>
根据位置返回字符串(重点)
方法名 | 说明 | 使用 |
---|---|---|
charAt(index) | 返回指定位置的字符(index 字符串的索引号) | str.charAt(0) |
charCodeAt(index) | 获取指定位置处字符的ASCII码(index索引号) | str.charCodeAt(0) |
str[index] | 获取指定位置处字符 | HTML5,IE8支持,和charat(等效) |
<script>
//1. charAt('index')
var str = 'andy';
console.log(str.charAt(3));
//遍历所有字符
for(var i=0;i<str.length;i++){
console.log(str.charAt(i));
}
//2.charCodeAt(index)返回相应索引号的字符ASCII值,目的:判断用户按下哪个键
console.log(str.charCodeAt(0)); //97
//3.str[index] H5新增
console.log(str[0]);//a
</script>
统计出现次数最多的字符
<script>
//用一个对象来判断是否
// var o = {
// age:18
// }
// if (o['age']) {
// console.log('里面有属性');
// }else{
// console.log('里面没有此属性');
// }
var str = 'asfHKjkajdkfjakjhfkjahdf';
var o = {};
for (var i= 0;i<str.length;i++){
var chars = str.charAt(i)//chars是字符串的每一个字符
if(o[chars]){
o[chars]++;
}else{
o[chars] = 1;
}
}
console.log(o);
var max = 0;
var ch = '';
//遍历对象
for(var k in o){
//k得到的数属性名
//o[k]得到的是属性值
if(o[k] >max){
max = o[k];
ch = k;
}
}
console.log(k+':'+max);
</script>
- 输出结果
ObjectH: 1K: 1a: 4d: 2f: 4h: 2j: 5k: 4s: 1[[Prototype]]: Object
h:5
字符串的操作方法
方法名 | 说明 |
---|---|
concat(st) | concat()方法用于连接两个或者多个字符串,拼接字符串,等效于+,+更常用 |
substr(start,length) | 从start位置开始(索引号),length取的个数,重点记住这个 |
slice(start,end) | 从start位置开始,截取到end位置,end取不到(他们两都是索引号) |
substring(start,end) | 从start位置开始,截取到end位置,end取不到,基本和slice相同,但是不接受负值 |
replace('被替换字符','替换为的字符') | 它只会替换第一个字符 |
split('分割符') | 字符转换为数组,前面我们学过join把数组转换成字符串 |
replace('被替换字符','替换为的字符') | 它只会替换第一个字符 |
toUpperCase() | 转换大写 |
toLowerCase() | 转换小写 |
简单数据类型和复杂数据类型导读
简单数据类型与复杂数据类型
- 简单类型又叫基本数据类型或者值类型,复杂类型又叫做引用类型
- 值类型:简单数据类型/基本数据类型,在存储变量中存储的是值本身,因此叫做值类型,string ,number,boolean,undefined,null;
- 引用类型:复杂数据对象,在存储时变量中存储仅仅是地址(引用),因此叫做引用数据类型,通过new 关键字创建的对象(系统对象,自定义对象),如Object,Array,Date等
堆和栈
- 简单数据类型放到栈里面,里面直接开辟一块内存空间,存放的是值
- 复杂数据类型,首先在栈里面存放地址,十六进制表示,然后这个地址指向堆里面的数据。
简单数据类型传参
- 函数形参可以看作变量,当我们把一个值类型变量作为参数传给函数形参时,其实是把变量在栈空间里的值负值了一份给形参,那么在方法内部对形参做任何修改都不会影响到外部变量。
复杂数据类型传参
- 函数形参可以看作变量,当我们把一个引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的的是同一个堆地址,所以操作的是同一个对象。
Web APls
前阶段是学的js基础,这个阶段是DOM,BOM
- Web APIs是js的应用,大量使用JS基础语法做交互效果
API
- 理解:API是给程序员提供的一种工具,以便更轻松的实现想要完成的功能。
Web API
- Web AP:是浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM)
- 主要针对浏览器做交互效果
- 一般都有输入和输出,很多都是方法
DOM
- 文档对象模型(document Object Model)是处理可扩展标记语言(HTML或者XML)的标准接口,可以改变网页的内容,结构和样式。
DOM树
- 文档:一个页面就是一个文档,DOM中用document表示
- 元素:页面中的所有标签就是元素,DOM中使用element表示
- 节点:网页中的所有内容都是节点(标签,属性,文本,注释等),DOM中使用node表示。
- DOM把以上内容都看做对象
- DOM树
获取元素
根据ID获取
getELementById
script写到标签下面
- get获得element元素by通过驼峰命名法
- 参数id是大小写敏感的字符串
- 返回的是一个元素对象
- console.dir 打印我们返回的元素对象 更好的查看里面的属性和方法。
<body>
<div id = "time">2019-09-09</div>
<script>
var timer = document.getElementById('time');
console.log(timer);
console.log(typeof timer);
console.dir(timer);
</script>
</body>
- 返回结果
2019-09-09
object
div#time
getElementsByTagName
- 返回的是 获取过来元素对象的
集合
,以伪数组的形式存储
- 如果页面中只有一个li返回都是伪数组
- 页面中没有这个元素,返回的是空的伪数组
- 还可以获取某个元素(父元素)内部所有指定标签名的子元素。
- 注意:父元素必须是单个对象(必须指明是哪个元素对象)。获取的时候不包括父元素自己。
<body>
<ul>
<li>支付方式覅哈哈1</li>
<li>支付方式覅哈哈2</li>
<li>支付方式覅哈哈3</li>
<li>支付方式覅哈哈4</li>
<li>支付方式覅哈哈5</li>
</ul>
<ol id="ol">
<li>支付方式1</li>
<li>支付方式2</li>
<li>支付方式3</li>
<li>支付方式4</li>
<li>支付方式5</li>
</ol>
<script>
//1. 返回的是 获取过来元素对象的集合,一伪数组的形式存储
var list = document.getElementsByTagName('li');
console.log(list);
console.log(list[0]);
//2. 依次打印里面的元素对象
for(var i=0;i<list.length;i++){
console.log(list[i]);
}
//3.如果页面中只有一个li返回都是伪数组
//4.页面中没有这个元素,返回的是空的伪数组
//5.element.getElementsByTagName('标签名')
// var ol = document.getElementsByTagName('ol')
var ol = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));
</script>
</body>
通过html5新增的方法获取 (getElementsByClassName)
getElementsByClassName
:根据类名获得某些元素的集合querySelector
:返回指定选择器的`第一个元素对象.切记,里面的选择器要加符号: .box #navquerySelectorAll
:返回指定选择器的所有对象的集合
<body>
<div class="box">盒子1</div>
<div class="box">盒子2</div>
<div id="nav">
<ul>
<li>产品</li>
<li>产品</li>
</ul>
</div>
<script>
var box = document.getElementsByClassName('box');//返回伪数组
console.log(box);
var firstBox = document.querySelector('.box');
console.log(firstBox);
var nav = document.querySelector('#nav')
console.log(nav);
var li = document.querySelector('li')
console.log(li);
var allBox = document.querySelectorAll('.box');
console.log(allBox);
</script>
</body>
获取body和html标签
获取body标签
var bodeEle = document.body;
console.log(bodeEle);
console.dir(bodeEle);
获取html元素
var htmlEle = document.documentElement;
console.log(htmlEle);
事件
事件三要素
- 事件源:事件被触发的对象
- 事件类型:鼠标点击触发,鼠标经过,键盘按下
- 事件处理程序:通过函数赋值的方式 完成
<body>
<button id="btn">离开家离开</button>
<script>
var btn = document.getElementById('btn')
btn.onclick = function(){
alert('点秋香');
}
</script>
</body>
操作元素
- javaScript的DOM操作会改变网页内容,结构和样式,我们可以利用DOM操作元素来改变元素里面的内容。
改变元素的内容
属性 | 说明 |
---|---|
element.innerText | 从起始内容到终点内容,但它去除html标签,同时空格和换行也会去掉 |
element.innerHTML | 起始位置到终点位置的全部内容,包含html标签,同时保留空格和换行(W3C推荐) |
<body>
<button>显示当前时间</button>
<div>某个时间</div>
<p>11243</p>
<script>
//点击按钮,div里面会变化
var btn = document.querySelector('button');
var div = document.querySelector('div');
btn.onclick = function () {
div.innerText = getDate();
}
function getDate() {
var date = new Date();
//2022年3月9日星期三
var year = date.getFullYear();
var moth = date.getMonth() + 1;
var datas = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六',];
var day = date.getDay();
return '今天是:' + year + '年' + moth + '月' + datas + '日 ' + arr[day];
}
//获取标签
var p = document.querySelector('p');
p.innerText = getDate();
</script>
</body>
操作元素修改元素属性
- innerText,innerHTML改变元素内容
- src,href
- id,alt,title
柏林,莫斯科案例(随便瞎起的,别当真,俄罗斯和德国打不起来的)
<style>
img {
display: block;
}
</style>
<body>
<button id="p1">图片一</button>
<button id="p2">图片二</button>
<img src="./1.jpg" alt="老照片" title="柏林">
<script>
var p1 = document.getElementById('p1');
var p2 = document.getElementById('p2');
var img = document.querySelector('img');
p2.onclick = function () {
img.src = './2.jpg';
img.title = '莫斯科';
}
p1.onclick = function () {
img.src = './1.jpg';
img.title = '柏林';
}
</script>
</body>
分时间案例
- 注意:innerHTML赋值要注意,第一次弄错了!
<style>
img {
width: 300px;
}
div {
margin-top: 12px;
height: 13px;
font-size: 16px;
}
</style>
<body>
<img src="./1.jpg" alt="">
<div>上午好</div>
<script>
var img = document.querySelector('img');
var div = document.querySelector('div');
var date = new Date();
var h = date.getHours();
if (h < 12) {
img.src = './2.jpg';
// div.innerHTML('好好写代码')错误写法!!!
div.innerHTML = '好好写代码'
} else if (h < 18) {
img.src = './1.jpg';
div.innerHTML = '下午好好写代码';
} else if (h < 24) {
img.src = './2.jpg';
div.innerHTML = '晚上好好写代码';
}
</script>
</body>
表单元素的属性操作
- 利用DOM可以操作如下表单属性
- type, value, checked,selected,disabled;
<body>
<button>按钮</button>
<input type="text" value="输入内容">
<script>
//1.获取元素
var btn = document.querySelector('button');
var input = document.querySelector('input');
//2.注册事件
btn.onclick = function () {
// input.innerHTML = '点击了'; 不起作用
//表单里面的值是通过value修改的
input.value = '点击了';
//如果想让某个表单被禁用,不能点击用disabled我们想要这个按钮button按钮
// btn.disabled = true;
// this 是指向事件函数的调用者btn
this.disabled = true;
}
</script>
</body>
仿京东隐藏显示隐藏密码明文案例
- 示例代码
<style>
.box {
width: 400px;
border-bottom: 1px solid #ccc;
margin: 100px auto;
}
.box input {
width: 370px;
height: 30px;
border: 0;
outline: none;
}
</style>
<body>
<div class="box">
<button>显示</button>
<input type="password" name="" id="pwd">
</div>
<script>
var btn = document.querySelector('button');
var input = document.getElementById('pwd')
var flag = 0;
btn.onclick = function () {
if (flag == 0) {
input.type = 'text';
btn.innerHTML = '隐藏';
flag = 1;
} else {
input.type = 'password';
btn.innerHTML = '显示';
flag = 0;
}
}
</script>
</body>
操作元素-修改样式属性
- 我们可以通过JS修改元素的大小,颜色,位置等样式。
| 属性 |说明|使用情况|
|:-----😐:------😐:------😐
| element.style| 行内样式操作|样式少,功能简单可以使用|
| element.className | 类名样式操作|样式多,功能复杂使用|
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
}
</style>
<body>
<div></div>
<script>
var div = document.querySelector('div');
div.onclick = function () {
//里面的属性采取驼峰命名法
this.style.backgroundColor = 'red';
this.style.width = '300px';
}
</script>
</body>
注意
:1.JS里面的样式采取驼峰
命名,比如:fontSize. 2.JS修改style样式操作,产生的是行内样式,css权重比较高。
仿淘宝二维码案例
<style>
.box {
position: relative;
height: 88px;
border: 1px solid #ccc;
margin: 100px auto;
font-size: 12px;
text-align: center;
color: #f40;
}
.box img {
width: 60px;
margin-top: 5px;
}
.close-btn {
position: absolute;
top: -1px;
left: 16px;
width: 14px;
height: 14px;
border: 1px solid #ccc;
line-height: 14px;
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
cursor: pointer;
}
</style>
<body>
<div class="box">
<img src="./1.jpg" alt="">
<div class="close-btn">x</div>
</div>
<script>
var box = document.querySelector('.box');
var btn = document.querySelector('.close-btn');
btn.onclick = function () {
box.style.display = 'none';
}
</script>
</body>
显示隐藏文本框内容
属性 | 说明 |
---|---|
onfocus | 获得焦点 |
onblur | 失去焦点 |
<body>
<input type="text" value="手机">
<script>
//1.获取元素
var text = document.querySelector('input');
text.onfocus = function () {
// console.log('得到了焦点');
if (this.value === '手机') {
this.value = '';
}
//获得焦点需要变黑(文字)
this.style.color = '#333';
}
text.onblur = function () {
// console.log('失去了焦点');
if (this.value === '') {
this.value = '手机';
}
his.style.color = '#999';
}
</script>
</body>
使用className修改样式属性
- 使用className可以修改大量属性,不同于style(只可以修改单个属性)
- 样式少,功能简单可以使用style
- 样式多,功能复杂使用className
- 注意:要先把修改后的样式写在css里,后调用!
className
会直接覆盖
原来的类名,如果想要保存原来的类名
<style>
.first {
width: 300px;
height: 300px;
background-color: pink;
}
.change {
background-color: purple;
color: #fff;
font-size: 25px;
margin-top: 100px;
}
</style>
<body>
<div class="first">文本</div>
<script>
var text = document.querySelector('div');
text.onclick = function () {
// this.style.backgroundColor = 'skyblue';
//当前元素的类名改为change
this.className = 'change';//注意不加点
// 如果想要保存原来的类名
this.className = 'fisrt change';
}
</script>
</body>
密码框验证信息(案例)
<style>
div {
width: 600px;
margin: 100px auto;
}
.message {
display: inline-block;
font-size: 12px;
color: #999;
background: url() no-repeat left center;
padding-left: 20px;
}
.wrong {
color: red;
background-image: url();
}
</style>
<body>
<div class="register">
<input type="password" class="ipt">
<p class="message">请输入6~16位密码</p>
</div>
<script>
var ipt = document.querySelector('.ipt');
var message = document.querySelector('.message');
ipt.onblur = function () {
//根据表单里面
if (this.value.length < 6 || this.value.length > 16) {
message.className = 'wrong message';
message.innerHTML = '您输入的位数不对';
}
}
</script>
</body>
排他思想(算法)
- 先排除其他人的样式,然后再设置自己的样式。
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
var btn = document.getElementsByTagName('button');
//btn得到的是为数组,里面的每个一元素btn[i]
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
//1.先把所有按钮的背景颜色去掉
for (var i = 0; i < btn.length; i++) {
btn[i].style.backgroundColor = '';
}
//2.让当前背景颜色为pink
this.style.backgroundColor = 'pink';
}
}
</script>
</body>
表格隔行变色效果
- 新的鼠标事件
| 属性 |说明|
|:-----😐:------😐
| onmouseover| 鼠标经过|
| onmouseout |鼠标离开|
表单全选取消全选案例
- 全选和取消全选的做法:让下面所有复选框的checked属性(选中状态)跟随,全选按钮即可
<script>
// 1. 全选和取消全选做法: 让下面所有复选框的checked属性(选中状态) 跟随 全选按钮即可
// 获取元素
var j_cbAll = document.getElementById('j_cbAll'); // 全选按钮
var j_tbs = document.getElementById('j_tb').getElementsByTagName('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.getArrtibute('属性');
- 设置属性值
- element.属性值 = '值'
- element.setAttribute('属性','值') 主要针对自定义属性
- 移除属性
- removeAttribute('属性')
- 区别:
- element.属性 获取内置属性值(元素本身自带的属性)
- element.getAttribute('属性');主要获得自定义的属性(标准)我们程序员自定义的属性
<body>
<div id="demo" index="1" class="nav"></div>
<script>
var div = document.querySelector('div');
// 1. 获取元素的属性值
// (1) element.属性
console.log(div.id);
//(2) element.getAttribute('属性') get得到获取 attribute 属性的意思 我们程序员自己添加的属性我们称为自定义属性 index
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
// 2. 设置元素属性值
// (1) element.属性= '值'
div.id = 'test';
div.className = 'navs';//改的是div的class
// (2) element.setAttribute('属性', '值'); 主要针对于自定义属性
div.setAttribute('index', 2);
div.setAttribute('class', 'footer'); // class 特殊 这里面写的就是class 不是className
// 3 移除属性 removeAttribute(属性)
div.removeAttribute('index');
</script>
</body>
Tab栏切换布局分析(重点案例)
- 排他思想重点了解
<div class="tab">
<div class="tab_list">
<ul>
<li class="current">商品介绍</li>
<li>规格与包装</li>
<li>售后保障</li>
<li>商品评价(50000)</li>
<li>手机社区</li>
</ul>
</div>
<div class="tab_con">
<div class="item" style="display: block;">
商品介绍模块内容
</div>
<div class="item">
规格与包装模块内容
</div>
<div class="item">
售后保障模块内容
</div>
<div class="item">
商品评价(50000)模块内容
</div>
<div class="item">
手机社区模块内容
</div>
</div>
</div>
<script>
// 获取元素
var tab_list = document.querySelector('.tab_list');
var lis = document.querySelectorAll('li');
var item = document.querySelectorAll('.item');
//for循环绑定点击事件
for (var i = 0; i < lis.length; i++) {
//给某 个li设定索引号
lis[i].setAttribute('index', i);
lis[i].onclick = function () {
//干掉所有人,其余的li清楚class这个类
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
}
//留下我自己
this.className = 'current ';
//下面模块显示内容
var index = this.getAttribute('index');
// console.log(index);
//排他思想,让其余item这些div隐藏
for (var i = 0; i < item.length; i++) {
item[i].style.display = 'none';
}
item[index].style.display = 'block';
}
}
</script>
H5自定义属性
- 目的:是为了保存和使用数据,有些数据可以保存到页面中而不用保存到数据库中.
1. 设置H5自定义属性
- H5规定自定义属性data-开头为属性名,并且赋值
- 比如:< div data-index='1'> < /div>
- 使用JS设置
- element.setAttribute('data-index',2);
2.获取H5自定义属性
- 兼容性获取 element.getAttribute('data-index');
- H5新增element.dataset.index 或者 element.dataset['index']** ie 11** 才开始支持
<div getTime="20" data-index="2" data-list-name="andy"></div>
<script>
var div = document.querySelector('div');
// console.log(div.getTime);//自定义属性不能取到
console.log(div.getAttribute('getTime'));
div.setAttribute('data-time', 20);
console.log(div.getAttribute('data-index'));
console.log(div.getAttribute('data-list-name'));
// h5新增的获取自定义属性的方法 它只能获取data-开头的
// dataset 是一个集合里面存放了所有以data开头的自定义属性
console.log(div.dataset);
console.log(div.dataset.index);
console.log(div.dataset['index']);
// 如果自定义属性里面有多个-链接的单词,我们获取的时候采取 驼峰命名法
console.log(div.dataset.listName);
console.log(div.dataset['listName']);
</script>
节点操作(页面中所有内容都算节点)
- 利用节点的父子关系获取元素
逻辑性强,兼容性差
- 网页中所有元素都是节点,在DOM中,节点使用node表示
HTML,DOM树
中的所有节点都可以通过javaScript来进行访问,所有的html都可以被修改,也可以被创建和删除.
节点概述
一般的,节点至少拥有node Type(节点类型)
,nodename(节点名称)
和nodeValue(节点值)
这3个基本属性
- 元素节点 nodeType为1
- 属性节点nodeType为2
- 文本节点 nodeType为3(文本节点包含文字,空格,换行等)
- 实际操作时元素节点
节点层级
夫级节点
<script>
// 1. 父节点 parentNode
var erweima = document.querySelector('.erweima');
// var box = document.querySelector('.box');
// 得到的是离元素最近的父级节点(亲爸爸) 如果找不到父节点就返回为 null
console.log(erweima.parentNode);
</script>
子节点
- DOM 提供的方法(API)获取
- 子节点 childNodes 所有的子节点 包含 元素节点 文本节点等等
- children 获取所有的子元素节点 也是我们实际开发常用的
<script>
// DOM 提供的方法(API)获取
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
// 1. 子节点 childNodes 所有的子节点 包含 元素节点 文本节点等等
console.log(ul.childNodes);
console.log(ul.childNodes[0].nodeType);
console.log(ul.childNodes[1].nodeType);
// 2. children 获取所有的子元素节点 也是我们实际开发常用的
console.log(ul.children);
</script>
节点操作之第一个子节点和最后一个子节点
- firstChild返回第一个子节点,不管是文本还是元素节点
- firstElemtChild
返回第一个子元素节点
,ie9才支持,找不到就返回null - lastElementChild
返回最后一个子元素
<body>
<ol>
<li>我是li1</li>
<li>我是li2</li>
<li>我是li3</li>
<li>我是li4</li>
<li>我是li5</li>
</ol>
<script>
var ol = document.querySelector('ol');
// 1. firstChild 第一个子节点 不管是文本节点还是元素节点
console.log(ol.firstChild);
console.log(ol.lastChild);
// 2. firstElementChild 返回第一个子元素节点 ie9才支持
console.log(ol.firstElementChild);
console.log(ol.lastElementChild);
// 3. 实际开发的写法 既没有兼容性问题又返回第一个子元素
console.log(ol.children[0]);
//最后一个元素的索引号
console.log(ol.children[ol.children.length - 1]);
</script>
</body>
ie9以上才支持
兄弟节点
属性 | 说明 | 兼容性 |
---|---|---|
node.nextSibling | 下个兄弟节点 | 都可以使用 |
node.previousSibling | 上个兄弟节点 | 都可以使用 |
node.nextElementSibling |
下个兄弟(元素)节点 | IE9才支持 |
node.previousElementSibling | 上个兄弟(元素)节点 | IE9才支持 |
var div = document.querySelector('div');
console.log(div.nextSibling);
console.log(div.previousSibling);
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);//unll
如何解决兼容性问题
- 答:自己封装一个兼容性函数
function getNextElementSibling(element) {
var el = element;
while (el = el.nextSibling) {
if (el.nodeType === 1) {
return el;
}
}
return null;
}
获取首位元素几点(避免兼容性问题)
解决方法:
如果想要第一个元素的子节点,可以使用parentNode.children[0]
如果想要最后一个子元素节点,可以使用parentNode.childern[parentNode.chilren.length - 1]
创建节点
- 这些元素原先不存在,是根据我们的需求
动态产生
的,所以我们也称为动态创建元素节点
。
- 创建节点元素节点
var li = document.createElement('li');
括号内的参数里面永远是标签名比如
li
,div
,p
,span
- 添加节点 node.appendChild(child) node 父级 child 是子级
后面
追加元素 类似于数组中的push
ul.appendChild(li);
- 添加节点 node.insertBefore(child, 指定元素);
- 将一个节点添加到父节点的
指定节点
的前面
,类似于css里面的before伪元素。
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
- 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
发布留言案例
- 留言后没有时间
<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('抱歉,没有输入内容')
} else {
// console.log(text.value);
var li = document.createElement('li');
li.innerHTML = text.value;
ul.insertBefore(li, ul.children[0]);
}
}
</script>
</body>
- 留言后有时间显示,可以对留言进行删除,且有按键监听,按下
s
光标定到输入框,按下enter
留言发布。
注意点:
获取ul节点,然后通过ul.innerHTML+(凭借好的字符串)实现元素的添加,innerHTML是识别标签的。
使用bootstrap框架
Date对象的使用
添加keyup,用来监听键盘按键
- html
<!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"
integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd"
crossorigin="anonymous"></script>
<body>
<div class="container" style="padding-top: 100px;">
<textarea class="form-control" rows="5" placeholder="请留言"></textarea>
<button type="button" class="btn btn-success">发布</button>
<ul class="list-group" style="margin-top: 20px;">
</ul>
<div class="alert alert-warning alert-dismissible" role="alert" style="height: 49px; display: none;">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true" class="sp">×</span>
</button>
<strong>错误!</strong>你最好输入一些东西后再按按钮
</div>
</div>
</body>
</body>
- js
<script>
var date = new Date();
var year = date.getFullYear();
var moth = date.getMonth() + 1;
var datas = date.getDate();
var btn = document.querySelector("button")
var text = document.querySelector("textarea")
var alerts = document.querySelector(".alert")
var ul = document.querySelector('ul');
var span = document.querySelector(".sp")
//对时间进行格式化
function getTime() {
var thme = new Date();
var h = thme.getHours();
var h = h < 10 ? '0' + h : h
var m = thme.getMinutes();
var m = m < 10 ? '0' + m : m
var s = thme.getSeconds()
var s = s < 10 ? '0' + s : s;
return h + ':' + m + ':' + s;
}
//按钮点击
btn.addEventListener('click', function () {
if (text.value.length == 0) {
alerts.style.display = "block"
} else {
var li = document.createElement('li');
var str = `<li class="list-group-item">${text.value} <span class="date">${year}.${moth}.${datas}-${getTime()}</span><a href="javascript:;">×</a> </li>`
ul.innerHTML = str + ul.innerHTML
//1. 获取所有的a标签
//2. 添加点击事件
//3. 通过a找到父节点li,移除节点方法移除
// for (let i = 0; i < deletea.length; i++) {
// deletea[i].addEventListener('click', function () {
// console.log(this);
// console.log(deletea[i]);
// ul.removeChild(this.parentNode)
// })
// console.log(i);
// deletea[i].onclick = function () {
// console.log(deletea[i]);
// ul.removeChild(this.parentNode)
// }
// }
var deletea = document.querySelectorAll("a");
console.log(deletea);
deletea.forEach(function (item, index) {
item.onclick = function () {
console.log(item);
ul.removeChild(item.parentNode)
}
})
for (let i = 0; i < deletea.length; i++) {
deletea[i].onclick = function () {
console.log(this.parentNode);
ul.removeChild(this.parentNode);
}
}
text.value = ""
}
})
//点击后,隐藏报错框
span.addEventListener('click', function () {
alerts.style.display = "none"
})
//添加按键监听
document.addEventListener('keyup', function (e) {
if (e.keyCode == 83) {
text.focus();
} else if (e.keyCode == 13) {
btn.click();
}
})
//删除
/***
* 获取所有的a,循环添加点击事件,this代表当前点击的a
* 1. 全局this,指向window
* 2. 构造函数内部 this 指向实例化的对象
* 3. 事件处理函数中 this
* */
</script>
- css
<style>
body {
background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
}
div {
/* display: flex; */
width: 100%;
height: 100vh;
/* padding: 200px; */
}
textarea {
margin-bottom: 20px;
resize: none;
}
.date {
float: right;
}
</style>
- 效果
删除节点
- node.removeChild(child)中,删除一个是子节点,返回删除的元素。
- 获取元素
- 删除元素 node.removeChild(child)
- 击按钮依次删除里面的孩子
<body>
<button>删除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光头强</li>
</ul>
<script>
// 1.获取元素
var ul = document.querySelector('ul');
// 2. 删除元素 node.removeChild(child)
// ul.removeChild(ul.children[0]);
// 3. 点击按钮依次删除里面的孩子
var btn = document.querySelector('button');
btn.onclick = function () {
if (ul.children.length == 0) {
this.disabled = true;
} else {
ul.removeChild(ul.children[0]);
}
}
</script>
</body>
删除留言的案例
- 阻止链接跳转需要添加javascript:void(0);或者javascript:;
<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 {
// console.log(text.value);
// (1) 创建元素
var li = document.createElement('li');
// 先有li 才能赋值
li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
// (2) 添加元素
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
// (3) 删除元素 删除的是当前链接的li 它的父亲
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
// node.removeChild(child); 删除的是 li 当前a所在的li this.parentNode;
ul.removeChild(this.parentNode);
}
}
}
}
</script>
复制节点(克隆节点)
- node.closeNode( ) :该方法返回调用该方法的节点的一个副本。也称为克隆节点/拷贝节点
| 属性值|解释说明|
|:-----😐:------😐
| node.cloneNode()| 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容|
| node.cloneNode(true) |括号为true 深拷贝 复制标签复制里面的内容|
<body>
<ul>
<li>1111</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
// 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
// 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);
</script>
</body>
动态生成表格-创建学生数据
- 案例分析:因为里面的学生数据都是动态的,我们需要js动态生成,这里我们模拟数据,自己定义好数据。数据采取对象形式存储。
三种动态创建元素的区别
属性 | 说明 |
---|---|
element.innerHtml | 当创建多的时候,效率不如createElement()(采用的拼接字符串),创建多个元素效率更高(采用数组形式拼接),结构稍微复杂 |
document.write() | 直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘 |
document.createElement() | 创建多个元素效率低一点点,但是结构清晰 |
DOM重点核心
创建
- docoment.write
- innerHTHL (识别html标签)
- createElement (不识别html标签)
增
- appendChild (后面添加)
- insertBefore (前面添加)
删
1.removeChild
改
- 修改元素属性:src,href,title等
- 修改元素内容:innerHTML,innerText
- 修改表单元素:value,type,displed等
- 修改样式属性:style,className
查
- DOM提供的API方法:getElementById,getElementByTagName(古老用噶,不太推荐)
- H5提供的新方法:querySelector,querySelectorAll 提倡
- 利用节点操作获取元素:父(parentNode),子(children),兄(previousElementSibling , nextElementSibling ) 提倡。
属性操作
- 主要针对自定义属性
- setAttribute:设置dom的属性值
- getAttribute:得到dom的属性值
- removeAttribute:移除属性
事件操作
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键时触发 |
onmouseover | 鼠标经过时触发 |
onmouseout | 鼠标离开时触发 |
onfocus | 获得鼠标焦点时触发 |
oninput | 每次输入都会触发(配合表单更佳) |
onblur | 失去鼠标焦点时触发 |
onmousemove | 鼠标移动触发 |
onmousedown | 鼠标按下时触发 |
事件高级
注册事件
- 给元素添加事件,称为注册事件或者绑定事件
- 注册事件有两种方式:传统方式和方法监听注册方式
传统的注册方式:
- 特点:唯一性
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数。
btns[0].onclick = function()
方法监听注册方式:
- w3c标准推荐方式
- addEventListener() 它是一个方法
- IE9之前的IE不支持此方法,可使用attachEvent( ) 代替
- 特点:同一个元素同一个事件可以注册多个监听器
- 按注册顺序依次执行
addEventLIstener 事件监听方式
eventTarget.addEventListener(type,listener[, useCapture])
- eventTarget.addEventListene( ) 方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时,就会执行事件处理函数。
三个参数
- type:事件类型字符串,比如click,mouseover,注意这里不带on
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认是
false
是冒泡型事件流
,也可以是true
,这样就会给当前事件添加捕获型事件流
。
- 注意:1. 里面的事件类型是字符串 必定加引号 而且不带on;2. 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
<body>
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>ie9 attachEvent</button>
<div>点击我</div>
<script>
var btns = document.querySelectorAll('button');
var div = document.querySelector("div")
// 1. 传统方式注册事件,on+type 缺点:同一事件源,同一事件的唯一性。
btns[0].onclick = function () {
alert('hi');
}
btns[0].onclick = function () {
alert('hao a u');
}
// 2. 事件侦听注册事件 addEventListener ,通过一个事件源中绑定不同的事件处理函数
// (1) 里面的事件类型是字符串 必定加引号 而且不带on
// (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
//第一种注册方式
btns[1].addEventListener('click', function () {
alert('22');
})
btns[1].addEventListener('click', function () {
alert('33');
})
//第二种注册方式,函数外部声明,后引入
div.addEventListener('click', fn, false)
function fn() {
console.log(3);
}
</script>
</body>
attachEvent 事件监听方式(i9版本之间适用)
- eventTarget.attachEvent(eventNameWitchOn ,callBack)
- eventTarget.attachEvent( )方法把指定的监听器注册到eventTarget(目标对象上),当该对象触发指定事件时,指定的回调函数就会被执行
- 该方法接受两个参数:
- eventNameWithOn: 事件类型字符串,比如onclick,onmouseover,这里要带on
- callback:事件处理函数,当目标触发事件时回调函数被调用
btns[2].attachEvent('onclick', function () {
alert('11');
})
注册事件兼容性方案
- 兼容性处理的原则:首先照顾大多数浏览器,再处理特殊浏览器
function addEventListener(element, evenName, fn) {
//判断当前浏览器是否支持addEventListener 方法
if (element.addEventListener) {
element.addEventListener(eventName, fn);//第三个参数默认时false
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, fn);
} else {
//相当于element.onclick = fn;
element['on' + eventName] = fn;
}
}
删除事件(解绑事件)
删除事件的方式
1. 传统注册方式
- element.onclick = null
divs[0].onclick = null;
2. 方法监听注册方式
- eventTarget.romoveEventListener(type,listne [, useCapture]);
- eventTarget.datachEvent(eventNameWithOn,callBack);
删除事件兼容性方案
function removeEventListener(element, eventName, fn) {
//判断当前浏览器是否支持removeEventListener方法
if (element.removeEventListener) {
element.removeEventListener(eventName, fn)//第三个参数默认是false
} else if (element.detachEvent) {
element.detachEvent('on' + eventName, fn);
} else {
element['on' + eventName] = null;
}
}
DOM事件流
- 事件流:描述的是从页面中接受事件的顺序
- 事件发生时会在元素之间
按照特定的顺序传播
,这个传播过程即DOM事件流
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
var father = document.querySelector(".father")
var son = document.querySelector(".son")
console.log(father);
console.log(son);
onclick只能是冒泡
on + type
son.onclick = function () {
console.log("son");
}
father.onclick = function () {
console.log("faher");
}
document.body.onclick = function () {
console.log("body");
}
document.documentElement.onclick = function () {
console.log("html");
}
</script>
<body>
<div class="father">
<div class="son">
</div>
</div>
<script>
var father = document.querySelector(".father")
var son = document.querySelector(".son")
console.log(father);
console.log(son);
//如果为true就是捕获,从根节点开始
son.addEventListener('click', function () {
console.log("son");
},true)
father.addEventListener('click', function () {
console.log("father");
},true)
father.parentNode.addEventListener('click', function () {
console.log("body");
},false)
document.documentElement.addEventListener('click', function () {
console.log("html");
},false)
</script>
</body>
注意:
- true在那个元素上,哪个元素的事件流就是捕获
- 上面案例中的dody元素和html元素的事件流是冒泡
- 当父子注册的事件一样时,才会有事件流
三个阶段
捕获阶段
当前目标阶段
冒泡阶段
- 事件冒泡:IE最早提出,事件开始时由最
具体的元素吸收
,然后逐级向上传播到DOM最顶层节点
的过程。 - 事件捕获:网景最早提出,由
DOM最顶层节点开始
,然后逐级向下
传播到最具体的元素接收的过程。
注意
- JS代码中只能执行或者捕获冒泡其中的一个阶段
- onclick和attachEvent只能得到冒泡阶段。
- addEventListener(type,listener[,useCapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
- 实际开发中我们很少使用事件捕获,我们更关注事件冒泡
- 有些事情是没有冒泡的,比如
onblur
,onfocus
,onmouseenter
,onmouseleave
。 - 冒泡需要合理运用,负责会带来麻烦。
-
捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段 document -> html -> body -> father -> son
-
冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段 son -> father ->body -> html -> document
三个阶段
事件对象
event
就是一个事件对象写到我们侦听函数的 小括号里面
当形参来看- 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
- 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击里面就包含了
鼠标的相关信息
,鼠标坐标
,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键
- 这个事件对象我们可以自己命名 比如
event
、evt
、e
- 事件对象也有兼容性问题 ie678 通过
window.event
兼容性的写法e = e || window.event;
var div = document.querySelector('div');
div.onclick = function(e) {
// console.log(e);
// console.log(window.event);
// e = e || window.event;
console.log(e);
}
兼容性处理
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.stopPropagtion() | 阻止冒泡 标准 |
- e.target: 返回的是触发事件的对象(元素) this 返回的是绑定事件的对象(元素)
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
// 我们给ul 绑定了事件 那么this 就指向ul
console.log(this);
console.log(e.target);
// e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
})
this 和 e.target的区别
- 区别 :
e.target 点击了哪个元素,就返回哪个元素
,this: 哪个元素绑定了这个点击事件,那么就返回谁
- 注意:跟 this 有个非常相似的属性 currentTarget ie678不认识(了解1)
this是事件绑定的元素,是函数的调用者(绑定这个事件的元素)
e.target是事件触发的元素
阻止默认行为
- 阻止默认行为(事件)
让链接不跳转
或者让提交按钮不提交
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);
}
阻止冒泡
- stopPropagation
<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>
阻止事件冒泡的兼容性解决方案
if(e && e.stopPropagation){
e.stopPropagation();
}else {
window.event.cancleBubble = true;
}
事件委托(代理,委派)
- 事件委托:也称为事件代理,在jQuery里面称为事件委派
- 原理:不要给每个字节点单独设置事件监听器,而是事件监听器设置在其父节点上,通过
e.target进行判断
,然后利用冒泡原理影响设置每个子节点。 - 事件委派的作用:只操作一次DOM,提高了程序执行的性能。
- 使用场景:
-
大量元素添加事件,提高性能,减少dom操作
-
动态创建的元素
<body>
<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>
</body>
<body>
ul>li*10{&&} emm语法,快速生成
<ul>
<li>01</li>
<li>02</li>
<li>03</li>
<li>04</li>
<li>05</li>
<li>06</li>
<li>07</li>
<li>08</li>
<li>09</li>
<li>10</li>
</ul>
<script>
//操作dom10次
var lis = document.querySelectorAll("li")
lis.forEach(function (v, i) {
v.onclick = function () {
this.style.color = "red"
}
})
//事件委派,操作dom一次,给父元素添加事件
var ul = document.querySelector("ul")
ul.onclick = function (e) {
e = e || window.event;
e.target.style.color = "red"
console.log(e.target);
}
</script>
</body>
<!-- 事件三要素:
注册事件的方式:on+type,事件监听(兼容性问题)
事件流:捕获阶段,目标阶段,冒泡阶段
事件对象:鼠标事件对象,键盘事件对象
事件委派:冒泡型事件流
1. 大量元素添加事件,提高性能,减少dom操作
2. 动态创建的元素
-->
事件委派的好处
常用的鼠标事件
- 静止鼠标右键菜单
- contentmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
<body>
我是一段不愿意分享的文字
<script>
// 1. contextmenu 我们可以禁用右键菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
// 2. 禁止选中文字 selectstart
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
</script>
</body>
- 禁止鼠标选中(selectstart 开始选中)
document.addEventListener('selectstart', function (e) {
e.preventDefault();
})
鼠标事件对象
鼠标事件对象 | 说明 |
---|---|
e.clientX | 返回鼠标相对于浏览器可视区的X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
e.apgeX | 返回鼠标相当于文档页面的X坐标 IE9+支持 |
e.pageY | 返回鼠标相当于文档页面的Y坐标 IE9+支持 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标先对于电脑屏幕的Y坐标 |
- e.clientX: 返回鼠标在可视区的x坐标
- e.clientY: 返回鼠标在可视区的y坐标
console.log(e.clientX);
console.log(e.clientY);
- e.pageX:鼠标在页面文档的x坐标
- e.pageY:鼠标在页面文档的y坐标
console.log(e.pageX);
console.log(e.pageY);
- e.screenX:creen 鼠标在电脑屏幕的x坐标
- e.screenY:creen 鼠标在电脑屏幕的y坐标
console.log(e.screenX);
console.log(e.screenY);
跟随小天使案例
<body>
<img src="./images/angel.gif" alt="">
<script>
var pic = document.querySelector('img');
document.addEventListener('mousemove', function (e) {
// 1. mousemove只要我们鼠标移动1px 就会触发这个事件
// console.log(1);
// 2.核心原理: 每次鼠标移动,我们都会获得最新的鼠标坐标, 把这个x和y坐标做为图片的top和left 值就可以移动图片
var x = e.pageX;
var y = e.pageY;
//3 . 千万不要忘记给left 和top 添加px 单位
pic.style.left = x - 50+ 'px';
pic.style.top = y - 40+ 'px';
});
</script>
</body>
常用的键盘事件
键盘事件 | 触发条件 | 使用keycode的情况 |
---|---|---|
onkeyup | 某个键盘按键被松开时触发 | 不区分大小写 |
onkeydown | 某个键盘按键被按下时触发 | 不区分大小写 |
onkeypress | 某个键盘被按下时触发 但是它不识别功能键 比如: ctrl shift等 |
区分大小写 |
<body>
<script>
// 常用的键盘事件
//1. keyup 按键弹起的时候触发
// document.onkeyup = function() {
// console.log('我弹起了');
// }
document.addEventListener('keyup', function() {
console.log('我弹起了');
})
//3. keypress 按键按下的时候触发 不能识别功能键 比如 ctrl shift 左右箭头啊
document.addEventListener('keypress', function() {
console.log('我按下了press');
})
//2. keydown 按键按下的时候触发 能识别功能键 比如 ctrl shift 左右箭头啊
document.addEventListener('keydown', function() {
console.log('我按下了down');
})
// 4. 三个事件的执行顺序 keydown -- keypress -- keyup
</script>
</body>
- 注意:三个事件的执行顺序 keydown -- keypress -- keyup
ASCII表[1:1]
- 键盘事件对象
- 注意:我们的onkeyup 和onkeydown事件不区分字母大小写,onkeypress 事件 区分字母大小写 .我们在实际开发中,我们更多的使用keydown和keyup,他可以识别所有的键(包括功能键),keypress不识别功能键,但是keycode属性能区分大小写,返回不同的ASCII值。
| 键盘对象属性 |属性|
|:-----😐:------😐
| keyCode| 返回该键的ASCII值|
模拟京东按键输入的内容
- 核心思路:检测用户是否按下了s 键,如果按下s 键,就把光标定位到搜索框里面;
- 使用键盘事件对象里面的keyCode 判断用户按下的是否是s键;
- 搜索框获得焦点: 使用 js 里面的 focus() 方法;
<body>
<input type="text">
<script>
// 核心思路: 检测用户是否按下了s 键,如果按下s 键,就把光标定位到搜索框里面
// 使用键盘事件对象里面的keyCode 判断用户按下的是否是s键
// 搜索框获得焦点: 使用 js 里面的 focus() 方法
var search = document.querySelector('input');
document.addEventListener('keyup', function (e) {
if (e.keyCode == 83) {
search.focus();
}
});
</script>
</body>
this指向
this的指向在函数定义时是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终执向的是那个调用它的对象。
- 全局作用域或者普通函数中的this指向全局对象window(注意
定时器里的this指向window
) - 方法调用中谁调用this指向谁。
- 构造函数中this指向构造函数的实例。
模拟京东快递快递单号查询案例
案例分析:
1. 快递单号输入内容时, 上面的大号字体盒子(con)显示(这里面的字号更大)
2. 表单检测用户输入: 给表单添加键盘事件
3. 同时把快递单号里面的值(value)获取过来赋值给 con盒子(innerText)做为内容
4. 如果快递单号里面内容为空,则隐藏大号字体盒子(con)盒子、
5. 当我们失去焦点,就隐藏这个con盒子
6. 当我们获得焦点,就显示这个con盒子
- 注意:keydown和keypress在文本框里面的特点:他们两个事件触发的时候,文字还没有落入文本框中。keyup事件触发的时候文字以及落入文本框里了。
BOM概述
- BOM:即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是window.
- BOM:由一系列相关的对象构成,并且每个对象都提供了很多方法和属性。
- 浏览器对象模型
- 把浏览器当作一个对象来看待
- BOM的顶级对象是window
- BOM学习的是浏览器窗口的交互的一些对象
- BOM是浏览器厂商在浏览器上定义的,兼容性较差。
- BOM要比DOM大
BOM的构成
window对象是浏览器的顶级对象,它具有双重角色。
- 它是JS访问浏览器窗口的一个接口。
- 它是一个全局对象。定义在全局作用域中的变量,函数都会变成window对象的属性和方法。
在调用的时候可以省略window,前面学习的对话框都属于window对象方法,如alert(),prompt()等。
注意:window下的一个特殊属性window.name
窗口加载事件
- 文档完全加载完触发
window.onload = function(){}
或者
window.addEventListener('load', function(){});
window.onload = function() {
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
alert('点击我');
})
}
window.onload = function() {
alert(22);
}
window.addEventListener('load', function () {
var btn = document.querySelector('button');
btn.addEventListener('click', function () {
alert('点击我');
})
})
window.addEventListener('load', function () {
alert(22);
})
- window.onload(页面) 加载事件,当文档内容完全加载完全后会触发事件(包括图像,脚本文件,CSS等),就调用的处理函数。
- 注意:
- 有了window.onload就可以把JS代码写到页面元素的上方,因为onload是等页面内容全部加载完毕,再去执行处理函数。
- window.onload传统的注册方式 ,只能写一次,如果有多个,会以最后一个window.onload为准。
- 以下三种情况都会刷新页面都会触发load事件。
- a标签的超链接
- F5或者刷新页面
- 前进后退按钮
- DOM加载后就触发
document.addEventListener('DOMContentLoaded', function () {}
document.addEventListener('DOMContentLoaded', function () {
alert(33);
})
- OMContentLoaded 是DOM 加载完毕,不包含图片 falsh css 等就可以执行 加载速度比 load更快一些。IE9以上才支持。
如果页面的图片很多,从用户访问到onlocd触发可能需要较长时间,交互效果就不能实现,必然影响用户的体验,此时用DOMContentLoaded事件比较合适。
调整窗口大小事件
window.onresise = funcation(){}
或者
window.addEventListener('resize', function() {})
<body>
<script>
window.addEventListener('load', function() {
var div = document.querySelector('div');
window.addEventListener('resize', function() {
console.log(window.innerWidth);
console.log('变化了');
if (window.innerWidth <= 800) {
div.style.display = 'none';
} else {
div.style.display = 'block';
}
})
})
</script>
<div></div>
</body>
window.onresize是调整窗口大小加载事件,当触发时就调用处理函数。
- 注意:
- 只要窗口大小发生像素变化,就会触发这个事件
- 我们经常利用这个事件完成响应式的布局。window.innerWidth当前屏幕的宽度。
setTimeout()定时器
window.setTimeout(调用函数, [延时时间(毫秒)]);
setTimeout(function() {
console.log('爆炸了');
},2000)
function callback() {
console.log('爆炸了');
}
var timer1 = setTimeout(callback, 3000);
var timer2 = setTimeout(callback, 5000);
该方法用于设置一个定时器,该定时器再定时器到期后执行调用函数。
- 这个window在调用时可以省略。
- 这个延时时间单位是毫秒 但是可以省略,如果省略默认的是0。
- setTimeout里面的调用函数也叫回调函数 callback
- 普通函数时按照代码顺序直接进行
- 而这个函数需要等待,时间到了才会去调用这个函数,因此称为回调函数。
停止setTimeout() 定时器
window.clearTimeout(timeout ID)
<body>
<button>点击停止定时器</button>
<script>
var btn = document.querySelector('button');
var timer = setTimeout(function() {
console.log('爆炸了');
}, 5000);
btn.addEventListener('click', function() {
clearTimeout(timer);
})
</script>
</body>
setInterval( ) 定时器
- 每隔这个延时时间,就去调用这个回调函数,会调用很多次,重复调用这个函数
indow.setInterval(调用函数, 延时时间);
setInterval(function() {
console.log('继续输出');
}, 1000);
setTIme和setInterval的区别
属性 | 区别 |
---|---|
setTimeout | 延时时间到了,就去调用这个回调函数,只调用一次 就结束了这个定时器 |
setInterval | 每隔这个延时时间,就去调用这个回调函数,会调用很多次,重复调用这个函数 |
倒计时案例(京东)
- 案例分析
- 这个倒计时时不断变化的,需要定时器自动变化(setInterval)
- 三个黑色盒子里面分别存放时分秒
- 三个黑色盒子利用innerHTML放入计算的小时分钟秒数
- 第一次是间隔毫秒数,因此刚刷新页面会有空白
- 最好采取封装函数的方式,这样可以先调用一次这个函数,防止刚开始刷新页面有空白问题
<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('2022-3-18 21: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>
停止setInterval( )定时器
- clearInterval( ) 方法取消了先前通过调用setInterval( )建立的定时器。
window.clearInerval(intervalID);
<body>
<button class="begin">开启定时器</button>
<button class="stop">停止定时器</button>
<script>
var begin = document.querySelector('.begin');
var stop = document.querySelector('.stop');
var timer = null; // 全局变量 null是一个空对象
begin.addEventListener('click', function() {
timer = setInterval(function() {
console.log('ni hao ma');
}, 1000);
})
stop.addEventListener('click', function() {
clearInterval(timer);
})
</script>
</body>
- 注意:
1.window可以省略、
2.里面的参数就是定时器的标识符。
发送短信案例
- 案例分析:
- 按钮点击之后,会禁用 disabled 为true 。
- 同时按钮里面的内容会变化, 注意 button 里面的内容通过 innerHTML修改。
- 里面秒数是有变化的,因此需要用到定时器。
- 定义一个变量,在定时器里面,不断递减。
- 如果变量为0 说明到了时间,我们需要停止定时器,并且复原按钮初始状态。
<body>
手机号码: <input type="number"> <button>发送</button>
<script>
// 按钮点击之后,会禁用 disabled 为true
// 同时按钮里面的内容会变化, 注意 button 里面的内容通过 innerHTML修改
// 里面秒数是有变化的,因此需要用到定时器
// 定义一个变量,在定时器里面,不断递减
// 如果变量为0 说明到了时间,我们需要停止定时器,并且复原按钮初始状态
var btn = document.querySelector('button');
var time = 10;
btn.addEventListener('click', function () {
this.disabled = true;
var timer = setInterval(function () {
if (time == 0) {
clearInterval(timer);
btn.disabled = false;
btn.innerHTML = '发送';
time = 10;//这个10需要重新开始
} else {
btn.innerHTML = '还剩下' + time + '秒';
time--;
}
}, 1000)
})
</script>
</body>
this的指向问题
- this 指向问题 一般情况下this的最终指向的是那个调用它的对象。
- 全局作用域或者普通函数中this指向全局对象window( 注意定时器里面的this指向window)
- 方法调用中谁调用this指向谁
- 构造函数中this指向构造函数的实例
JS执行机制
JS是单线程
- JavaScript语言的一大特色就是单线程,也就是说,
同一个时间只能做一件事
。这是因为JavaScript这门脚本语言诞生使命所致。
同步和异步
- HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,于是JS中出现了
同步
和异步
。
同步任务
- 程序执行顺序和任务排列时一致的,同步的。
- 同步任务都在主线程执行,形成一个
执行栈
异步任务
- 在做一件事情的同时,还可以处理其他事情。
- JS的异步是通过回调函数实现的。
- 一般而言,异步任务有以下三种类型:
- 普通时间:如
click
,resize
等 - 资源加载:如
load
,error
等 - 定时器:包括
setInterval
,setTimeout
等
异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)
由于主线程不断重复获得任务,执行任务,再获取任务,再执行,所以这种机制被称为时间循环(event loop)
执行过程:
- 先执行执行栈中的同步任务
- 异步任务(回调函数)放入任务队列中。
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行,开始执行。
location对象
什么是location对象:
window对象给我们提供了一个location属性用来获取或者设置窗体的url,并且可以用于解析URL。因为这个属性返回的是一个对象,所以我们将这个属性也称为location对象。
url
- 唯一资源定位符
- 语法
protoccol://host[:port]/path/[?query]#fragment
组成
组成 | 说明 |
---|---|
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 | 返回片段 #后面内容常见于链接 锚点 |
location.assign() | 跟href一样,可以跳转页面(也称为重定向) |
location.replace() | 替换当前页面,因为不记录历史,所以不能后退页面 |
location.reload() | 重新加载页面,相当于刷新页面按钮或者 f5 如果参数为true 强制刷新 ctrl+f5 |
<body>
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// 记录浏览历史,所以可以实现后退功能
// location.assign('http://www.itcast.cn');
// 不记录浏览历史,所以不可以实现后退功能
// location.replace('http://www.itcast.cn');
location.reload(true);
})
</script>
</body>
navigator对象
navigator对象包含有关浏览器的信息,他有很多属性,最常见的就是userAgent,该属性可以用来返回有客户机发送服务器的user-agent头部值。
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 = ""; //电脑
}
history对象
- 可以与浏览器历史记录进行交互。该对象包含用户(在浏览窗口中)访问过的URL
| history对象方法 |作用|
|:-----😐:------😐
| back()| 可以后退功能|
| forward() | 前进功能|
| go(参数) |前进后退功能,参数如果是1 前进1个页面,如果是 -1 后退1个页面|
PC端网页特效
offset概述
offset翻译过来就是偏移量
,我们使用offset系列相关属性得到元素的位置(偏移),大小等。
- 获得元素距离带有定位父元素的位置
- 或者元素自身的大小。(宽度,高度)
- 注意:返回的数值都不带单位。
offset常用属性:
| offest系列属性 |作用|
|:-----😐:------😐
| element.offsetParent| 返回作为该元素带有定位的父级元素,如果父级都没有定位,则返回body|
| element.offsetTop | 返回元素相对带有定位父元素上方的偏移|
| element.offsetLeft| 返回元素相对带有定位父元素左方的偏移|
| element.offsetWidth| 返回自身包括padding,边框,内容区的宽度,返回数值不带单位|
| element.offsetHeight| 返回自身包括padding,边框,内容区的高度,返回数值不带单位|
offset与style的区别
- offset:可以得到任意样式表中的样式值;只读属性;获取元素大小位置用它比较合适
- style:只能得到行内样式表中的样式值;是可读写属性,可以获取也可以赋值;给元素该值style更合适;
仿京东放大镜效果限制遮挡层
= 核心JS代码
window.addEventListener('load', function () {
var preview_img = document.querySelector('.preview_img');
var mask = document.querySelector('.mask');
var big = document.querySelector('.big');
// 1. 当我们鼠标经过 preview_img 就显示和隐藏 mask 遮挡层 和 big 大盒子
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) {
// (1). 先计算出鼠标在盒子内的坐标
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
// console.log(x, y);
// (2) 减去盒子高度 300的一半 是 150 就是我们mask 的最终 left 和top值了
// (3) 我们mask 移动的距离
var maskX = x - mask.offsetWidth / 2;
var maskY = y - mask.offsetHeight / 2;
// (4) 如果x 坐标小于了0 就让他停在0 的位置
// 遮挡层的最大移动距离
var maskXMax = preview_img.offsetWidth - mask.offsetWidth;
var maskYMax = preview_img.offsetHeight - mask.offsetHeight;
if (maskX <= 0) {
maskX = 0;
} else if (maskX >= maskXMax) {
maskX = maskXMax;
}
if (maskY <= 0) {
maskY = 0;
} else if (maskY >= maskYMax) {
maskY = maskYMax;
}
mask.style.left = maskX + 'px';
mask.style.top = maskY + 'px';
// 3. 大图片的移动距离 = 遮挡层移动距离 * 大图片最大移动距离 / 遮挡层的最大移动距离
// 大图
var bigIMg = document.querySelector('.bigImg');
// 大图片最大移动距离
var bigMax = bigIMg.offsetWidth - big.offsetWidth;
// 大图片的移动距离 X Y
var bigX = maskX * bigMax / maskXMax;
var bigY = maskY * bigMax / maskYMax;
bigIMg.style.left = -bigX + 'px';
bigIMg.style.top = -bigY + 'px';
})
})
元素可视区域client系列
client翻译过来就是客户端,我们使用client系列相关属性来获取元素可视区的相关信息。通过client系列的相关属性可以动态的得到该元素的边框大小和元素大小等。
client系列属性 | 作用 |
---|---|
element.clientTop | 返回元素上边框大小 |
element.clientLeft | 返回元素左边框大小 |
element.clientWidth | 返回自身包括padding,不含边框,内容区的宽度,返回数值不带单位 |
element.clientHeight | 返回自身包括padding,不含边框,内容区的高度,返回数值不带单位 |
client和offset区别
client
宽度 和我们offsetWidth
最大的区别就是不包含边框
立即执行函数
(function(){})()或者
(function () { }())
主要作用:创建一个独立的作用域
- 立即执行函数:不需要自己调用,立马就可以执行的函数
- 如果有多个立即执行函数,就必须用分号隔开。
<body>
<script>
// 1.立即执行函数: 不需要调用,立马能够自己执行的函数
function fn() {
console.log(1);
}
fn();
// 2. 写法 也可以传递参数进来
// 1.(function() {})() 或者 2. (function(){}());
(function(a, b) {
console.log(a + b);
var num = 10;
})(1, 2); // 第二个小括号可以看做是调用函数
(function sum(a, b) {
console.log(a + b);
var num = 10; // 局部变量
}(2, 3));
// 3. 立即执行函数最大的作用就是 独立创建了一个作用域, 里面所有的变量都是局部变量 不会有命名冲突的情况
</script>
</body>
淘宝flexibleJs源码分析
(function flexible(window, document) {
// 获取的html 的根元素
var docEl = document.documentElement
// dpr 物理像素比
var dpr = window.devicePixelRatio || 1
// adjust body font size 设置我们body 的字体大小
function setBodyFontSize() {
// 如果页面中有body 这个元素 就设置body的字体大小
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
} else {
// 如果页面中没有body 这个元素,则等着 我们页面主要的DOM元素加载完毕再去设置body
// 的字体大小
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10 设置我们html 元素的文字大小
function setRemUnit() {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// reset rem unit on page resize 当我们页面尺寸大小发生变化的时候,要重新设置下rem 的大小
window.addEventListener('resize', setRemUnit)
// pageshow 是我们重新加载页面触发的事件
window.addEventListener('pageshow', function (e) {
// e.persisted 返回的是true 就是说如果这个页面是从缓存取过来的页面,也需要从新计算一下rem 的大小
if (e.persisted) {
setRemUnit()
}
})
// detect 0.5px supports 有些移动端的浏览器不支持0.5像素的写法
if (dpr >= 2) {
var fakeBody = document.createElement('body')
var testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
}(window, document))
- 注意:火狐中有个一特点,有个“往返缓存”,这个缓存中还保存着DOM和JavaScript的状态;实际上是将整个页面都保存在了内存里。所以此刻后退按钮不能刷新页面。
- 此时可以用pageshow事件来触发,这个事件在显示时触发,无论页面是否来自缓存。在重新加载页面中,pageshow会在load事件出发后触发;根据事件对象中的persistes来判断时候时缓存中的页面触发的pageshow事件,注意这个事件给window添加!
元素滚动scoll系列
- scoll翻译过来就是滚动的,我们使用scoll系列相关的属性可以动态得到该元素的大小,滚动距离等。
scroll事件
- scroll滚动事件当我们滚动条发生变化会触发的事件。
div.addEventListener('scroll', function () {
console.log(div.scrollTop);
})
scroll系列属性 | 作用 |
---|---|
element.scrollTop | 返回被卷去的上侧距离,返回数值不带单位 |
element.scrollLeft | 返回被卷去的左侧距离,返回数值不带单位 |
element.scrollWidth | 返回自身实际的宽度,不含边框,返回数值不带单位 |
element.scrollHeight | 返回自身实际的高度,不含边框,返回数值不带单位 |
<script>
// scroll 系列
var div = document.querySelector('div');
console.log(div.scrollHeight);
console.log(div.clientHeight);
div.addEventListener('scroll', function () {
console.log(div.scrollTop);
})
</script>
仿淘宝固定右侧侧边栏案例
- 原来的侧边栏是绝对定位
- 当页面滚动到一定位置,侧边栏改为固定定位。
- 页面继续滚动,就会让返回顶部显示出来。
- 案例分析
- 需要用到页面滚动事件scroll,因为是页面滚动,所以事件源是document
- 滚动到某个位置,就是判断页面被卷去的上部值。
- 页面被卷去的头部:可以通过window.pageYOffest获得 ,如果被卷去的是左侧的window.pageXOffset
- 注意:元素被卷去的头部是element.scrollTop,如果是页面被卷去头部,则是windoow.pageYOffset.
<script>
//1. 获取元素
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
//一定要写道滚动的外边
var banenrTop = banner.offsetTop;
//当侧边栏固定定位后应该变化的值
var sliderbarTop = sliderbar.offsetTop - banenrTop;
//获取Mian主体元素
var main = document.querySelector('.main');
var goBack = document.querySelector('.goBack');
var mainTop = main.offsetTop;
document.addEventListener('scroll', function () {
//window.pageYOffset 页面被减去的头部
// console.log(window.pageYOffset);
// 3.当页面被卷去的头部大于等于 172 此时,侧边栏就要改为固定定位
if (window.pageYOffset >= 172) {
sliderbar.style.position = 'fixed';
sliderbar.style.top = sliderbarTop + 'px';
} else {
sliderbar.style.position = 'absolute';
sliderbar.style.top = '300px';
}
if (window.pageYOffset >= mainTop) {
goBack.style.display = 'block';
} else {
goBack.style.display = 'none';
}
})
</script>
三大系列总结
三大系列大小对比 | 作用 |
---|---|
element.offsetWidth | 返回自身包括padding,边框,内容区的宽度,返回数值不带单位 |
element.clientWidth | 返回自身包括padding,内容区的宽度,不含边框,返回数值不带单位 |
element.scrollWidth | 返回自身实际的宽度,不含边框,返回数值不带单位 |
- 他们的主要用法
- offset系列经常用于获取元素位置 offsetLeft offsetTop
- client经常用来获得元素大小 clientWidth clientHeight
- scroll经常用于获取滚动距离 scrollTop scrollLeft
- 注意:页面滚动距离是通过window.pageXOffset 获得
mouseenter和mouseover的区别
mouseenter鼠标事件
- 当鼠标移到到元素上就会触发mouseenter事件.
- 类似mouseover,他们两者之间的差别就是:mouseover鼠标经过自身盒子会触发,经过子盒子还会触发.mouseenter只会经过自身盒子触发.
- 之所以这样,就是因为mouseenter不会冒泡.
- 跟mouseenter搭配,鼠标离开 mouseleave同样不会冒泡
动画效果
动画函数的封装
注意函数需要传递两个参数,动画对象和移动到的距离。
动画实现原理(匀速运动)
- 核心原理:通过定时器setInterval( ) 不断移动盒子位置。
实现步骤:
- 获得盒子当前位置。
- 让盒子在当前位置加上1个移动距离。
- 利用定时器不断重复这个操作。
- 加一个结束定时器的条件。
5.** 注意此元素需要添加定位, 才能使用element.style.left。**
动画函数给不同元素记录不同定时器
如果多个元素都是用这个动画效果,每次都要var 声明定时器。我们可以给不同的元素使用不同的定时器(自己专门用自己的定时器)。
核心原理:利用JS是一门动态语言,可以很方便的给当前对象添加属性。
<button>运动按钮,点击才走</button>
<div>盒子</div>
<span>小蓝</span>
<script>
var obj = {};
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 () {
if (obj.offsetLeft >= target) {
//停止动画
// 本质是停止计时器
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 30)
}
//调用函数
animate(div, 500);
btn.addEventListener('click', function () {
animate(span, 400)
})
</script>
缓动效果
- 原理:缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来。
- 思路:
- 让盒子每秒移动的距离慢慢变小,速度就会慢慢落下来。
- 核心算法:(目标值-现在位置)/10作为每次移动的距离步长。
- 停止的条件:让当前盒子位置等于目标位置就停止计时器。
- 实现代码(和上面代码块相比只改了一小部分)
<body>
<button>点击夏雨荷才走</button>
<span>夏雨荷</span>
<script>
// 缓动动画函数封装obj目标对象 target 目标位置
// 思路:
// 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
// 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
// 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
function animate(obj, target) {
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步长值写到定时器的里面
var step = (target - obj.offsetLeft) / 10;
if (obj.offsetLeft == target) {
// 停止动画 本质是停止定时器
clearInterval(obj.timer);
}
// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
var span = document.querySelector('span');
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// 调用函数
animate(span, 500);
})
</script>
</body>
- 匀速动画 就是 盒子是当前的位置 + 固定的值 10
- 缓动动画就是 盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)
动画函数多个目标值之间移动
- 可以让动画函数从800移动到500.
- 当我们点击按钮时,判断步长是正值还是负值。
- 步长是正的,往大了取。
- 步长是负的,往小了取。
动画函数添加回调函数
- 回调函数原理:函数可以做为一个参数。将这个函数作为参数传到另外一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调。
- 回调函数书写位置:定时器结束的位置。
<body>
<button class="btn500">点击夏雨荷到500</button>
<button class="btn800">点击夏雨荷到800</button>
<span>夏雨荷</span>
<script>
function animate(obj, target, callback) {
// console.log(callback); callback = funcation(){} 调用的时候 callback()
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';
}, 15);
}
var span = document.querySelector('span');
var btn500 = document.querySelector('.btn500');
var btn800 = document.querySelector('.btn800');
btn500.addEventListener('click', function () {
// 调用函数
animate(span, 500);
})
btn800.addEventListener('click', function () {
// 调用函数
animate(span, 800, function () {
// alert('你好吗?')
span.style.backgroundColor = 'pink';
});
})
</script>
</body>
动画函数封装到单独的JS文件里面
- 因为以后经常使用动画函数,可以单独封装到一个JS文件里面,使用的时候引用这个JS文件即可。
- 新建一个js文件
- js里面写入自己的函数
轮播图
功能需求:
- 鼠标经过轮播图模块,左右按钮显示,离开左右按钮隐藏。
- 点击右侧按钮一次,图片往左播放一张,以次类推,左侧按钮同理
- 图片播放时,下面小圆圈跟着变化
- 点击小圆圈可以播放相应的图片
- 鼠标不经过轮播图,轮播图也会自动播放图片
- 鼠标经过轮播图图片,自动播放停止。
动态生成小圆圈
- 小圆圈的个数要和图片张数一致
- 所以首先利用先得到的ul里面的图片张数(图片放入li里,所以就是li的个数)
- 利用循环动态生成小圆圈(这个小圆圈要放到ol里面)
- 创建节点 createElemtent()
- 插入节点 ol.appendChild(li)
小圆圈的排他思想
- 点击当前小圆圈,就添加current类
- 其余小圆圈移除这个类
- 注意,我们在生成小圆圈的同时,就可以直接绑定点击事件了。
点击小圆圈滚动图片
- 此时用到animate动画函数,将js文件引入(注意:index.js依赖animate.js所以,anmiate.js要写到index.js上面)
- 使用动画函数的前提,该元素必须有定位
- 注意是ul移动,而不是li移动
- 滚动图片的核心算法:点击某个小圆点,就让图片滚动,小圆圈的索引号乘以图片的宽度作为ul的移动距离。
- 此时需要知道小圆圈的索引号,我们可以在生成小圆圈的时候给它设置一个自定义属性,点击的时候获取这个自定义属性即可。
点击右侧按钮一次,就让图片滚动一张
- 声明一个num,点击一次,自增一,让这个变量乘以图片宽度,就是ul的滚动距离。
- 图片无缝滚动
克隆第一张图片,让程序更智能
- 克隆第一个li cloneNode( ) 加true 深克隆负值里面的字节点,false 浅克隆。
点击右侧按钮,小圆圈跟随变化
- 最简单的做法是再声明一个变量circle,每次点击自增1,注意:左侧按钮也需要这个变量,因此需要声明全局变量。
- 图片有n张,我们小圆圈只有n-1个,必须加一个判断条件。
- 如果circle == n-1 ,就重新复原为0.
自动播放
- 添加一个定时器。
- 自动播放轮播图,实际就类似于点就了右侧按钮。
- 这时我们使用手动调用右侧按钮点击事件 arrow_r.click ( )
- 鼠标经过就banner区域就停止定时器
- 鼠标离开就开启定时器。
案例代码
- index.js
window.addEventListener('load', function () {
//获取元素
var prev = this.document.querySelector('.prev');
var next = this.document.querySelector('.next');
var banner = this.document.querySelector('.banner');
var ul = banner.querySelector('ul');
var img = ul.querySelector('a');
var imgWidth = img.offsetWidth;
//鼠标经过时显示小箭头
banner.addEventListener('mouseenter', function () {
prev.style.display = 'block';
next.style.display = 'block';
clearInterval(timer);
timer = null;//清除定时器变量
})
//鼠标离开小箭头消失
banner.addEventListener('mouseleave', function () {
prev.style.display = 'none';
next.style.display = 'none';
timer = setInterval(function () {
next.click();
}, 3000)
})
//动态生成小圆圈,有几张图片就生成几个
// var ul = banner.querySelector('ul');
var ol = banner.querySelector('ol');
// console.log(img);
// console.log(ul.children.length);
for (var i = 0; i < ul.children.length; i++) {
//创建一个li
var li = this.document.createElement('li');
//记录当前小圆圈的索引号,通过自定义属性来做
li.setAttribute('index', i);
//把li插入到ol里面
ol.appendChild(li);
//小圆圈的排他思想
li.addEventListener('click', function () {
//干掉所有人,把所有的li移除current类名
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
//留下我自己 当前的li设置 current
this.className = 'current';
//点击小圆圈,移动图片
//ul的移动距离 ,注意是负值,是往左走
var index = this.getAttribute('index');
//当我们点击某个li,就把这个li的索引号给num
num = index;
//当我们点击某个li,就把这个li的索引号给circle
circle = index;
console.log(imgWidth);
animate(ul, - index * imgWidth);
})
}
//把ol里面的第一个li设置类名为 current
ol.children[0].className = 'current';
//克隆第一张图片放到最后
var first = ul.children[0].cloneNode('true');
ul.appendChild(first);
//点击右侧按钮,图片滚动一张
var num = 0;
//circle控制小圆圈的缩放
var circle = 0;
next.addEventListener('click', function () {
//如果走到最后复制一张图片,快速切换回去。
if (num == ul.children.length - 1) {
ul.style.left = 0;
num = 0;
}
num++;
animate(ul, - num * imgWidth)
circle++;
//如果circle变成3就需要重置了
// if (circle == ol.children.length) {
// circle = 0;
// }
circle = circle == ol.children.length ? 0 : circle;
//先清除其他小圆圈的current类名
//调用函数
circleChange();
})
//左侧按钮做法
prev.addEventListener('click', function () {
//如果走到最后复制一张图片,快速切换回去。
if (num == 0) {
num = ul.children.length - 1;
ul.style.left = -num * imgWidth + 'px';
// alert(ul.style.left)
}
num--;
animate(ul, -num * imgWidth)
circle--;
//如果circle小于0说明第一张的图片,则小圆圈要改为第四个。
// if (circle < 0) {
// circle = ol.children.length - 1;
// }
circle = circle < 0 ? ol.children.length - 1 : circle;
//先清除其他小圆圈的current类名
//调用函数
circleChange();
})
function circleChange() {
for (var i = 0; i < ol.children.length; i++) {
ol.children[i].className = '';
}
ol.children[circle].className = 'current';
}
var timer = this.setInterval(function () {
//手动调用点击事件
next.click();
}, 3000)
})
- animate.js
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 调用的时候 callback()
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer);
obj.timer = setInterval(function () {
// 步长值写到定时器的里面
// 把我们步长值改为整数 不要出现小数的问题
// var step = Math.ceil((target - obj.offsetLeft) / 10);
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();
// }
callback && callback();
}
// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
节流阀
- 防止轮播图连续点击造成播放速度过快
- 目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。
- 核心思路:利用回调函数,添加一个变量来控制,锁住函数哈和解锁函数。
- 开始设置一个变量 var flag = true;
- if(flag){flag=false;dosomething}; 关闭水龙头
- 利用回调函数 动画执行完毕 ,flag = true;打开水龙头
if (flag) {
flag = false;
animate(ul, -num * imgWidth, function () {
flag = true;
})
}
返回顶部
- 滚动窗口至文档顶部
- window.scroll(x,y)
- x 和 y不跟单位,之间写数字
- 页面滚动了多少,可以通过window.pageOffset得到。
- 封装的函数:
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 调用的时候 callback()
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步长值写到定时器的里面
// 把我们步长值改为整数 不要出现小数的问题
// var step = Math.ceil((target - obj.offsetLeft) / 10);
var step = (target - window.pageYOffset) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (window.pageYOffset == target) {
// 停止动画 本质是停止定时器
clearInterval(obj.timer);
// 回调函数写到定时器结束里面
// if (callback) {
// // 调用函数
// callback();
// }
callback && callback();
}
// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
// obj.style.left = window.pageYOffset + step + 'px';
window.scroll(0, window.pageYOffset + step);
}, 15);
}
筋斗云案例
- 利用动画函数做出动画效果
- 原先筋斗云的其实位置是0
- 鼠标经过某个li,把当前的li的offsetLeft位置作为目标值即可。
- 鼠标离开某个li,就把目标值设为0
- 如果点击了某个li,就把li当前的位置储存起来,作为筋斗云的起始位置。
<script>
window.addEventListener('load', function() {
// 1. 获取元素
var cloud = document.querySelector('.cloud');
var c_nav = document.querySelector('.c-nav');
var lis = c_nav.querySelectorAll('li');
// 2. 给所有的小li绑定事件
// 这个current 做为筋斗云的起始位置
var current = 0;
for (var i = 0; i < lis.length; i++) {
// (1) 鼠标经过把当前小li 的位置做为目标值
lis[i].addEventListener('mouseenter', function() {
animate(cloud, this.offsetLeft);
});
// (2) 鼠标离开就回到起始的位置
lis[i].addEventListener('mouseleave', function() {
animate(cloud, current);
});
// (3) 当我们鼠标点击,就把当前位置做为目标值
lis[i].addEventListener('click', function() {
current = this.offsetLeft;
});
}
})
</script>
移动端的网页特效
触屏事件
- 移动端浏览器兼容性好,我们不需要考虑以前JS的兼容性问题,可以放心的使用原生的JS书写效果,但是移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android和IOS都有。
触屏touch事件 | 说明 |
---|---|
touchstart | 手指触摸到一个DOM元素时触发 |
touchmove | 手指再一个DOM元素滑动时触发 |
touchend | 手指从一个DOM元素上移开时触发 |
<body>
<div></div>
<script>
// 1. 获取元素
// 2. 手指触摸DOM元素事件
var div = document.querySelector('div');
div.addEventListener('touchstart', function() {
console.log('我摸了你');
});
// 3. 手指在DOM元素身上移动事件
div.addEventListener('touchmove', function() {
console.log('我继续摸');
});
// 4. 手指离开DOM元素事件
div.addEventListener('touchend', function() {
console.log('轻轻的我走了');
});
</script>
</body>
触摸事件对象(TouchEvent)
- TouchEvent是一类描述手指在触摸平面(触摸屏,触摸板等)的状态变化是事件,这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,增加和减少,等等。
- touchstart,touchmocve,touchend等三个事件都会各自有事件对象。
触摸事件
移动端拖动元素
- touchstart,touchmove,touchend可以实现拖动元素
- 但是拖动元素需要当前手指坐标值,我们可以用targetTouches[0]里面的pageX和pageY
- 移动端拖动原理:手指移动中,计算出手指移动的距离。然后用盒子原来的位置+手指移动的距离。
- 手指移动距离:手指滑动中的位置减去 手指刚开始触摸的位置。
拖动元素三部曲
- 触摸元素:touchstrat:获取手指初始坐标,同时获得盒子原来坐标。
- 移动手指:touchmove:计算手指的滑动距离,并且移动盒子。
- 离开手指 touchend:
- 注意:手指移动也会触发滚动屏幕,这里要阻止默认的屏幕滚动 e.preventDefault( )
<body>
<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 = x + moveX + 'px ';
this.style.top = y + moveY + 'px ';
e.preventDefault();//阻止屏幕滚动的默认行为
})
</script>
</body>
移动端常用特效
classList属性
classList属性是HTML5新增的一个属性,返回元素类名。但是ie10以上版本才支持。
- 可以添加类:element.claddList.add('类名') 注意不要加点。
- 可以删除类:element.removeList.add('类名')注意不要加点。
- 可以切换类:element.classList.toggle('类名')
<body>
<div class="one two"></div>
<button> 开关灯</button>
<script>
// classList 返回元素的类名
var div = document.querySelector('div');
// console.log(div.classList[1]);
// 1. 添加类名 是在后面追加类名不会覆盖以前的类名 注意前面不需要加.
div.classList.add('three');
// 2. 删除类名
div.classList.remove('one');
// 3. 切换类
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
document.body.classList.toggle('bg');
})
</script>
</body>
移动端轮播图
轮播图功能基本和PC端一致
- 可以自动播放图片
- 手指可以拖动播放轮播图
自动播放功能
- 开启定时器
- 移动端移动,可以使用translate移动
- 如果想让图片优雅的移动,请添加过渡效果。
自动播放功能-无缝滚动
- 注意:我们的判断条件时要等到图片滚动完毕再去判断,就是过渡完成后判断
- 此时需要添加检测过渡完成事件 transitionend
- 如果索引号变为3,此时就应该为0
- 此时,图片去掉过渡效果,然后移动
- 如果索引号小于0,相当于倒着走,索引号等于2
- 此时图片,去掉过滤效果,然后移动。
小圆点跟随变化的效果
- 把ol里面的li带有current类名的选出来去掉类名 remove
- 让当前索引号的小li 加上类名 current add.
- 但得等过渡结束后才变化,所以写到transitionend事件里面。
手指滑动轮播图
- 本质就是ul跟随手指移动,简单说就是移动端拖动元素。
- touchstart:获取手指初始坐标
- touchmove:计算手指的滑动距离,并且移动盒子。
- touchend:根据滑动的距离分不同的情况。
- 如果移动距离小于某个像素,就回弹原来位置
- 如果移动距离大于某个元素就上一张,下一张开始滑动。
js代码
window.addEventListener('load', function() {
// alert(1);
// 1. 获取元素
var focus = document.querySelector('.focus');
var ul = focus.children[0];
// 获得focus 的宽度
var w = focus.offsetWidth;
var ol = focus.children[1];
// 2. 利用定时器自动轮播图图片
var index = 0;
var timer = setInterval(function() {
index++;
var translatex = -index * w;
ul.style.transition = 'all .3s';
ul.style.transform = 'translateX(' + translatex + 'px)';
}, 2000);
// 等着我们过渡完成之后,再去判断 监听过渡完成的事件 transitionend
ul.addEventListener('transitionend', function() {
// 无缝滚动
if (index >= 3) {
index = 0;
// console.log(index);
// 去掉过渡效果 这样让我们的ul 快速的跳到目标位置
ul.style.transition = 'none';
// 利用最新的索引号乘以宽度 去滚动图片
var translatex = -index * w;
ul.style.transform = 'translateX(' + translatex + 'px)';
} else if (index < 0) {
index = 2;
ul.style.transition = 'none';
// 利用最新的索引号乘以宽度 去滚动图片
var translatex = -index * w;
ul.style.transform = 'translateX(' + translatex + 'px)';
}
// 3. 小圆点跟随变化
// 把ol里面li带有current类名的选出来去掉类名 remove
ol.querySelector('.current').classList.remove('current');
// 让当前索引号 的小li 加上 current add
ol.children[index].classList.add('current');
});
// 4. 手指滑动轮播图
// 触摸元素 touchstart: 获取手指初始坐标
var startX = 0;
var moveX = 0; // 后面我们会使用这个移动距离所以要定义一个全局变量
var flag = false;
ul.addEventListener('touchstart', function(e) {
startX = e.targetTouches[0].pageX;
// 手指触摸的时候就停止定时器
clearInterval(timer);
});
// 移动手指 touchmove: 计算手指的滑动距离, 并且移动盒子
ul.addEventListener('touchmove', function(e) {
// 计算移动距离
moveX = e.targetTouches[0].pageX - startX;
// 移动盒子: 盒子原来的位置 + 手指移动的距离
var translatex = -index * w + moveX;
// 手指拖动的时候,不需要动画效果所以要取消过渡效果
ul.style.transition = 'none';
ul.style.transform = 'translateX(' + translatex + 'px)';
flag = true; // 如果用户手指移动过我们再去判断否则不做判断效果
e.preventDefault(); // 阻止滚动屏幕的行为
});
// 手指离开 根据移动距离去判断是回弹还是播放上一张下一张
ul.addEventListener('touchend', function(e) {
if (flag) {
// (1) 如果移动距离大于50像素我们就播放上一张或者下一张
if (Math.abs(moveX) > 50) {
// 如果是右滑就是 播放上一张 moveX 是正值
if (moveX > 0) {
index--;
} else {
// 如果是左滑就是 播放下一张 moveX 是负值
index++;
}
var translatex = -index * w;
ul.style.transition = 'all .3s';
ul.style.transform = 'translateX(' + translatex + 'px)';
} else {
// (2) 如果移动距离小于50像素我们就回弹
var translatex = -index * w;
ul.style.transition = 'all .1s';
ul.style.transform = 'translateX(' + translatex + 'px)';
}
}
// 手指离开的时候就重新开启定时器
clearInterval(timer);
timer = setInterval(function() {
index++;
var translatex = -index * w;
ul.style.transition = 'all .3s';
ul.style.transform = 'translateX(' + translatex + 'px)';
}, 2000);
});
// 返回顶部模块制作
var goBack = document.querySelector('.goBack');
var nav = document.querySelector('nav');
window.addEventListener('scroll', function() {
if (window.pageYOffset >= nav.offsetTop) {
goBack.style.display = 'block';
} else {
goBack.style.display = 'none';
}
});
goBack.addEventListener('click', function() {
window.scroll(0, 0);
})
})
click延时解决方案
移动端click事件会有300ms的延迟,原因是移动端屏幕双击会缩放(double tap to zoom)页面。
解决方案:
- 禁用缩放,浏览器禁止用默认的双击缩放行为并且去掉300ms的延迟。
<meta name="viewport" content="user-sclable=no">
- 利用touch事件自己封装这个事件,解决300ms延迟。
- 弊端:只能解决一个元素的问题
//封装top解决 click300ms 延时
function tap(obj, callback) {
var isMove = false;
var starTime = 0;//记录触摸时的时间变量
obj.addEventListener('touchstart', function (e) {
starTime = Date.now();//记录触摸时间
});
obj.addEventListener('touchmove', function (e) {
isMove = true;//看看是否有滑动,有滑动拖拽,不算点击
});
obj.addEventListener('touchend', function (e) {
if (!isMove && (Date.now() - starTime) < 150) {//如果手指触摸和离开时间小于150ms算点击
callback && callback();//执行回调函数
}
isMove = false;//取反 重置
starTime = 0;
});
}
tap(div, function () {
//执行代码
});
- 使用插件。fastclick插件解决300ms延迟。
插件:它一般是为了解决某个问题而专门存在的,且功能单一,并且比较小。
Swiper插件的使用
- 引入插件相关文件
- 按照规定语法使用
注意:要引入css和js文件,而且对于引入,应该写引入Swiper插件,在引入自己的
superslide插件
iscroll插件
移动端视频插件 zy.media.js
H5提供了video标签,但是浏览器支持情况不同。
不同的视频格式文件,我们可以通过sourse解决
但是外观,样式,暂停,播放只能自己解决。
这时,我们可以使用插件来制作。
移动端常用开发框架
- 框架:一套架构,它会基于自身的特点向用户提供一套较为完整的解决方案,框架的控制权仅在框架本身,使用者要按照框架所规定的某种规范进行开发。
- 插件:一般是为了解决某个问题而专门存在,其功能单一,并且比较小。
前端常用框架
- 框架(大而全,一整套解决方案)
Bootstrap,Vue,Augular,React等。既能开发PC端,也可以开发移动端 - 插件(小而专一,某个功能的解决方案)
swiper,superslide,iscroll 等
本地存储
随着互联网的快速发展,基于网页的应用越来越普遍,同时越来越复杂,为了满足各种各样的需求,会经常性的存储大量数据,HTML规范提出了相关解决方案。
本地存储特性
数据存储
在用户浏览器- 设置,读取方便,甚至页面刷新不丢失数据
- 容量较大,sessionStorag约5MB,localstorage约20M
- 只能存储字符串,可以将对象JSON.stringify() 编码后存储
Window.sessionStriage
生命周期
为关闭浏览器窗口(数据在何时存在)- 在同一个窗口(页面)下数据可以共享
- 以
键值对
的形式存储使用
存储数据:
<script>
sessionStorage.setItem(key, value)
</script>
获取数据:
<script>
sessionStorage.getItem(key)
</script>
删除数据
<script>
sessionStorage.removeItem(key)
</script>
删除所有数据
<script>
sessionStorage.clear()
</script>
window.localStorage
生命周期永久生效
,除非手动删除,否则关闭页面也会存在。- 可以窗口(页面)共享(同一浏览器可以共享)
- 键值对存储
存储数据:
<script>
localStorage.setItem(key, value)
</script>
获取数据:
<script>
localStorage.getItem(key)
</script>
删除数据
<script>
localStorage.removeItem(key)
</script>
删除所有数据
<script>
localStorage.clear()
</script>
总结:两者方法极其相似,找一个纪就可以
JSON
轻量级数据的转换
JSON.stringify()
对象转字符串
//存储字符串:对象-》字符串 JSON.stringfy()
console.log(obj);
console.log(JSON.stringify(obj));
localStorage.obj = JSON.stringify(obj);
JSON.parse()
字符串转对象
//字符串转换成对象后,再输出
console.log(JSON.parse(localStorage.obj));
JavaScript中对象的拷贝
浅拷贝
传址拷贝,直接拷贝对象的内存地址,修改拷贝的数据,原始数据也会改变。
深拷贝
新开辟一块内存
,将对象中的所有属性全部复制,原地址中对象改变了,深拷贝出来的对象也不变。
- 深拷贝的
两种
方式
- 通过json.stringify() 先将对象转换成字符串,再JSON.parse()转换成对象.
- 递归遍历,逐层拷贝,封装一个递归函数。
function dedCopy(o) {
if (Array.isArray(o)) {
var result = [];
} else if (typeof o == 'object') {
var result = {};
} else {
var result = o;
}
for (var i in o) {
if (typeof o[i] == 'object') {
result[i] = dedCopy(o[i])
} else {
result[i] = o[i]
}
}
return result;
}
ES6
ES6文档[2]
作用域
块级作用域
ES6有了块级作用域的概念
{} , var 不识别块级作用域, let ,const 识别块级作用域。
let关键字
- 声明变量
- 识别块级作用域
- 不存在变量提升
- 不能重复声明
const关键字
- 声明常量
- 识别块级作用域
- 不存在变量提升
- 不能重复声明
解构赋值
let [a, b, c] = [1, 4, 5]
console.log(`${a},${b},${c}`);
1,4,5
对象的解构赋值
变量必须与属性名相同才能赋值,解构失败为undefined
函数
函数可以给形参
添加默认值
function fn(s, y = 1) {
console.log(y);
}
fn()
参数个数于赋值情况
- 形参 > 实参
- arguments对象:接受全部的实参。
- rest参数:接受多余的参数,将多余的参数放到数组中。
箭头函数
- 用字面量的方式来声明函数,没有函数提升。
var fu = function () {
console.log(111);
}
fu()
var fn = () => {
return console.log(2);
}
var sum = (sum1, sum2) => sum1 + sum2
var sum = (num1, num2) => {
var sum = num1 + num2
return sum
}
jQuery概述
Javascript库
即library,是一个封装好的特定的集合(方法和函数),从封装一大堆函数的角度理解库,就是在这个库中,封装了很多预先定义好的函数在里面,比如动画 animate,hide,show,比如获取元素等。
简单理解:就是一个JS文件,里面对我们原生的js代码进行了封装,存放到里面。这样我们可以快速高效的使用这些封装好的功能了。
比如jQuery,就是为了快速方便的操作DMO,里面基本是函数和方法
常见的JavaScript库
- jQuery
- Prototype
- YUI
- Dojo
- Ext Js
- 移动端的zepto
这些库都是对原生javaScript的封装,内容都是用javaScript实现的,我们主要学习的是jQuery.
jQuery的概述
jQuery是一个快速,简洁的JavaScript库,其设计宗旨就是"write Less ,Do More",即编写更少的代码,做更多的事情。
j就是JavaScript; Query查询:意思就是查询js,把js中的DOM操作做了封装,我们可以快速的查询使用里面的功能。
jQuery封装了JavaScript常见的功能和代码,优化了DOM操作,事件处理,动画设计和Ajax交互
学习JQuery的本质:就是学习调用这些函数(方法)。
jQuery的优点
- 轻量级,核心文件几十kb,不会影响网页的加载速度
- 跨浏览器兼容,基本兼容了现在主流的浏览器
- 链式编程,隐式迭代
- 对事件,样式,动画支持,大大简化了DOM操作
- 支持插件扩展开发。有着丰富的第三方库,例如:树形菜单,日期控件轮播图等
- 免费,开源
jQuery的基本使用
jQuery的入口函数
$(function () {
...//此处填写页面DOM加载完成的入口
});
$(document).ready(function () {
...//此处是页面DOM加载完成的入口
});
- 代码示例
<script>
$(document).ready(function () {
$('div').hide();
})
$(function () {
$('div').hide;
})
</script>
- 等着DOM结构渲染完毕即可执行内部代码,不必等到所有外部资源加载完毕,jQuery帮我们完成了封装。
- 相当于原生js中的DOMContentLoaded.
- 不同于原生js中的load事件是等页面文档,外部的js文件,css文件,图片
加载完毕
后才执行内部代码。 - 更推荐使用第一种方式。
jQuery的顶级对象 $
- 是jQuery的
别称
,在代码中可以使用jQuery代替$,但一般为了方便,通常都直接使用$. $
是jQuery
的顶级对象
,相当于原生javascript中的window
,把元素利用$包装成jQuery对象,就可以调用jQuery的方法。
jQuery对象和DOM对象
- 用
原生JS
获取来的对象就是DOM对象 - jQUery方法获取的元素就是jQuery对象。
- jQuery对象的本质就是:利用$ 对DOM对象包装后产生的对象(
伪数组
形式存储)
<script>
//1. DOM对象:用原生的js获取过来的对象就是DOM对象
var myDiv = document.querySelector('div');
var mySpan = document.querySelector('span');
console.log(myDiv);
//2. JQuery对象:用jquery方式获取过来的对象是jQuery对象。本质:通过$ 把DOM元素进行了包装
$('div');//JQuery对象
console.dir($('div'))
$('span')
//3. jQuery对象只能用jQuery方法,DOM对象则使用原生的JavaScript属性和方法
myDiv.style.display = 'none';
// $('span').style.display = 'none'; 这个$('span')是一个jQuery对象,不能使用原生的js的属性和方法。
</script>
jQuery对象只能用jQuery方法,DOM对象则使用原生的JavaScript属性和方法
DOM和jQuery对象之间的转换
因为原生的js比jQuery更大,原生的一些属性和方法jQuery没有给我们封装,要想使用这些属性和方法必须要把jQuery对象转换为DOM对象才可以使用。
- DOM对象转换成jQuery对象:$(DOM对象)
$('video')
var myvideo = document.querySelector('video');
$(myvideo)
- jQuery对象转换成DOM对象(两种方式)
$('video')[0].play()
$('video').get(0).play()
注意:因为jQuery对象是伪数组,所以要用索引号。
$('div')[index]
$('div'.get(index))
index是索引号
jQuery常用API
jQuery基础选择器
原生JS获取元素方法很多,很杂,而且兼容性情况不一致,因此jQuery给我们做了封装,使得获取元素统一标准。
$("选择器") //里面选择器直接写css选择器就可以,但是要加引号zz
名称 | 用法 | 描述 |
---|---|---|
ID选择器 | $(”#id“) | 获取指定ID元素 |
全选择器 | $(” * “) | 匹配所有元素 |
类选择器 | $(”.class“) | 获取同一类class元素 |
标签选择器 | $(”div“) | 获取同一类标签的所有元素 |
并集选择器 | $(”div,p,li“) | 获取多个元素 |
交集选择器 | $(”li.current“) | 交集元素 |
jQuery层级选择器
名称 | 用法 | 描述 |
---|---|---|
子代选择器 | $(”ul>li“) | 使用> 号,获取亲儿子层级的元素;注意,并不会获取孙子层级的元素 |
后代选择器 | $(”ul li“) | 使用空格,代表后代选择器,获取ul下的所有li元素,包括孙子 |
JQuery设置样式
$('div').css('color(属性)', 'pink(值)')
隐式迭代(重要)
遍历内部DOM元素(伪数组形式存储)的过程就叫隐式迭代
。
简单理解:给匹配到的所有元素
循环进行遍历,执行相应的方法,而不用我们再进行循环,简化我们的操作,方便我们调用。
jQuery筛选器
语法 | 用法 | 描述 |
---|---|---|
:first | $(”li:first“) | 获取第一个li |
:last | $(”li:last“) | 获取最后一个li |
:eq(index) | $(”li:eq(2“) | 获取到的li元素中,选择索引号为2的元素,索引号从0开始 |
:odd | $(”li:odd“) | 获取到的li元素中,选择索引号为奇数的元素 |
:even | $(”li:even“) | 获取到的li元素中,选择索引号为偶数的元素 |
jQuery筛选方法(重点)
语法 | 用法 | 描述 |
---|---|---|
parent() |
$(”li“).parent(); | 查找父级 |
children(selector) |
$(”ul“).chilren("li") | 相当于$("ul>li"),最近一级(亲儿子) |
find(selector) |
$(”ul“).find("li") | 相当于$("ul li"),后代选择器 |
siblings(selector) |
$(”.first“).siblings("li") | 查找兄弟节点,不包括本身 |
nextAll[expr] | $(”.first“).nextAll() | 查找当前元素之后的所有同辈元素 |
prevtAll[expr] | $(”.last“).prevAll() | 查找当前元素之前的所有同辈元素 |
hasClass(class) | $(”div“).hasClass("protected") | 检查当前的元素是否含有某个特定的类,如果有,则返回true |
eq(index) |
$(”li“).eq(2) | 相当于$("li:eq(2)").index从0开始 |
新浪下拉菜单(案例)
<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>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
a {
text-decoration: none;
font-size: 14px;
}
.nav {
margin: 100px;
}
.nav>li {
position: relative;
float: left;
width: 80px;
height: 41px;
text-align: center;
}
.nav li a {
display: block;
width: 100%;
height: 100%;
line-height: 41px;
color: #333;
}
.nav>li>a:hover {
background-color: #eee;
}
.nav ul {
display: none;
position: absolute;
top: 41px;
left: 0;
width: 100%;
border-left: 1px solid #FECC5B;
border-right: 1px solid #FECC5B;
}
.nav ul li {
border-bottom: 1px solid #FECC5B;
}
.nav ul li a:hover {
background-color: #FFF5DA;
}
</style>
<script src="jquery.min.js"></script>
</head>
<body>
<ul class="nav">
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
</ul>
<script>
$(function() {
// 鼠标经过
$(".nav>li").mouseover(function() {
// $(this) jQuery 当前元素 this不要加引号
// show() 显示元素 hide() 隐藏元素
$(this).children("ul").show();
});
// 鼠标离开
$(".nav>li").mouseout(function() {
$(this).children("ul").hide();
})
})
</script>
</body>
jQuery里面的排他思想
想要多选一的效果,排他思想;当前元素设置样式,其余的兄弟元素清除样式。
<button>快速</button>
<button>快速</button>
<button>快速</button>
<button>快速</button>
<button>快速</button>
<button>快速</button>
<button>快速</button>
$(function () {
// 1. 隐式迭代 给所有的按钮都绑定了点击事件
$("button").click(function () {
// 2. 当前的元素变化背景颜色
$(this).css("background", "pink");
// 3. 其余的兄弟去掉背景颜色 隐式迭代
$(this).siblings("button").css("background", "");
});
})
淘宝服饰精品案例分析(案例)
核心原理:鼠标经过左侧小盒子某个li,就让内容区盒子相对应的图片显示,其余图片隐藏。
- 需要得到当前的li的索引号,就可以显示对应索引号的图片。
- jQuery得到当前元素索引号
$(this)..index()
- 中间对应的图片,可以通过eq(index)方法去选择。
- 显示元素show() 隐藏元素 hide()
$(function () {
$("#left li").mouseover(function () {
//li背景颜色的排他思想
$(this).css("background", "pink");
$(this).siblings("li").css("background", "")
// 让其他图片隐藏
var index = $(this).index();
$("#content div").eq(index).show();
$("#content div").eq(index).siblings().hide();
})
})
链式编程
链式编程
是为了节约代码量
,看起来更优雅。
$(this).css("color", "red").siblings().css("color", "");
jQuery修改样式css方法
jQuery
可以使用css方法
修改简单元素样式;也可以操作类,修改多个样式。
- 参数只写属性名,则是返回属性值
$(this).css('color');
- 参数是属性名,属性值,逗号分隔,是设置一组样式,属性必须加引号,值如果是数字可以不用跟单位和引号。
$(this).css('color', "red");
- 参数可以设置对象,方便设置多组样式。属性名和属性值用
冒号
隔开,属性
可以不用加引号
。
$(this).css({
"color": "white",
"font-size": "20px"
});
tab栏切换分析(案例)
- 点击上部的li,当前的li添加current类,其余兄弟移除类。
- 点击的同时,得到当前li的索引号。
- 让下部里面相应索引号item显示,其余item隐藏。
案例:jQuery - 第一天 - 16
<script>
$(function() {
// 1.点击上部的li,当前li 添加current类,其余兄弟移除类
$(".tab_list li").click(function() {
// 链式编程操作
$(this).addClass("current").siblings().removeClass("current");
// 2.点击的同时,得到当前li 的索引号
var index = $(this).index();
console.log(index);
// 3.让下部里面相应索引号的item显示,其余的item隐藏
$(".tab_con .item").eq(index).show().siblings().hide();
});
})
</script>
类操作与className区别
原生js中className
会覆盖
元素里面的类名。
jQuery里面类操作对象会指定元素进行操作,不影响原先的类名
。
<body>
<div class="one two"></div>
<script>
// var one = document.querySelector(".one");
// one.className = "two";
// $(".one").addClass("two"); 这个addClass相当于追加类名 不影响以前的类名
$(".one").removeClass("two");
</script>
</body>
jQuery效果
jQuery给我们封装了很多动画效果,最为常见的如下:
作用 | 相关函数 |
---|---|
显示隐藏 | show();hide();toggle() |
滑动 | slideDown();slideUp();slideToggle() |
淡入淡出 | fadeln();fadeOut();fadeToggle();fadeTo() |
自定义动画 | animate() |
显示隐藏效果
- 显示语法规范
show([speed,[easing],[fn]])
- 显示参数
- 参数都可以省略,无动画直接显示。
- speed:三种预定速度之一的字符串("slow","nomal",or "fast")或表示动画时长的毫秒数值(如:1000).
- easing:(Optional)用来指定切换效果,默认是"swing",可用参数"linear".
- fn:回调函数,再动画完成时执行函数,每个元素执行
函数名 | 作用 |
---|---|
显示 | show() |
隐藏 | hide() |
切换(点击一下显示,点击一下隐藏) | toggle() |
<body>
<button>显示</button>
<button>隐藏</button>
<button>切换</button>
<div></div>
<script>
$(function() {
$("button").eq(0).click(function() {
$("div").show(1000, function() {
alert(1);
});
})
$("button").eq(1).click(function() {
$("div").hide(1000, function() {
alert(1);
});
})
$("button").eq(2).click(function() {
$("div").toggle(1000);
})
});
</script>
</body>
一般情况下,我们都不加参数直接显示隐藏就可以了,切换样式太丑了
滑动效果
函数名 | 作用 |
---|---|
下拉滑动 | slideDown() |
上拉滑动 | slideUp() |
切换滑动 | slideToggle() |
- 滑动效果语法规范
- 下滑效果参数
- 参数都可以省略
- speed:三种预定速度之一的字符串("slow","normal",or "fast")或表示动画时长的毫秒数值(如:1000);
- easing:(Opatonal)用来指定切换效果,默认是"swing",可用参数"linear".
- fn:回调函数,在动画完成时执行函数,每个元素执行一次。
<body>
<button>下拉滑动</button>
<button>上拉滑动</button>
<button>切换滑动</button>
<div></div>
<script>
$(function() {
$("button").eq(0).click(function() {
// 下滑动 slideDown()
$("div").slideDown();
})
$("button").eq(1).click(function() {
// 上滑动 slideUp()
$("div").slideUp(500);
})
$("button").eq(2).click(function() {
// 滑动切换 slideToggle()
$("div").slideToggle(500);
});
});
</script>
</body>
事件切换
hover([over,]out)
- over:鼠标移动到元素上要触发的函数(相当于mouseenter)
- out:鼠标移出元素要触发的函数(相当于mouseleava)
<script>
$(function() {
// 鼠标经过
// $(".nav>li").mouseover(function() {
// // $(this) jQuery 当前元素 this不要加引号
// // show() 显示元素 hide() 隐藏元素
// $(this).children("ul").slideDown(200);
// });
// // 鼠标离开
// $(".nav>li").mouseout(function() {
// $(this).children("ul").slideUp(200);
// });
// 1. 事件切换 hover 就是鼠标经过和离开的复合写法
// $(".nav>li").hover(function() {
// $(this).children("ul").slideDown(200);
// }, function() {
// $(this).children("ul").slideUp(200);
// });
// 2. 事件切换 hover 如果只写一个函数,那么鼠标经过和鼠标离开都会触发这个函数
$(".nav>li").hover(function() {
$(this).children("ul").slideToggle();
});
})
</script>
事件切换 hover 如果只写一个函数,那么鼠标经过和鼠标离开都会触发这个函数。
jQuery动画队列及其停止排队方法
- 动画或效果队列
动画或者效果一旦触发就会执行,如果多次触发,就造成多个动画或者效果队列执行。 - 停止排队
stop()
stop()方法用于停止动画或效果。
注意
:stop()写到动画或者效果的前面,相当于停止结束上一次的动画
。
<script>
$(function() {
// 鼠标经过
// $(".nav>li").mouseover(function() {
// // $(this) jQuery 当前元素 this不要加引号
// // show() 显示元素 hide() 隐藏元素
// $(this).children("ul").slideDown(200);
// });
// // 鼠标离开
// $(".nav>li").mouseout(function() {
// $(this).children("ul").slideUp(200);
// });
// 1. 事件切换 hover 就是鼠标经过和离开的复合写法
// $(".nav>li").hover(function() {
// $(this).children("ul").slideDown(200);
// }, function() {
// $(this).children("ul").slideUp(200);
// });
// 2. 事件切换 hover 如果只写一个函数,那么鼠标经过和鼠标离开都会触发这个函数
$(".nav>li").hover(function() {
// stop 方法必须写到动画的前面
$(this).children("ul").stop().slideToggle();
});
})
</script>
注意:方法必须写到动画的前面.
淡入淡出效果
函数名 | 作用 |
---|---|
淡入 | fadeIn() |
淡出 | fadeOut() |
透明度 | fadeTo() |
切换(淡入淡出相互切换)) | fadeToggle() |
- 渐进方式调整到指定的不透明度
fadeTo([speed,opcity,[easing],[fn]])
- 效果参数
opacity
透明度必须写,取值0~1之间
.- speed:三种预定速度之一的字符串("slow","normal",or"fast")或表示动画时长的毫秒数值(如:1000).必须写
- easing:(Optional)用来指定切换效果,默认是"swing",可用参数"linear".
- fn:回调函数,在动画执行完成时执行函数,每个元素执行一次.
$("button").eq(3).click(function() {
// 修改透明度 fadeTo() 这个速度和透明度要必须写
$("div").fadeTo(1000, 0.5);
});
淡入淡出小案例(唱戏小人)
主要思想 :透明度的排他思想,使用了hover,设置了鼠标移入和鼠标移除的效果,使用stop函数,停止了动画排队.
<script>
$(function() {
//鼠标进入的时候,其他的li标签透明度:0.5
$(".wrap li").hover(function() {
$(this).siblings().stop().fadeTo(400, 0.5);
}, function() {
// 鼠标离开,其他li 透明度改为 1
$(this).siblings().stop().fadeTo(400, 1);
})
});
</script>
自定义动画animate
- 语法
animate(params,[speed],[easing],[fn])
- 参数
params
: 想要更改的样式属性,以对象的形式传递,必须写
.属性名可以不用带引号
,如果是复合函数属性
,则需要采取驼峰命名法
borderLeft.其余参数都可以省略
.- speed:三种预定速度之一的字符串("slow","normal",or"fast")或表示动画时长的毫秒数值(如:1000).必须写
- easing:(Optional)用来指定切换效果,默认是"swing",可用参数"linear".
- fn:回调函数,在动画执行完成时执行函数,每个元素执行一次.
王者荣耀手风琴效果分析
- 鼠标经过某个li 有两个操作
- 当前小li 宽度变为224px,同时里面的小图片淡出,大图片淡入
- 其余兄弟小li 宽度变为69px,小图片淡入,大图片淡出。
设置或获取元素固有属性 prop( )
所谓元素固有属性就是元素自带的属性,比如 < a > 里面的href,比如< input >里的typpe
- 获取属性语法
prop('属性')
- 设置属性语法
prop('属性','属性值')
//1. element.prop("属性名") 获取元素固有的属性值
console.log($("a").prop("href"));
$("a").prop("title", "我们都挺好");
$("input").change(function() {
console.log($(this).prop("checked"));
});
设置或获取元素自定义属性 attr( )
用户自己给元素添加的属性,我们称为自定义属性,比如给 div 添加 Index ="1".
- 获取属性语法
attr('属性') //类似原生 getAttribute()
- 设置属性语法
attr('属性','属性值') //类似原生 setAttribute()
// console.log($("div").prop("index"));
// 2. 元素的自定义属性 我们通过 attr()
console.log($("div").attr("index"));
$("div").attr("index", 4);
console.log($("div").attr("data-index"));
// 3. 数据缓存 data() 这个里面的数据是存放在元素的内存里面
数据缓存 data()
data() 方法可以在指定的元素上获取元素,并不会修改DOM元素结构。一旦页面刷新,之前存放的元素就将被移除。
把元素当作变量来看,把数据存放到内存里。
- 附加数据语法
data("name","value") //向被选元素附加数据
- 获取数据语法
date("name") //向被选元素获取数据。
同时还可以读取html5自定义属性data-index ,得到的是数字型。
// 3. 数据缓存 data() 这个里面的数据是存放在元素的内存里面
$("span").data("uname", "andy");
console.log($("span").data("uname"));
console.log($("div").data("index"));
这个方法获取data-index h5自定义属性 第一个 不用写data- 而且返回的是数字型
jQuery元素操作
主要是遍历
,创建,添加,删除元素操作。
jQuery遍历元素
jQuery隐式迭代
是对同一类元素做了同样的操作。如果想要给同一个元素做不同的操作,就需要用到遍历。
- 语法一
$("div").each(function (index, domEle) { xxx; })
each()方法遍历匹配每一个元素。主要用DOM处理,each每一个
里面的回调函数有两个参数:index是每个元素的索引号,demEle是每个元素的DOM元素对象,不是jQuery对象。
- 语法二
$each(object,function(index,element){ xxx;})
$.each()方法可以用于遍历任意对象,主要用于数据处理,比如数组,对象
里面的函数有两个参数:index是每个元素的索引号,element遍历内容
$.each({
name: "andy",
age: 18
}, function (i, ele) {
console.log(i); // 输出的是 name age 属性名
console.log(ele); // 输出的是 andy 18 属性值
})
// $("div").each(function (index, domEle) { xxx; })
})
创建元素
语法:
$("<li></li>")
动态创建li标签
添加元素
- 内部添加
element.append("内容")
$("ul").append(li)
$("ul").prepend(li)
element.append("内容") 把内容放到匹配元素的最后面,类似原生的appendChild。
element.prepend("内容") 把内容放到匹配元素的最前面,类似原生的insertBefore
- 外部添加
var div = $("<div>我是真的</div>")
element.after("内容") //放到目标元素后面
element.before("内容") //放到目标元素前面
$(".test").after(div)
$(".test").before(div)
内部
添加元素后,生成之后,它们是父子
关系
外部
添加元素后,生成之后,它们是兄弟
关系
删除元素
element.remove()
删除匹配的元素(本身)
element.empty()
删除匹配的元素集合中的所有子节点(本身不会被删除)
element.html("")
清空匹配的元素内容
购物车删除案例
// 6. 删除商品模块
// (1) 商品后面的删除按钮
$(".p-action a").click(function() {
// 删除的是当前的商品
$(this).parents(".cart-item").remove();
getSum();
});
// (2) 删除选中的商品
$(".remove-batch").click(function() {
// 删除的是小的复选框选中的商品
$(".j-checkbox:checked").parents(".cart-item").remove();
getSum();
});
// (3) 清空购物车 删除全部商品
$(".clear-all").click(function() {
$(".cart-item").remove();
getSum();
})
jQuery尺寸
语法 | 作用 |
---|---|
width()/height() | 取得匹配元素宽度和高度值 只算 width/height |
innerWidth()/innerHieght() | 取得匹配元素的宽度和高度值包含 padding |
outerWidth()/outerHeight() | 取得匹配元素宽度和高度值 包含padding,border |
outerWidth(ture)/outerHeight(true) | 取得匹配元素宽度和高度值 包含padding,borde,margin |
以上参数为空,则是获取相应属性,返回的是数字型
如果参数为数字,则是修改相应的值
参数可以不必写单位
jQuery位置
位置主要有三个 :offset()
,position( )
, scrollTop( ) / scrollLeft( )
- offset()
设置
或获取元素偏移- offset()方法设置返回被选元素相对于
文档
的偏移坐标,和父级没有关系
。 - 该方法有两个属性
left
,top
.offset().top
用于获取距离文档顶部
的距离,offset().left
用于获取距离文档左侧
的距离。 - 可以设置元素的偏移量: offset({top:10,left:30});
- offset()方法设置返回被选元素相对于
console.log($(".son").offset());
console.log($(".son").offset().top);
$(".son").offset({
top: 200,
left: 200
});
- position()获取元素偏移
- position( )方法用于返回被选元素相对于带有定位的父级偏移坐标,如果父级没有定位,则以文档为准。
console.log($(".son").position());
这个方法只能获取不能设置偏移
- scrollTop()/scrollLeft() 设置或获取元素被卷去的头部和左侧
- scrollTop()方法设置或返回被选元素被卷去的头部。
卷去头部隐藏”返回顶部“按钮(案例)
$(function() {
$(document).scrollTop(100);
// 被卷去的头部 scrollTop() / 被卷去的左侧 scrollLeft()
// 页面滚动事件
var boxTop = $(".container").offset().top;
$(window).scroll(function() {
// console.log(11);
console.log($(document).scrollTop());
if ($(document).scrollTop() >= boxTop) {
$(".back").fadeIn();
} else {
$(".back").fadeOut();
}
});
// 返回顶部
$(".back").click(function() {
//没有动画效果
// $(document).scrollTop(0);
$("body, html").stop().animate({
scrollTop: 0
});
// $(document).stop().animate({
// scrollTop: 0
// }); 不能是文档而是 html和body元素做动画
})
})
带有动画的返回顶部
- 核心原理:使用animate动画返回顶部。
- animate动画函数里面有个scrollTop属性,可以设置位置。
- 但是是
元素
做动画,因此$("body,htmt").animate({scrollTop:0}),不能是文档,而是html和body做动画。
jQuery事件注册
单个事件注册
语法:
element.事件(funcation(){})
$("div").click(funcation(){ 事件处理程序 })
$("div").click(function () {
$(this).css("background", "purple");
});
其他事件和原生基本一致。
比如 mouseover, mouseout,blur, focus,change,keydown,keyup,resize,scroll等
jQuery事件处理
1. 事件处理on() 绑定事件
on() 方法在匹配元素上绑定一个或多个事件的事件处理函数
语法:
element.on(events,[selector],fn)
- events;一个或多个用空格分隔的事件类型,如"click"或"keydown"。
- selector:元素子元素选择器。
- fn:回调函数,即绑定在元素身上的侦听函数。
$("div").on({
mouseenter: function() {
$(this).css("background", "skyblue");
},
click: function() {
$(this).css("background", "purple");
},
mouseleave: function() {
$(this).css("background", "blue");
}
});
on( )方法优势1:
可以绑定多个事件,多个处理事件处理函数
on( )方法优势2:
可以事件委派操作。事件委派的定义就是,把原来加给子元素身上的事件绑定在父元素身上,就是把事件委派给父元素。
在此之前有bind(),live() delegate()等方法来处理事件绑定或者事件的委派,最新版本请用on
替代它们。
on( )方法优势3:
动态创建的元素,click()没有办法绑定事件,on() 可以动态生成的元素绑定事件。
2. 事件处理off() 解绑事件
off( )方法可以移除通过on( )方法添加的事件处理程序。
$("div").off(); // 这个是解除了div身上的所有事件
$("div").off("click"); // 这个是解除了div身上的点击事件
$("div").off("click","li"); //解除事件委派
如果有的事件只想触发一次,可以使用one()来绑定事件。
// 2. one() 但是它只能触发事件一次
$("p").one("click", function() {
alert(11);
})
3.自动触发事件 trigger( )
有些事件希望自动触发,比如轮播图自动播放功能和右键点击右侧按钮一致,可以利用定时器触发右侧按钮点击事件,不必鼠标点击触发。
- 第一种简写形式
element.click()
- 自动触发模式
element.trigger("type")
- 自动触发事件 trigger( )
element.triggerHandler(type)
$("div").triggerHandler("click");
$("input").on("focus", function() {
$(this).val("你好吗");
});
jQuery事件对象
事件被触发,就会有事件对象的产生
element.on(events,[selector],funcation(event){})
阻止默认行为: event.privientDefault() 或者 return false
阻止冒泡: event.stopPropagation( )
jQuery对象拷贝
如果想要把某个对象拷贝(合并)给另外一个对象使用,此时可以使用$.extend()方法
- 语法:
$.extend([deep] , target,objectl,[objectN])
$.extend(target, obj);
- 把obj给targetObj.
var targetObj = {};
var obj = {
id: 1,
name: "andy"
};
$.extend(targetObj, obj);
- deep:如果设置为true为深拷贝,默认为false 浅拷贝
- target:要拷贝的目标对象
- object1:待拷贝的第一个对象的对象。
var targetObj = {
id: 0
};
var obj = {
id: 1,
name: "andy"
};
// $.extend(target, obj);
$.extend(targetObj, obj);
console.log(targetObj); // 会覆盖targetObj 里面原来的数据
浅拷贝是把被拷贝对象
复杂数据类型
中的地址拷贝给对象,修改目标对象会影响被拷贝
的对象
因为拷贝后指向的是地址,所以目标拷贝对象修改后,拷贝对象也会改变。
$.extend(true, targetObj, obj);
深拷贝把里面的
数据完全复制
一份给目标对象 如果里面有不冲突的属性,会合并到一起
jQuery多库共存
问题:
jquery使用$作为标识符,随着JQuery的流行,其他的Js库也会用这$作为标识符,这样一起使用就会说引起冲突。
客观需求:
需要一个解决方案,让jQuery和其他的js库不存在冲突,可以同时存在,这叫多库共存。
jQuery解决方案:
- 统一把
$
符号改为jQuery
。比如jQuery("div") - jQuery变量规定新的名称:$onConflict( ) var xx = $.noConflict( );
<script>
$(function() {
function $(ele) {
return document.querySelector(ele);
}
console.log($("div"));
// 1. 如果$ 符号冲突 我们就使用 jQuery
jQuery.each();
// 2. 让jquery 释放对$ 控制权 让用自己决定
var suibian = jQuery.noConflict();
console.log(suibian("span"));
suibian.each();
})
</script>
jQuery插件
jQuery插件功能有限,想要更加复杂的特效效果,可以借助于jQuery插件完成。
注意:这些插件是依赖于JQuery来完成时的,所以
必须先引入jQuery文件
,因此也称为jQuery插件
jQuery插件常用的网站:
jQuery插件的使用步骤:
- 引入相关文件。(jQuery文件和插件)
- 复制相关html,css,js(调用插件)
图片懒加载技术
图片懒加载:图片使用延迟加载可以高网页下载速度
它也能帮助轻服务器负载
当我们页面滑动到可视区域,再显示图片。
我们使用jquery插件库 EasyLoad 。
注意,此时的js引入文件和js调用必须写道DOM元素
图片
最后面。
bootstrap JS插件
bootstrap框架也是依赖于jQuery开发的,因此里面的js插件使用,也必须引入jQuery文件。
案例:toDoList
核心思路以及本地存储数据格式
- 文本框里面输入内容,按下回车,就可以生成待办事项
- 点击代办事项复选框,就可以把当前的数据添加到已经完成的事项里面
- 点击已完成事项的复选框,就可以把当前数据添加到代办事项里面。
但是本页面的内容刷新不会丢失
使用localstorage来存储数据,可以满足第4点要求。
核心思路:不管按下回车,还是点击复选框,就是把本地存储的数据加载到页面中,这样保证刷新页面不hi丢失数据。
存储数据格式: var todolist = [{ tatle:'xxx', done: false}]
注意点1 :本地存储localStrage
里面只能存储字符串格式
,因此需要把对象
转换成字符串 Json.stringify(data)
注意点2:获取
本地存储数据,需要把里面的字符串
转换成对象格式JSON.parse()
我们才可以用里面的数据
数组对象转换成字符串格式 JSON.stringify( )
- 本地存储里面只能存储字符串的数据格式,把我们的数组对象转换成字符串的格式
localStorage.setItem("todo", JSON.stringify(todolist))
字符串转格式转换成数组对象 JSON.parse()
var data = localStorage.getItem("todo")
data = JSON.parse(data)
toDolist按下回车读取本地存储数据
- 切记:页面中的数据,都要从本地存储里获取,这样刷新页面就不会丢失,所以把数据保存到本地存储里面。
- 利用
事件对象.keyCode
判断用户按下回车键(13)- 声明一个数组,保存数组
- 先要读取本地存储里面的数据(声明函数 getData()) ,反到这个数组里面。
- 之后把最新的表单获取过来,追加到数组里面。
- 最后把数组存储给本地存储(声明函数 saveDate( ))
toDoList本地存储加载到页面
- 因为后面也会经常渲染加载操作,所以声明一个函数load,方便后面调用。
- 先要读取本地存储数据(数据要转换成对象格式)
- 之后遍历这个数据($.each()),有几条数据,就生成几个li添加到ol中。
layui的介绍和使用
做项目是遇到的问题
1.弹出二级导航栏后鼠标移入导航栏不消失
附录
ASCII表
ECMAScript6
阮一峰ES6入门
ECMAScript6 ↩︎
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)