JavaScript笔记
JavaScript
1.基本认识
1.1 可以直接在标签中添加事件
<div id="wrap" onclick="alert(123);">123</div>
<a href="javascript:void(0);">gogogogogo</a>
<a href="javascript:alert('a标签被点击了!');">233333</a>
1.2 script标签只能放在head或者body里面
- 一个html中可以放无数个script标签
- script标签载入有先后顺序
- 如果一个script标签已经用来引入外部的js文件了,那么在标签内写代码无用
<script type="text/javascript" language="JavaScript"> //type和language是声明语言格式,推荐不写
alert('潭州教育!转义字符\\')
</script>
1.3 系统弹窗 confirm prompt
let a = confirm('确认不要媳妇啦?');
console.log(a); //获得用户选择的结果, "boolean"
let b = prompt('请输入你媳妇的名字:');
console.log(b); //用户输入的结果, 取消-> null -> "object" 确定 -> string
2.数据类型
2.1 ES5、ES6定义变量的区别
ES6 定义变量,4种方式
- let
- const 常量,不可更改,初始必须赋值
- function
- class
ES5 定义变量,2种方式
- var
- function
变量命名规则:
- 严格区分大小写;
- 只能包含 字母 数字 _ $ 四大类,且不能以数字开头;
- 不能使用 关键词/保留词/已有的API;
- 见名知意。
- 函数声明时会覆盖掉同名变量
2.2 ES6的七大数据类型
- number 数字
- string 字符串
- boolean 布尔值
- undefined 未定义
- null 空 但是在浏览器上 typeof null = "object"
- symbol ES6新增的一种数据类型
- object 对象
// number
let x = 10;
// string
let x = "10";
let x = '10';
let x = `456`; //模板字符串 ES6中新的字符串定义方式
let x = "true";
// boolean
let x = true;
let x = false; //布尔值有两种,true 和 false
// undefined
let x;
let x = undefined;
const x = undefined; //const不允许初始不赋值
// symbol
let x = Symbol(123);
let y = Symbol(123); // x和y都是独一无二的 Symbol(变量)
// object
let x = [10,true,10]; //数组是对象的一种
function 和 class 定义的变量 typeof 显示"function", 其本质是object
2.3 typeof
let a = typeof NaN; //number
let b = typeof a; //b是string类型
let c; //undefined
let d = null; //typeof在检测null类型时返回object类型,其本质是null类型
let e = Symbol(123); //symbol
let f = document; //object
let g = function(){ //typeof在检测function数据会返回"function",其本质是object
};
console.log(typeof(b));
console.log(typeof c);
console.log(typeof d);
console.log(typeof e);
console.log(typeof f);
console.log(typeof g);
3. js获取dom元素节点
let a = document.getElementById("wrap"); //a就是节点对象
console.log(a); // <div id="wrap"></div>
//ClassName不唯一,所以Elements有s
let b = document.getElementsByClassName("box");
console.log(b); //类(似)数组 HTMLCollection(3) [div.box, div.box, div.box]
console.log(b.length); // 3
console.log(b[0]); // <div class="box">1</div>
b[1].innerHTML = '阿飞';
let d = document.getElementsByName('name'); //应用在input标签
console.log(d); // NodeList [input]
3.1 html唯一标签获取
注意:打印的是标签,不是类数组节点
console.log(document.body); // body标签及其子标签
console.log(document.head); // head标签及内容
console.dir(document.title); //标题
//获取HTML,此处是引用,尽管在后面改变,但引用也会跟上
console.log(document.documentElement); //打印的是整个html页面
document.title = "阿飞";
document.documentElement.id = '狗蛋';
3.2 querySelector
let aaP = document.getElementById("wrap")
.getElementsByTagName("div")[0]
.getElementsByTagName("p"); //一层层查找,但性能仍然较querySelector好
console.log(aaP); // HTMLCollection(3) [p, p, p]
let aP = document.querySelectorAll("#wrap div p"); //All多个,参数类似css选择器
console.log(aP); // NodeList(3) [p, p, p]
/*最低支持IE8*/
let sP = document.querySelector("#wrap div p"); //只能选到第一个 打印出的就是标签
3.3 操作元素属性
w3c允许的标签属性,既是合法
合法的标签属性,直接 . 操作
- `class`比较特殊,需要使用`className`代替操作
- `style` 这个属性非常特殊,是个对象
let oDiv = document.getElementById("wrap");
//oDiv.title = '狗蛋'; 直接写
oDiv.className = 'wrap'; //属性class是保留词,这里用className
oDiv.id = 'goudan';
oDiv.innerHTML = '<p>666</p>'; //虽然改了id,但oDIV仍指向这个节点对象整体,id只是其中一个属性,不能影响整体
//oDiv.innerHTML += '456'; 可以直接+=
let oGouDan = document.getElementById("goudan");
console.log(oDiv === oGouDan); //完全相等
/*
css样式
js中css属性名用驼峰法:
操作复合样式的时候,去掉 - 号,后面的第一个字母大写
*/
let oWrap = document.getElementById("wrap");
console.log(oWrap.style);
oWrap.style.height = "100px";
oWrap.style.backgroundColor = "pink"; //将background-color改为驼峰命名法,backgroundColor
oWrap.style.cssText +="width:100px;height:100px;background-color:pink"; // 也可以这样写
/ oWrap.className += " box"; / /* 操作className代替复杂的css样式设置 */
3.4 自定义标签属性
- getAttribute()
- setAttribute()
- removeAttribute() 移除属性
let oWrap = document.getElementById("wrap");
//获取自定义标签属性
console.log(oWrap.getAttribute("afei"));
//设置自定义标签属性
oWrap.setAttribute("afei","456");
oWrap.setAttribute("zhuque","123");
//移除自定义属性
oWrap.removeAttribute("afei");
//可以操作合法属性,但一般不用,没有直接.操作方便
console.log(oWrap.getAttribute("id"));
3.5 标签数据 innerHTML、innerText(火狐低版本,textContent)、value
<div id="wrap"><i>阿飞飞</i> 小浪浪 海文文 银时时 朱雀雀</div>
<input id="inp" type="text">
<button id="btn">按钮</button>
<script>
/*
.innerHTML
.innerText 火狐低版本 .textContent
.value
*/
// let oWrap = document.getElementById("wrap");
//
// console.log(oWrap.innerHTML); //获取HTML
// console.log(oWrap.innerText); //只获取文本
//
// oWrap.innerHTML = "<b>朱雀雀真...</b>";
//oWrap.innerText = "<b>猪八戒...</b>";
document.getElementById("btn").onclick = function(){
alert(document.getElementById("inp").value);
}
</script>
3.6 css超级选择器
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div#wrap.on.goudan[title]{
width:150px;
height:150px;
background-color:pink;
border:5px solid #999;
}
</style>
</head>
<body>
<div id="wrap" class="on goudan" title=""></div>
</body>
4. 算术运算
4.1 隐式类型转换
- "+" 两边任意一边有字符串,那么都会进行隐式字符串转换,再进行拼接
- 布尔值和数字运算,会转换成 1 0
- 除开number string boolean之外,比如去讨论一个对象和另一个对象的加法等是没有实际意义的
let a = 10;
let b = "20";
//alert(a + b); // 弹出 "1020",结果是字符串
//alert("123" + {}); // 123[object Object]
//alert("123" + document); // 123[object HTMLDocument]
//alert("123" + undefined); // 123undefined
console.log(true + 8); // 返回9
//没意义
// console.log({}+{}); //[object Object][object Object]
// console.log([]+{}); //[object Object]
// console.log([]+[]); //
//同级运算从左到右
alert(1 + 2 + "3"); // 返回 "33"
alert("8" + 1 + 2); // 返回 "812"
// 将字符串转成数字, 前面带一个 +
console.log(+"86867");
// 数组和任何东西相加,都会转换成字符串
[1,2,3]+3 // "1,2,33"
[1,2,3]+true // "1,2,3true"
[1,2,3]+null // "1,2,3null"
[1,2,3]+undefined // "1,2,3undefined"
[1,2,3]+'' // "1,2,3"
[1,2,3]+NaN // "1,2,3NaN"
undefined+[] // "undefined"
{}+[] // "[object Object]"
- * / %都会变成数字再进行运算
出现非法运算(字符串非数字字符串进行计算)时,会出现NaN(not a number)
let a = '50p'; //非数字
let b = "40";
console.log(a - b); // NaN
console.log(a * b); // NaN
console.log(a / 20); // NaN
console.log(a % 20); // NaN
console.log(typeof(NaN)); //NaN是number类型,但不是一个数字
console.log(NaN + 10); // 返回NaN
4.2 自增和自减
let a = 10;
console.log(a++); //返回10
// let a = 10;
// let b = 5;
// console.log(a++ + b); //返回15
let a = "5";
a ++; // ++ 或 -- 会强行变数字进行计算,最终a的值也是数字
console.log(a); // 6
4.3 模板字符串
/*
单引号 或者 双引号 描述的字符串,内部不能换行
` ` 模板字符串可以
*/
let oWrap = document.getElementById("wrap");
let x = "阿飞老师有点皮"
// oWrap.innerHTML = "<ul>"+
// "<li>"+
// "<p>"+
// "<a href=''>"+x+"</a>"+
// "</p>"+
// "</li>" +
// "</ul>";
/* ${}可以直接引用变量,{}内是JS代码 */
oWrap.innerHTML = `<ul>
<li>
<p>
<i>${x}</i>
<b>\$\{\}</b>
</p>
<p>\`\`是ES6的特点</p>
</li>
</ul>`;
5. 运算符
5.1 赋值运算 a+=1
let a = 15;
a -= 1; //a = a - 1
a *= 2; //a = a * 2
a /= 3; //a = a / 3
a %= 4; //a = a % 4
alert(a);
5.2 比较=运算
/*
== 只比较值相等与否,不关心数据类型
=== 值与数据类型都要相等
!= 不等
!== 不全等
*/
let a = 10;
let b = "10";
console.log(a == b); //true
console.log(a === b); //false
console.log(a !== b); //true
console.log(a != b); //false
5.3 对象引用类型比较地址
/*
基础数据类型 (栈内存) 只比较值与类型
number string boolean undefined null symbol
引用数据类型 (堆内存) 比较地址
object
*/
/* a 和 b 是不同的对象,有自己的地址 */
let a = [10];
let b = [10];
console.log(a == b); //false
console.log(a === b); //false
console.log(a[0] === b[0]); //true
//console.log(false == [0]); //这样不科学的,建议 ===
5.4 字符串比较
/*
> < >= <=
*/
//字符串比较,从首位的ASCII码开始比较
let a = '3';
let b = '20';
console.log(a > b); // '3' > '2' 的ACSII码,所以返回 true
5.5 逻辑运算&& || !
/*
&& 与 //只考虑布尔值时:真真为真,其他都是假
真正的作用:遇到假就停,然后取假值,否则取后面的值
|| 或 //只考虑布尔值时:假假为假,其他都是真
真正的作用:遇到真就停,然后取真值,否则取后面的值
! 非 //只考虑布尔值时:取反
真正的作用:取数据对应布尔值的非
那些数据在被转成布尔值的时候是 false:
0 undefined null false '' "" NaN
*/
// let a = true && false;
// console.log(!a);
let a = 5 && 0;
console.log(a); //取假值,返回 number 0
let b = 8 && 9;
console.log(b); // 返回 9
console.log(NaN || 7 || 0); //返回7
console.log(!1); //返回 false
console.log(!0); //返回 true
//取一个数据对应的布尔值
console.log(!! NaN); //NaN的布尔值是false
5.6 逗号运算
/*
逗号运算符,从左到右 从上到下 运算
*/
let a = (4,5,6); //算到6后停止
console.log(a); //返回 6
5.7 运算优先级
/*
运算符优先级
. [] ()
++ -- - ~ ! delete new typeof void
* / %
+ -
< <= > >=
== != === !==
&&
||
三目
=
,
*/
// let a = 8 || 9 && 0;
// console.log(a); //返回8
let a = 10;
let b = 5;
//浏览器会惰性运算,||的左边已经确定,右边不会计算
// a = 8 || 5 && (b=6);
//console.log(a); //8
//console.log(b); //5 ,b的赋值没有计算
a = 0 || 5 && (b=6); //返回 a = 6, b = 6
console.log( 6 || (b=6) && 10 || 11); //返回6
console.log(b); //b仍未赋值
5.8 位运算(先取整再算)
/*
二进制
位运算时会将数值转换为32位整型来进行运算,
所以位运算遇到小数时,直接处理掉小数部分当成整数来运算。
*/
let a = 15;
// 00000000 00000000 00000000 00001111
// -15的二进制
// 11111111 11111111 11111111 11110000 取反码
// 11111111 11111111 11111111 11110001 反码+1
/**
* 位运算操作符:按位非`~` 、按位与`&`、按位或`|`、按位异或`^`
*左移`<<`、 无符号右移`>>>`、 有符号右移`>>`
*/
//按位取反, 满足条件 a + ~a=-1
let a = 7; // 0111
console.log(~a); // -8 ( 1..1000 结果 取反 +1 ) (0...0111 -> 0...1000)
//按位与
console.log(10 & 8); // 1010 & 1000 = 1000 => 8
//按位或
//左移
a << 2; //a * 2^2;
6. 判断和循环
6.1 三目运算
/*
哪些数据是假:
六大假 0 undefined null false "" NaN
当条件、真语句、假语句都是一条语句时,我们可以使用三目来改写if
条件 ? 真语句 :假语句
*/
4<5 ? alert('真') : alert('假');
let val = true;
//三目运算符的 优先级 低于 +
let name = "val is" + val ?"狗蛋":"大锤";
//"val is true" ? "狗蛋" : "大锤"
console.log(name);
// 多级三目,从左到右
function f(n) {
let a = n>100 ? n-100 : n>99 ? n-99 : n;
console.log(a);
}
6.2 switch
let a = '海文';
// if (a === "阿飞") {
// alert(a + "老师一般帅!");
// }else if (a === "小浪") {
// alert(a + "老师??");
// }else if (a === "海文") {
// alert(a + "斯文");
// }else if (a === "朱雀") {
// alert(a + "可爱");
// }else{
// alert(a + "喵喵喵");
// }
//switch 是全等判断
switch (a) {
case "阿飞":
alert(a + "帅!");
break;
case "小浪":
alert(a + "也帅!");
break;
case "海文":
alert(a + "斯文");
break;
case "朱雀":
alert(a + "可爱");
break;
default:
alert("喵喵喵?");
break;
}
6.3 逻辑运算符代替判断
let a = true;
function b() {
console.log(123);
}
// if (a) {
// b();
// }
a && b(); //遇到假停止,b()会运行
//先与再或,勉强可以代替三目运算
let x = 5;
let y = 6;
//console.log(x<y ? 2 : 3);
console.log(x<y && 2 || 3);
6.4 for循环
// 2+2^2+2^3+2^4+...+2^10
let a = 1;
let sum = 0;
for(let i = 1; i <= 10; i++){
console.log("i=" + i);
a *= 2; //a = a*2
sum += a;
console.log("sum=" + sum);
}
6.5 综合案例,生成尖括号
/*
5 3
6 3
7 4
8 4
9 5
10 5
*/
let oWrap = document.getElementById("wrap");
let HTML = '';
let num = 11;
let mid = 0;
//计算oWrap的宽高
if(num & 1){ //奇数判断
mid = (num+1)/2;
}else{
mid = num/2;
}
oWrap.style.width = num*50 + 'px';
oWrap.style.height = mid*50 + 'px';
for(let i = 0; i < num; i++){
let x = i>(mid-1) ? num-i-1 : i; //箭头朝下
let y = i>(mid-1) ? i+1-mid : mid-1-i; //箭头朝上
HTML += `<div style="margin-top:${y*50}px;">${i+1}</div>`;
}
oWrap.innerHTML = HTML;
7. 循环
7.1 break vs continue
/*
break:
switch里面的break只对switch有用,不会影响到外面的for
if里面的 break ,结束上级 for 循环
continue: 该次循环结束,进入下一个循环
*/
for(let i=0;i<10;i++){
switch (i) {
case 5:
break; //作用不到for
}
console.log(i);
}
for(let i=0;i<9;i++){
if(i===5){
//continue; //执行到continue,即刻停止,进入下一个循环
break; //结束 for 循环
}
console.log(i);
}
//break只能跳出一个for,要想跳出第二层,定义一个伪变量表示for循环,break aaa;
aaa:for(let i=0;i<5;i++){
for(let j=0;j<4;j++){
if(i*j ===6){
break aaa;
}
console.log(`i===${i},j===${j}`);
}
}
7.2 while
//let在for循环内定义时,是局部变量
for(let i = 0;;)
//var在for循环内定义时,相当于全部变量
for(var i = 0;;)
let i = 0;
for(;i<4;i++){
}
console.log(i); //返回4
//全局变量下的for循环可以用while代替
var i =0;
for(;i<5;){
console.log(i);
i++;
}
var j=0;
while(j<5){
console.log(j);
j++;
}
// do while
let x = 5;
do{
console.log(x);
x++;
}while(x<5);
8. 函数
8.1 定义函数方式
/*
let a = function () {
alert(1);
}
a(); //函数加括号,自执行
*/
/*
a(); //可以放在function之前,let、var函数表达式定义的函数,不允许提前调用
function a () {
alert(1);
}
*/
/* let、var定义的函数,不允许提前调用
a();
var a = function () {
alert(1);
}
*/
let a = function b() {
alert(2);
console.log(b); //在函数里面可以获取b,此时b === a
console.log(b === a);
}
a();
//b(); //显示b()未定义,函数外面不能使用b
8.2 函数表达式
/* 使用fuction直接定义的函数不能直接加括号执行,只能通过名字再加括号执行
function a() {
alert(3);
}
a();
*/
//let定义的函数表达式,可以直接在后面加括号执行
let b=function () {
console.log(4);
}();
console.log(b); //undefined,此时b不能代表函数,b成为了函数的返回值
//匿名函数只能传参或赋值,不允许直接出现
//[function () {}] //允许
// function{} //不允许
//匿名函数加括号变成函数表达式,括号可内可外
(function () {
console.log(5);
})();
(function () {
console.log(6);
}());
//改变函数的返回值,也是函数表达式
+function(){ //一元运算符 + - 可以变为函数表达式
console.log(7);
}();
~function () { //位运算非
console.log(8);
}();
!function () { //逻辑运算非
console.log(9);
}();
8.3 参数
/*
参数
形参
实参
不定参
*/
//定义函数的时候()里面是允许写变量名字的,这些变量名字就是形参,形参只针对函数内容起作用
function a(x,y=200){
alert(x+y);
}
//函数调用的时候,()里面写的就是实参
a(7);
function f(a,b,c) {
console.log(a);
console.log(b);
console.log(c);
}
f(1,8); //从左到右进入形参,没有传入实参的,显示undefined
f(1,5,3,4); //实参多了,多的那个无效
function sum(a,b) {
console.log(a+b);
}
sum(7,8);
sum(45,1);
//求 n 个数的和,每次不一定是相同的个数,实参传入几个数,就求几个数的和
function sum(a,b,c,d) {
//不定参 它是一个类数组,存储着 所有实参
// console.log(arguments);
let s = 0;
for(let i=0,len=arguments.length;i<len;i++){
s+=arguments[i];
}
console.log(s);
}
sum(4,5,6);
sum(1,2,3,4);
sum(8,6);
8.4 上下文this
console.log(this); //打印Window 是顶层属性
// window.alert(4);
// alert(a); //未定义 报错
// alert(requestAnimationFrame);
//不存在即报错
if(window.requestAnimationFrame){ //直接判断时,如果不支持,直接报错,不能进行判断,此时最好用类属性判断
console.log(requestAnimationFrame);
}
/* 函数声明,默认位于window对象内
函数(声明式or表达式一样)自执行,this指向window
*/
function a() {
console.log(this === window);
}
console.log(a === window.a); // 相等
a();
//let定义的函数不挂载window内,var定义的函数在window内
let b = function () {
console.log(this); //this都是指向window
}
console.log(b === window.b);
b();
/*
对象内的this,找 爸爸 所在的对象
*/
let afei = {
name:'阿飞',
x : function () {
console.log(this);
}
}
afei.x(); //对象方法自执行。this指向对象
let zhuque = {
xx:{
name:"朱雀的xx",
a:function () {
console.log(this === zhuque.xx);
}
}
}
zhuque.xx.a(); // 打印 父级的对象
8.5 每个函数都有返回值,默认 return undefined
//函数运行到return即停止,return后面的不执行
function a() {
alert(1);
return 2;
alert(3);
}
console.log(a());
8.6 ES6{}就是一个作用域
let关键词定义的变量,起作用的范围就是包含这个变量最近的{}
var关键词,只有在function内定义的变量,才是局部变量,while、if、for内定义的都是全局变量
同名函数会被覆盖
function a() {
alert(2);
}
function a(x,y) { //覆盖上一个定义
alert(x+y);
}
a();
8.7 获取元素的动态方法
动态有三个,意思是存储节点的变量会随着页面的改变实时改变,少了或者多了
- getElementsByClassName()
- getElementsByTagName()
- getElementsByName()
静态有以下,获取后,选择器被改也指向原对象
- querySelectorAll
- getElementById
<div id="wrap">
<p class="goudan"></p>
<p class="goudan"></p>
<p class="goudan"></p>
</div>
<script>
//getElementsByClassName是个动态的
let aP = document.getElementsByClassName("goudan"); // 有三个
let oP = aP[0]; // 这种就是静态的,不存在因修改而改变
oP.className = 'dachui'; //改变了 aP,只剩两个 “goudan”
oP.title = 'ppp';
aP[0].className = "a2121"; //aP是动态数组,
aP[0].innerHTML = "112121212"; //因为aP[0]的类名被改变了,动态获取的内容更新了,现在又少了一个
</script>
9.作用域与解析顺序
9.1 var、function在全局作用域定义的变量默认是window对象的属性
//script标签是最大的作用域,也是全局作用域
//如果var、function在全局作用域里面定义变量。相当于给window添加了属性
var b = 10;
console.log(window.b,this); //window的属性
//ES5定义变量的关键词 var funtion
//作用域是往上离变量最近的函数
function a() {
var g = 10; // var在function内定义的才是局部作用域
console.log(g,this.b,this); //函数自执行this指向window
}
a();
//任意作用域里面,如果不加var直接产生了没有定义过的变量,那么这个变量相当于window的属性
//但是实际开发不允许这样写
function aa() {
bb = "bb"; // 赋值产生变量才行,如果直接使用则会报错
}
aa();
console.log(bb);
//面试题
function f() {
var x=y=5;
console.log(x); //x是局部的5
}
f();
console.log(y); //y未声明,因此算是window的属性,y=5
//console.log(x); //因为x是局部变量,外部访问不到,故报错
9.2 作用域链
//作用域链,操作变量时,一层层的作用域查找变量声明的地方,
//如果没有找到,调用变量会报错
//如果是赋值,在非严格模式下,变量成为windows的属性
var x=10;
function a() {
x=15; //本作用域找不到,去父级作用域找,找到后并赋值
var y=5; //局部作用域
return x+y;
}
console.log(a());
console.log(x); //全局变量被修改了,因此是15
9.3 es5解析顺序
var、function解析顺序
第一步:定义
找出当前作用域里面所有的var和function定义的变量名,不赋值,赋值是执行
此时function定义的函数,是个完整的函数,所以函数定义可以在函数执行的前后任意位置
第二步:执行
从上到下执行
alert(x); // 返回不是报错,是undefined,变量已有,但未赋值
var x=10;
//let x=10; // 报错
/*
1.定义
var x;
2.执行
alert(x); //undefined
x=10;
*/
alert(b);
function b() {
}
/*
1.定义
function b(){}
2.执行
alert(b);
*/
9.4 变量重名与覆盖
/*
定义过程中,多个var声明同一个变量,我们只需要留一个
多个函数声明重名,只留最后一个函数
var和function重名,无论先后,只留function
*/
function v() {
alert(5);
}
function v() { // 被打印
alert(10);
}
var v;
console.log(v);
9.5 闭包
函数执行每次都会产生一个新的作用域 (父级也是新的) ,彼此不相干
/*
JS自带变量回收机制,只有全局变量不会被回收,除非网页关闭;
闭包:一个使用了外部函数的参数或者变量的函数(作用域嵌套作用域,ES5只有函数能产生作用域)
*/
function a() {
var x=10;
function b() {
x++;
console.log(x,this);
}
return b;
}
//函数执行每次都会产生新的作用域,
var c=a(); //c指向函数体内的函数b,局部变量x只在a()时产生了一次,所以不会回收
//alert(c); c是函数
//c()每次执行使用的都是同一个父级作用域下的变量x
c(); //11
c(); //12
c(); //13
c(); //14
//a()每次执行后返回的都是新的作用域,使用的变量x是新的,
a()(); //11
a()(); //11
a()(); //11
闭包的作用之一,闭包避免局部变量被回收
<div id="wrap">
<p>aaaaaaaaaaa</p>
<p>bbbbbbbbbbb</p>
<p>cccccccccc</p>
<p>dddddddddd</p>
<p>eeeeeeeeee</p>
</div>
<script>
//闭包的作用之一,闭包避免局部变量被回收,onclick不知道什么时候触发,所以num不会被回收
(function () {
var num=10;
document.onclick = function () {
num++;
alert(num);
}
})();
let oP = document.getElementsByTagName("p");
//ES6只要是{}就是作用域,{}内的onclick使用了父级的i,所以i没有回收,子作用域可以调用
//产生了5次闭包,存了5个i,子作用域之间的i不相干
//5个闭包是5个单独的作用域,let i是5个父级作用域
for(let i=0;i<5;i++){
oP[i].onclick = function () {
alert(++i);
}
}
//var不能产生作用域,不是闭包,函数作用域用的是同一个变量i,(扩号内执行的结果是5)
//i最后是5,所以每次点击都是同一个i
for(var i=0;i<5;i++){
oP[i].onclick = function () {
alert(i);
}
};
//强行给var加闭包,创造一个父级作用域,使得点击事件用上父级作用域的变量,产生5个闭包,存下5个变量
for(var i=0;i<5;i++){
function a(x){
oP[x].onclick = function() {
alert(x);
};
}
a(i); //a(i)执行了5次,产生了5次闭包
}
//等于自执行
for(var i=0;i<5;i++){
(function a(x){
oP[x].onclick = function() {
alert(x);
};
})(i);//a(i)执行了5次,产生了5次闭包
}
//可以简写自执行
for(var i=0;i<5;i++){
!function a(x){
oP[x].onclick = function() {
alert(x);
};
}(i);//a(i)执行了5次,产生了5次闭包
}
</script>
练习
fn()();
var a = 0;
function fn(){
alert(a);
var a = 3;
function c(){
alert(a)
}
return c;
}
/*
1.定义
var a;
function fn(){}
2.执行
fn() ===> 新作用域
1.定义
var a;
function c(){}
2.执行
alert(a) undefined
a=3
return c;
fn()() ===>新作用域
alert(a),a从父级找,弹出3
*/
var a = 5;
function fn(){
var a = 10;
alert(a);
function b(){
a ++;
alert(a);
}
return b;
}
var c = fn();
c();
fn()();
c();
/*
10
11
10
11
12
*/
9.6 function属于对象类型,相等判断时是比较地址
console.log(5 === 5);
console.log([] === []); //引用,需要比地址,false
var h = function () {};
var l = function () {};
console.log(h === l); //false
function a() {
return function () {};
}
var b = a();
var c = a();
console.log(b ===c); //false
9.7 ES6的作用域
只要是在作用域里面let过的变量,那就不允许提前使用
/*
ES6定义变量
let const function class
let 和 const没有预解析,不同于var
先对定义function,进行解析
*/
alert(a); //报错
let a = 10;
let a = 20;
function b() {
//从上到下读
//暂时性死区,只要是在作用域里面let过的变量,那就不允许提前使用
alert(a);
let a = 30; //死区了,报错
}
b();
//var的作用域只认函数
if(false){
var a=10;
}
console.log(a); //undefined
//let的作用域是大括号
if(true){
let a=1;
}
console.log(a); //无法访问局部作用域
//for的小括号()是{}的父级作用域,但var不认这是作用域
const g = 10; //不允许重新赋值的常量
const a = []; //对象不能被重新赋值
a[0] = 10; //但允许改变其内容
console.log(a);
10. call apply bind
10.1 函数内的this
function a() {
console.log(this);
}
a();
/*
普通模式下, 自执行this指向window,
严格模式下, this指向undefined
被动模式下,this指向触发事件的对象
*/
document.onclick = a;
10.2 call apply
/* call()内第一个参数是函数内this的指向,后面跟的是实参,调用后会执行 */
function a(x,y) {
console.log(x);
console.log(y);
console.log(this);
}
a(8,9); //自执行
//a.call(); //call()不加参数与自执行a()效果一样
a.call(document,8,9); //this指向document
/* apply(),与call()类似,但是只有两个参数,第二个是传参的数组 */
a.apply(document,[8,9]); //this指向document
//多个参数要用数组的形式传入
10.3 bind
bind之后相当于生成一个新的函数,还未执行
/* bind不能执行 */
function a(x,y) {
console.log(x);
console.log(y);
console.log(this);
}
//a.bind(document); 这样直接写是没有效果的,只是相当于生成了一个新的函数,将this绑定给document
function b(x) {
x();
}
b( a.bind(document) ); //bind后生成了有this新指向的函数,bind是定义函数,不能直接执行,需要手动执行
a.bind(document)(10,20); //新的函数内的this指向 document
a.bind(10)(0,1); //新的函数内this指向number 10
//bind定义this指向
document.onclick = function (x,y) {
console.log(x);
console.log(y);
console.log(this);
}.bind({name:'阿飞'},200,250); //这里类似于call传参,bind产生新函数
10.4 H5新API classList
oWrap.classList.[attr] attr = add、remove、toggle
let aDiv = document.querySelectorAll("#wrap .title"),
aList = document.querySelectorAll("#wrap .friend .list"),
len=aDiv.length;
for(let i=0;i<len;i++){
aDiv[i].onclick = function () {
//toggle,如果有就删除,没有就添加
aList[i].classList.toggle("show");
}
}
//classList 方法还有 add remove
oWrap.classList.add("afei"); //直接添加类名
11. ES6的解构赋值
// ES6 定义变量的解构赋值
let a = 10,
b = 20,
c = 30;
//结构模式对应,赋值效果同上
let [a,b,c] = [10,20,30];
//多了 显示 undefined
let [a,b,c,d] = [20,30,41]; // d = undefined
//不用let的变量赋值语句,变量默认是window的属性
[a,b] = [20,30,41];
//变种写法
function fn() {
let x=[];
for(let i =0;i<5;i++){
x[i]=i*i;
}
return x;
}
let [a,b,c,d,e] = fn();
//对象的解构赋值,属性是用来对应的,只有变量定义了
let {a:x,b:y} = {a:10,b:20};
console.log(x);
console.log(a); // 报错,属性不是定义的
let {x:x,y:y} = {a:10,b:20,y:30};
console.log(x); //找不到右边对象的x属性,所以变量x显示未定义
console.log(y); //属性对应才能赋值 y=30
//注,属性和变量相同时,可以只写一个
let {x,y} = {x:10,y:30};
console.log(x,y);
//ES6新增简写规则
let a = 10,
b = 20,
c = {
a,
b
};
/*属性名和变量名相同,可以简写,对象c的定义同下
c = {
a:a,
b:b
}
*/
console.log(c);
11.1 深层解构赋值
let [a,[b,c],d] = [1,[2,3],4];
console.log(a,b,c,d);
let [a,b,{x,y}] = [1,2,{x:10,y:20}];
console.log(a,b,x,y);
11.2 解构赋值时默认值写法
只有右边**严格等于undefined**时取默认值
不允许前面的默认值用后面的变量值
/*使用解构赋值,取默认值的方法*/
function fn(data) {
let a = data.a;
let b = data.b;
let c = data.c || 100; // 要确保传入的值不是假,否则走默认值,这种不严格
// 必须严格的走 全等undefined,再添加默认值
if(c === undefined){
c = 100;
}
}
fn({a:10,b:20});
//ES6的默认值写法,左边写一个等于,只有右边严格等于undefined时取默认值
function fn(data) {
let {a:a=1,b:b=2,c:c=100} = data; //左边严格上说不能认为是对象,只有右边是对象
console.log(a,b,c); // c = null
}
fn({a:10,b:20,c:null}); // 这里 null===undefined 不成立,
//数组默认值写法
let [d,e,f=90] = [7,8];
console.log(d,e,f);
//默认值是表达式时,如果不需要默认值,则默认值无法执行
function f1() {
console.log("12");
}
let [x = f1()] = [1]; // x=1, f1未执行
let [y = f1()] = [undefined]; // y=undefined, 是f1执行后的返回值
//不允许前面的默认值用后面的变量值
let [m=n,n]=[undefined,1];
console.log(m,n); //报错
12. 字符串方法
12.1 基本数据类型包装对象无意义
undefined null 等不能进行点操作,会报错的
//基础数据类型虽然可以点操作,但没有意义,拿不到包装对象;
//点操作本质上是针对数据的包装对象进行操作,每一次的包装对象都是新产生的对象,不能确定
//undefined null 等不能进行点操作,会报错的
let a='阿飞';
a.index = 20; //不能给字符串添加自定义属性,不会报错,显示undefined,这是操作的a的包装对象,用了即消失,存不下来
console.log(a,a.index); //第二次的点操作是操作的全新的包装对象,用后即消失
/*
let b={};
b.index = 20; //对象可以添加自定义属性
console.log(b);
*/
let a = new String("阿飞"); //这里的a是字符串对象
a.index = 20; //a的包装对象是 new String(),可以添加自定义属性
console.log(a+"朱雀",a.index);
12.2 str.charAt() 取出字符串中的第几位字符,不能赋值
let a = '阿飞';
//console.log(new String(a)); //可以打印包装对象属性为String的对象
//针对a的包装对象的charAt
console.log(a.charAt(1)); //取出字符串中的第几位字符
console.log(a[0]); // a的包装对象有a的内容,对象访问时可以的,但是IE6,7不支持,最好用charAt
//包装对象不能赋值,没有意义;使用即消失,存不了
a[0]="5";
console.log(a[0]);
12.3 str.charCodeAt() 获取ASCII编码
/*
charCodeAt()
调用第几个字符的编码,
String.fromCharCode()
与之相反,从ASCII码到字符
*/
let a = "阿A飞";
let b = `阿
飞`;
console.log(a.charCodeAt(1)); // 65
console.log(b.charCodeAt(1)); //换行码是 10
console.log(String.fromCharCode(39134)); // 飞
//加密,利用ASCII码
let c = "小卑鄙我爱你";
let d = "";
for(let i=0,len=c.length;i<len;i++){
let code = c.charCodeAt(i)+520;
console.log(code);
d += String.fromCharCode(code);
}
console.log(d);
12.4 str.substring(x,y) 字符串截取一段[x,y),xy大小无所谓,y默认为len
/*substring(x,y) 从第x位到第y位截取,x要,y不要*/
// slice可以倒着截取
let a="abc阿飞789456";
let b = a.substring(3,5); //包含3,不包含5
console.log(b); //阿飞
let bb=a.substring(5,3); //没有前后要求,会自动调整
console.log(bb); //阿飞
let c = a.substring(3); //从3到结尾
console.log(c); //阿飞789456
let d = a.substring(-2,3); //没有负值,会认为0
console.log(d); // abc
let e = a.slice(-5,-2); //负值表示从后开始数,倒着数,要满足先后顺序
console.log(e); // 894
12.5 大小写转换toLocaleUpperCase
//主要针对英文字母大小写
/*
toLocaleUpperCase()
*/
let a = "abc";
let b = a.toLocaleUpperCase();
console.log(b);
console.log(b.toLocaleLowerCase());
12.6 indexof()返回坐标,默认-1
/*
找位置,返回num
*/
let a = "我觉得阿飞老师是最皮的";
console.log(a.indexOf("阿飞"));
//指定位置开始找,后面加一个参数
console.log(a.indexOf("老师",3));
//找不到返回 -1
12.7 split(",")切割返回数组,join(",")拼接成字符串
// 使用split()进行切割,返回一个包含分开特定字符前后元素的数组
let a = "阿飞,朱雀,心艾,岚岚,丫丫,艾米";
let b = a.split(",");
console.log(b);
console.log(b.join("php"))
// let c = a.split("");
// console.log(c);
12.8 ES字符串扩展
function fn(a,b) {
console.log(arguments); // [ 0:["1,2", "阿飞", ""], 1:5 , 2:6 ]
console.log(a+b); // 1,2,阿飞,5
}
//fn(1,2);
let b=5;
let a = 6;
fn`1,2${b}阿飞${a}`;
13. 数组方法
13.1 push pop shift unshift
增加,返回数组长度,删除,返回被删的内容
/*
push
参数:任意数据
功能:直接改变原数组
返回值:返回改变后数组的长度
pop
参数:null
功能:改变原数组,删除最后一位
返回值:删除的元素
shift
功能:改变原数组,删除第一位
返回值:删除的元素
unshift
功能:改变原数组,从第一位添加
返回值:数组长度
*/
let a = ["阿飞","无虑"];
console.log(a.push("小浪","海文"));
console.log(a);
console.log(a.pop());
console.log(a);
console.log(a.shift());
console.log(a);
console.log(a.unshift("first"));
console.log(a);
//骚操作,
// pop()返回的是删除的最后一个函数,后面跟参数执行
let x = [5,function(x){alert(x)}];
x.pop()(x[0]);
13.2 a.indexOf() a.slice()
//类数组除了.length,不能执行其他api
let a = ["阿飞","无虑","朱雀"];
console.log(a.indexOf("朱雀")); //2
//数组截取
let b = a.slice(1);
console.log(b); // ["无虑", "朱雀"]
13.3 数组切割splice()
返回被切割的部分
//数组切割,单个参数时,包含前面而不含后面的
let a = ['阿飞','无虑','小浪'];
console.log(a.splice(1)); //从第1个切,切到最后 ["无虑", "小浪"]
console.log(a); // ["阿飞"]
//第二个参数表示切除几个
console.log(a.splice(1,1)); //从第1个开始切除1个 ["无虑"]
console.log(a); // ["阿飞", "小浪"]
//添加与替换
a.splice(1,1,'朱雀','心艾'); //切除一个,替换了2个 ["无虑"]
console.log(a); // ["阿飞", "朱雀", "心艾", "小浪"]
13.4 数组排序a.sort() a.reverse()
二分法排序
不加参数,默认升序, 数组被改变了,但引用地址没变,仍相等
//一般只是针对num类型数组排序,其他类型没有意义
// sort()从小到大排序,升序
// reverse() 反序,元素从后往前排,可以先升序再反序实现降序排列
// 返回值是排列完成之后的数组,
let a=[12,78,50,20,32,40,90];
a.sort();
console.log(a);
a.reverse();
console.log(a);
console.log(a.sort() === a); //改变之后还是a本身,相等
//降序
console.log(a.sort().reverse());
//JS二分法排序 a-b: 为升序 b-a: 为降序
a.sort(function (a,b) {
return a-b;
})
console.log(a);
let a = [
{name:'阿飞',age:20},
{name:'朱雀',age:30},
{name:'丫丫',age:18},
{name:'心艾',age:80},
{name:'岚岚',age:22},
{name:'发发',age:22},
{name:'艾米',age:28}
];
//a.sort(); 无法直接对对象排序
a.sort(function (a,b) {
return b.age-a.age; //后者减前者,降序
})
console.log(a);
13.5 数组拼接数组 a.concat(b)
// concat 拼接数组
let a = [1,2,3];
let b = [4,5,6];
let c = a.concat(b); //将b拼接到a的后面
console.log(a,b); //不改变原数组
console.log(c);
13.6 数组方法 Array.isArray(a)
// 只有 Array 可以使用 isArray()方法
let a = [1];
let b = document.querySelectorAll("div");
console.log(Array.isArray(a));
console.log(Array.isArray(b)); //常用于判断类数组,其没有数组常用的方法
13.7 数组拼接字符串 a.join(",")
let a = ["阿飞",'心艾','朱雀'];
let b = a.join("<==>"); //通常将字符串数组元素拼接成一个新的长的字符串
console.log(a); //不改变原数组
console.log(b); //b是返回的长字符串 阿飞<==>心艾<==>朱雀
13.8 数组遍历 a.forEach(v,i)
//forEach 遍历数组,必须要有函数作为参数,自动执行length次,不支持函数return
/*
接收函数,该函数第一个形参代表每一位的数据,
第二个形参代表每一位的序号,
第三个形参代表原数组
*/
let a = [4,5,6,7,8,9];
let b=a.forEach(function (x,y,z) {
console.log(x,y,z);
});
console.log(b); //undefined
//与forEach效果一样
for(let i=0;i<a.length;i++){
(function (x,y,z) {
console.log(x,y,z);
})(a[i],i,a);
}
13.9 数组遍历 a.map(cb(val,i))
//map是有返回值的数组遍历,返回一个基于原数组结构的数组
let a = [1,2,4,5];
let b = a.map(function (x,y,z) {
console.log(x,y,z);
return x*x;
});
console.log(a); //map不改变a
console.log(b); //b是基于a结构的新生数组 [1, 4, 16, 25]
**ES6 的Map对象,可用于记数**
let a = [1,2,4,5];
let c = new Map()
a.map(function (val,index) {
c.set(index,value) // 实例方法,设置 map数据
})
console.log(c); // Map对象实例 Map(4) {0 => 1, 1 => 2, 2 => 4, 3 => 5}
c.get(3); // 5 按set时的index查找
c.has(0); // true index
c.keys(); // MapIterator {0, 1, 2, 3}
c.values(); // MapIterator {1, 2, 4, 5}
[...c]; // [[0,1], [1,2], [2,4], [3,5]]
13.10 过滤 a.filter(cb(val,i))
/* 遍历
func:过滤
生成一个过滤后的数组,return true 留下,false 过滤掉
*/
let a=[10,20,5,7,89,41];
let b=a.filter(function (x,y,z) {
console.log(x,y,z);
return x>10; //将x>10的留下,新生一个数组
});
console.log(a); //不改变原数组
console.log(b); //b是过滤后的数组
13.11 ES6 ...扩展
let a = [1,2,3];
console.log(...a); //去除数组括号,拆解成单个,ES6兼容,babel可转
console.log(1,2,3); //与上等价
//param形参
function f(param) {
console.log(param); // 只有一个形参 1
}
//f(1,2,3);
f(...a);
/*
let c = (...a); //这样做是不允许的
console.log(c);
*/
...数组拼接
// ...数组拼接
let a = [1,2,4];
let b = [5,6,7];
//let c = a.concat(b);
let c = [...a,...b];
console.log(c);
...解构赋值
//b是数组,拆开后赋值, ...b只能放在后面,表示接受全部
let [a,...b]=[1,2,3,4];
console.log(a); // 1
console.log(b); // [2, 3, 4]
...与iterator接口
//常见的Iterator遍历器接口
/ Array String nodelist arguments /
// Nodelist是节点对象集合
function fn(a,b,c) {
console.log(a,b,c);
}
fn("753"); // 753 undefined undefined
fn(..."753"); // 7 5 3
...与NodeList
let aP = document.getElementsByTagName("p");
// 类数组不能用数组的遍历
// aP.forEach(function (val,index) {
// });
//ES5就有办法将 aP 先搞成数组,之后再使用forEach
//slice不传参数就不切割,数组切割,方法slice使用call改变切割对象执行,返回一个真数组
let x = [].slice.call(aP); //生成一个新数组
console.log(x);
x.forEach(function (node,index) {
node.onclick = function () {
alert(index);
}
})
//ES5 类数组=>真数组遍历遍历
[].slice.call(aP).forEach(function (node,index) {
node.onclick = function () {
alert(index);
}
});
//ES6 , ...将Nodelist拆了,加上[]成为真数组
console.log([...aP]);
[...aP].forEach(function (n,i) {
n.onclick = function () {
alert(i);
}
});
...与function
//任何拆解都要放在最后面
function fn(a,...b) {
console.log(a);
console.log(b);
}
fn(4,5,6);
function fn(...argu) {
console.log(argu); //ES6的...可以直接代替arguments
}
fn(7,8,9);
14. 数学对象
14.1 Math
- Math.pow(x,y)表示x的y次方
- Math.trunc(-5.999991) 去小数点取整 -5
/*
Math 对象
属性:
方法:
*/
//小数表示方式: 0表示正负 10表示小数点的位置为2 10.1010的整数部分为2,小数部分是1010/2^4, 10/16
//var a = 0 10 10.1010; //表示 2.625
/*
Math.abs()
1.传入的值是正确的,返回一个新的绝对值结果,字面量赋值
2.传入的值是数字字符串,会取value值取绝对值
3.单个数字元素的数组也会取值,多个数字元素也是NaN
4.传入的值其他类型,返回NaN,表示not a number
*/
console.log(Math.abs(["-888"])); // 888
//Math.pow(x,y)表示x的y次方
console.log(Math.pow(2,10)); // 1024
//开方,y小于1
console.log(Math.pow(256,1/2)); // 16
//过气的开二次方
console.log(Math.sqrt(256)); // 16
//取整,floor接地气,往小了取整,正负一样
console.log(Math.floor(2.5),Math.floor(-2.01)); //2 -3
//向上取整
console.log(Math.ceil(2.5),Math.ceil(-2.9)); //3 -2
//四舍五入取整
console.log(Math.round(4.49),Math.round(-4.6)); //4 -5
//去小数点取整
console.log(Math.trunc(-5.999991)); // -5
14.2 三角函数
/*
圆周 2PI 360deg
PI/6 30deg
PI/3 60deg
sin 正弦 对/斜
cos 余弦 邻/斜
tan 正切 对/邻
反三角
arcsin
*/
console.log(Math.sin(Math.PI/6),Math.cos(Math.PI/3),Math.tan(Math.PI/4)); //结果有小数,不精确
console.log(Math.asin(0.5),Math.PI/6);
14.3 随机数 Math.random()
/*
Math.random() 返回一个[0,1)的数
*/
//console.log(Math.random(),Math.round(Math.random()*10));
// 生成一个n到m的随机数,m取不到
const rdm = function(n=0,m=n+1){
return Math.floor((m-n)*Math.random()+n);
}
console.log(rdm(1,7));
14.4 parseInt() parseFloat()
/*
非数学对象
parseInt(a,b)
a 需要转换的数值,隐式转换成字符串
b 进制(2,36) 10+26
*/
console.log(parseInt("123abc")); //返回字符串中的整数部分,遇到NaN停止 返回123
//第二个可选参数是进制
console.log(parseInt("ff",16)); //按16进制解析,结果是10进制255
console.log(parseInt("0xa")); // 10
/*
parseFloat()返回带小数点的
在底层parseFloat会先判断传入的参数类型,转换成字符串;
如果传入对象,会默认调用对象的toString()方法
*/
console.log(parseFloat("12.3254a"));
console.log({}.toString()); // 打印 "[object Object]"
//ES6次方简写
console.log(3**2); //表示3的平方
14.5 立方根cbrt,e的幂exp, 单精度浮点 fround
// cbrt是取立方根结果,类似 Math.pow(27,1/3)
console.log(Math.cbrt(27),Math.pow(27,1/3)); //3 3
// exp是自然对数e的幂函数,e^ln2 = 2;
console.log(Math.exp(Math.LN2),Math.exp(Math.LN10)); //2 10
// 转成最近的单精度浮点数的数字
console.log(Math.fround(100.1));
15. 对象方法
15.1 对象遍历 for in
let a={
name:'阿飞',
'age':18,
marry:true,
handsome:true
}
//for in循环,遍历对象,也可以是数组
for(let key in a){
console.log(key,":",a[key]);
}
15.2 对象的增删改查
//对象的属性是无序的,一般按照字母先后顺序展示
let a={
name:'阿飞',
age:18,
marry:true
}
console.log(a); //这里a是引用,后面改了,这边也能相应
//增
a.GF = ['朱雀','丫丫','岚岚','茜茜'];
//改
a.age = 21;
//删除
delete a.marry;
//查找,是否存在
console.log('age' in a);
15.3 json JSON.stringify() JSON.parse()
//json 是一个格式非常标准长得像对象的字符串
//通用字符串,基本上所有语言都能识别的字符串格式
//let a = '{"name":"阿飞","age":18,"marry":true}';
let a={
'name':'阿飞',
age:18,
marry:true
};
//将一个对象转为JSON格式 JSON.stringify() 反序列化
let b=JSON.stringify(a)
console.log(b);
//将JSON序列化, JSON.parse() 解析成对象
let c = '{"a":10,"b":"狗蛋","c":true}';
//必须是标准严格的JSON格式才能解析,里面必须用双引号包起来""
console.log(JSON.parse(c));
15.4 es6的默认值
let [a,b=10]=[5]; // a=5 b=10
let {x:hh,y:tt=20} = {x:11}; // hh=11 tt=20
// function fn([a,b]) {
// console.log(a,b,arguments);
// }
// fn([5]);
function fn({a=10,b=100}) {
console.log(a,b,arguments);
};
//fn({a:5});
//fn({a,b});
fn({}); // 10 100
//无实参取形参的默认值{x,y},有实参对应实参的默认值{x:10,y:30}
function ffn({x,y} = {x:10,y:30}) {
console.log(x,y);
}
ffn(); //10 30
ffn({}); //un un
15.5 箭头函数
/*
ES6 箭头函数
() =>
*/
/* 形参 返回值 */
let fn = v => v;
//ES5写法如下
var fn = function (v) {
return v;
}
/* 加法写法 */
var fn = function (a,b) {
return a+b;
}
let fn = (a,b) => {a+b};
/* 函数内容较多 */
var fn=function (a,b) {
let c = a+2;
let d = b-3;
return(c+d);
}
let fn = (a,b)=>{
let c = a+2;
let d = b-3;
return(c+d);
}
/* 如果返回对象时,需要再加上() */
var fn = function () {
return {a:10,b:20};
}
let fn = () => ({a:10,b:20})
/*
document.onclick = function () {
console.log(this);
}
*/
//通常用在回调函数内,方便使用
let arr=[1,2,3];
arr.forEach((value,key)=>{
console.log(value);
});
let b = arr.map(v=>v*v); //结果平方返回
console.log(b);
16.定时器
16.1 setTimeout(cb,T)
/*
setTimeout 一次执行定时器
param1:回调函数,或者是字符串包裹的js脚本,或者是引号包裹的全局作用域内的函数自执行
param2:数字(毫秒单位)
*/
setTimeout(function () {
alert("timeout!");
},1000);
let fn = function () {
alert(1);
return function () {
alert(3);
}
};
setTimeout(fn(),1000); //不能是返回值,第一个参数是函数
let str = "let a=10;alert(a);"; //可以接收字符串参数,当成JS代码来读
setTimeout(str,2000);
let fn = function () { // 如果fn不在全局作用域内,则 "fn()"找不到将报错
alert(4);
};
setTimeout("fn()",1500); //默认在全局中执行引号的内容,作用域在全局
16.2 setInterval(cb,T)
/*
setInterval 循环定时
*/
let num=0;
let fn = function () {
console.log(++num);
}
setInterval(fn,1000/60); //最小时间间隔最多是60次每秒,
16.3 定时器队列
主程序执行完之后才执行定时器队列
//读到setTimeout时将定时器放入队列中,主程序执行完之后才执行队列
//所以先弹出3,后弹出4
setTimeout(function () { //进入队列后执行
alert(4);
},0);
!function fn() { //先执行
alert(3);
}();
16.4 参数
回调函数带参时,放在定时器第二个参数之后
//定时器的函数有参数时,直接放在第二个参数之后
(function () {
function fn(a,b) {
console.log(a+b);
}
//setInterval(fn(2,7),1000); //这样会直接执行
/*
setInterval('fn(2,7)',1000); //双引号内的内容默认丢在全局中执行,全局中找不到fn,报错
window.fn = fn; //将局部fn赋值到window
*/
setInterval(fn,1000,25,14); //参数接着放
})();
16.5 返回值
/*
返回值是按定时器出现顺序从1号开始的编号,作用是用来清除定时器的
编号不区分作用域
*/
let x = setTimeout(function(){alert(3);},50000);
let y = setTimeout(function(){alert(4);},60000);
let z = setTimeout(function(){alert(5);},70000);
let w = setInterval(function(){alert(6);},80000);
let v = setInterval(function(){alert(7);},90000);
console.log(x,y,z,w,v); // 1 2 3 4 5
16.6 清除定时器
clearInterval(t)
clearTimeout(t)
let x = setTimeout(function(){console.log("a")},2000); // 1
let y = setTimeout(function(){console.log("b")},2000); // 2
console.log(x,y);
clearTimeout(y); //清除编号为2的定时器
// 定时器的队列编号跟作用域没关系,按出现顺序编号
(function () {
let x = setTimeout(function(){console.log("a")},2000); // 3
let y = setTimeout(function(){console.log("b")},2000); // 4
console.log(x,y);
})();
16.7 requestAnimationFrame(cb)
canselAnimationFrame()
/*
H5出的新的API
requestAnimationFrame() 不需要第二个参数,间隔是浏览器的刷新频率,单次执行
主要是让动画很流畅,浏览器准备好就刷新
CSS3关于动画的API底层都是它
取消
canselAnimationFrame()
*/
let oW = document.getElementById("wrap");
let start=0;
function m(){
start += 2;
oW.style.left = start+'px';
requestAnimationFrame(m);
}
requestAnimationFrame(m);
// 兼容
window.requestAnimationFrame = window.requestAnimationFrame || function (fn) {
setTimeout(fn,1000/60);
};
window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
16.8 案例,自动无缝轮播图
关键点: oImg.style.transitionDuration = 0+'s';
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{font-family: "Microsoft YaHei",serif;}
body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
ol,ul,li{margin:0;padding:0;list-style:none;}
img{border:none;}
#wrap{
overflow: hidden;
position: relative;
width:520px;
height:280px;
margin:50px auto;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#wrap .img{
position: absolute;
top:0;
left:0;
width:1000%;
height:100%;
transition-property: left;
}
#wrap .img li{
position: relative;
float:left;
width:10%;
height:100%;
}
#wrap .tab{
position: absolute;
left:0;
right:0;
bottom:15px;
z-index:5;
width:80px;
margin:auto;
background-color: rgba(255,255,255,.3);
border-radius: 10px;
font-size:0;
text-align:center;
}
#wrap .tab li{
float: left;
width:10px;
height:10px;
margin:3px;
border-radius: 10px;
background-color: white;
cursor:pointer;
}
#wrap .tab li.active{
background-color: #ff5000;
}
#wrap>span{
display: none;
z-index:5;
position: absolute;
top:0;
bottom: 0;
width:30px;
height:30px;
margin:auto;
background-color: rgba(0,0,0,.3);
border-radius: 30px;
color:#fff;
font-size:22px;
line-height:30px;
cursor: pointer;
}
#wrap:hover>span{
display: block;
}
#wrap>span:hover{
background-color: rgba(0,0,0,.5);
}
#wrap .left{
left:-12px;
text-indent: .5em;
}
#wrap .right{
right:-12px;
text-indent: .1em;
}
</style>
</head>
<body>
<div id="wrap">
<ul class="img">
<li>
<img src="img/05.webp">
</li>
<li>
<img src="img/01.webp">
</li>
<li>
<img src="img/02.jpg">
</li>
<li>
<img src="img/03.jpg">
</li>
<li>
<img src="img/04.png">
</li>
<li>
<img src="img/05.webp">
</li>
<li>
<img src="img/01.webp">
</li>
</ul>
<ul class="tab">
<li class="active"></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<span class="left"><</span>
<span class="right">></span>
</div>
<script>
(function () {
//定义变量
let oWrap = document.getElementById("wrap"),
aTabLi = document.querySelectorAll("#wrap .tab li"),
oImg = document.querySelector("#wrap .img"),
aImgLi = document.querySelectorAll("#wrap .img li"), //做不到无缝
oLeft = document.querySelector("#wrap .left"),
oRight = document.querySelector("#wrap .right"),
len = aImgLi.length-1,
lastIndex=1,
timer='';
//做一个定时器动画
window.requestAnimationFrame = window.requestAnimationFrame || function (fn){setTimeout(fn,1000/60);};
window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
oImg.style.left = '-'+lastIndex*100+'%'; //初始是显示第一个
//封装动作事件
function move(x) {
aTabLi[x].classList.remove("active");
oImg.style.transitionDuration = .3+'s'; //动画时间
oImg.style.left = '-'+lastIndex*100+'%'; //动画步骤
if(lastIndex === len){ //到达最后一个了!len = 6
requestAnimationFrame(function () {
//偷天换日,改到第一个
lastIndex=1;
aTabLi[0].classList.add("active");
});
//坐标移动该怎么不被动画发现呢,延时吧,等于duration 0.3s
setTimeout(function () {
oImg.style.left = '-'+lastIndex*100+'%';
oImg.style.transitionDuration = 0+'s';
},300);
}else if(lastIndex === 0){ //到达第0个了!len-1 = 5
requestAnimationFrame(function () {
//偷天换日,改到第一个
lastIndex=len-1;
aTabLi[4].classList.add("active");
});
//坐标移动该怎么不被动画发现呢,延时吧,等于duration 0.3s
setTimeout(function () {
oImg.style.left = '-'+lastIndex*100+'%';
oImg.style.transitionDuration = 0+'s';
},300);
}else{
aTabLi[lastIndex-1].classList.add("active");
}
}
//tab点击事件
[...aTabLi].forEach((oTabLi,index)=>{
oTabLi.onclick = function () {
if(index === lastIndex-1)return;
let x = lastIndex-1;
lastIndex = index+1;
move(x);
}
});
//left点击事件 , lastIndex = 0 1 2 3 4
oLeft.onclick = function () {
let x = lastIndex-1; // [0,4]
lastIndex --;
move(x);
}
//right点击事件
oRight.onclick = function () {
let x = lastIndex-1; //x从0开始
lastIndex++;
move(x);
}
//定时器
timer = setInterval(function () {
let x = lastIndex-1; //x从0开始
lastIndex++;
move(x);
},3000);
//停止
oWrap.onmouseenter=function () {
clearInterval(timer);
}
//继续
oWrap.onmouseleave=function () {
timer = setInterval(function () {
let x = lastIndex-1; //x从0开始
lastIndex++;
move(x);
},3000);
}
})();
</script>
</body>
</html>
17. 时间API
17.1 Date类
/*Date类
new Date()
本地此时此刻的日期对象/时间戳
*/
let d = new Date(); //获取的是对象
console.dir(d);
console.log(d.getTime()); // 时间戳
let t = new Date(d.getTime());
console.log(t);
//以下API返回数字 number
console.log(d.getFullYear()); //得到 年
console.log(d.getMonth()+1); //得到 月(从0开始计数,应该+1返回)
console.log(d.getDate()); //日
console.log(d.getHours()); //时
console.log(d.getUTCHours()); //0时区 UTC
console.log(d.getMinutes()); //分
console.log(d.getSeconds()); //秒
console.log(d.getDay()); //星期 星期日是0
console.log("====================");
console.log(d.toUTCString());
let x = new Date(); //日期对象可以做减法,会自动调用getTime进行相减
//定时器都不是 精准的计时
setInterval(function () {
let y=new Date();
console.log(y-x);
x=y;
},50); //周期很小,则误差较大
17.2 设置时间戳
//无参是获取,有参是设置
let x=new Date(2018,8-1,8,1,1,1); //月份从0开始的,所以设置8月应输入7
let x=new Date(2018); //只有一个参数时,会被认为是毫秒时间戳,从1970年开始加
let x=new Date(2018,5-1); //默认1日,0时0分0秒
console.log(x);
let a = new Date().getTime();
console.log(new Date(a-3600000)); //打印一个小时前的时间
17.3 网页倒计时跳转
<p>404 页面未找到~~</p>
<div><span>8</span>秒后,返回 <a href="">主页</a></div>
<script>
(function () {
let oS = document.querySelector("div span");
let oVal = 8;
setInterval(function () {
oS.innerHTML = --oVal;
if(oVal === 1){
window.location.href = "http://web.tanzhouedu.com";
}
},1000)
})();
</script>
17.4 新年倒计时
(function () {
let oW = document.getElementById("wrap");
let x = new Date(2020,2-1,24); //过年时间
function fn(){
let d = x - new Date(); //差了多少秒
let DD = Math.floor(d/1000/60/60/24); //天
let HH = Math.floor(d/1000/60/60%24);
let MM = Math.floor(d/1000/60%60);
let SS = Math.floor(d/1000%60);
if(DD<10) DD = '0'+DD;
if(HH<10) HH = '0'+HH;
if(MM<10) MM = '0'+MM;
if(SS<10) SS = '0'+SS;
oW.innerHTML = `距离过年还有 <span>${DD}</span> 天 <span>${HH}</span> 小时 <span>${MM}</span> 分 <span>${SS}</span> 秒;`;
};
fn();
setInterval(fn,1000);
})();
18. 运动框架
18.1 基础的移动
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#wrap{
position: absolute;
left:0;
top:0;
width:100px;
height:100px;
background-color: pink;
}
</style>
</head>
<body>
<div id="wrap"></div>
<script>
(function () {
let oWrap = document.getElementById("wrap");
let startVal = 0;
function m() {
startVal +=3;
oWrap.style.left = startVal + 'px';
requestAnimationFrame(m); //推荐,保证前一个动画执行完成后,进入下一次动画
//setTimeout(m,1000/60);
}
m();
})();
</script>
</body>
</html>
18.2 封装好的运动框架
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
<style>
body{font-family: "Microsoft YaHei",serif;}
body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
ol,ul,li{margin:0;padding:0;list-style:none;}
img{border:none;}
#wrap{
width:50px;
height:50px;
margin-left:300px; /*百分比在IE显示百分比,要转成px*/
background-color: pink;
opacity: .8;
filter:alpha(opacity=80); /*标准IE浏览器的兼容,opacity 0-100 */
}
</style>
<script src="move.js"></script>
</head>
<body>
<div id="wrap"></div>
<script src="move.js"></script>
<script>
var oW = document.getElementById("wrap");
Move(oW,"marginLeft",600,3);
Move(oW,"width",500,3);
Move(oW,"height",500,3);
Move(oW,"opacity",0,.01); //opacity没有单位
</script>
</body>
</html>
'use strict';
/*
* 运动框架
* param:
* ele - object 必须 表示要进行运动的节点
* attr - string 必须 表示要改变的css属性
* target - number 必须 表示属性的终点值
* step - number 选填 表示运动速度的正值,默认5
*return:
*
*/
window.Move = function () {
//兼容定时器
window.requestAnimationFrame = window.requestAnimationFrame || function (fn) {
setTimeout(fn, 1000 / 60);
};
window.cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
//框架函数
return function Move(ele, attr, target) {
var step = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5;
//ele.style.marginLeft 只能获取行内样式
//console.log(getComputedStyle(ele)); //原生JS,存储着节点对象全部的样式
//获取存储着ele展示样式的对象
var cssObj = ele.currentStyle || getComputedStyle(ele); //解决兼容性问题IE8用currentStyle
//初始的值
var sVal = parseFloat(cssObj[attr]); //去掉单位,变成数字
//兼容IE的opacity
if(attr === "opacity" && isNaN(sVal))sVal=1;
//考虑初始值与目标值大小的问题
var bool = sVal>target;
if(sVal > target){
step = -Math.abs(step); //负值
}else if (sVal < target){
step = Math.abs(step); //正值
}else{
return;
}
function f() {
sVal += step; // + -step
if (bool?sVal<=target:sVal>=target) {
sVal = target;
}else {
requestAnimationFrame(f);
}
if(attr === 'opacity'){
ele.style[attr] = sVal;
ele.style.filter = "alpha(opacity="+100*sVal+")"; // IE浏览器兼容
}else if(attr === 'zIndex'){
ele.style[attr] = sVal; //不加单位
}else{
ele.style[attr] = sVal + 'px'; //加单位
}
}
requestAnimationFrame(f);
};
}();
19. DOM
19.1 节点nodeType nodeName nodeValue
/*
元素节点的nodeType是 1 nodeName是 大写的标签名 nodeValue=null
元素属性的nodeType是 2 nodeName是 属性名 nodeValue=属性值
文本节点的nodeType是 3 nodeName是 #Text nodeValue=文本内容
注释节点的nodeType是 8 nodeName是 #comment nodeValue=注释内容
*/
let oW = document.getElementById("wrap"),
oC = document.getElementsByClassName("content")[0];
console.dir(oW);
console.log(oW.nodeType); //1 元素节点
console.log(oW.nodeName); //DIV
console.log(oW.childNodes); //子节点,包含所有节点类型
console.log(oW.attributes[2].nodeType); // 2
// console.log(typeof oC.childNodes[0].nodeValue);
oW.attributes[2].nodeValue = '朱雀'; //不建议这样修改,应该坐标是不确定的
console.log(oW.attributes[2]); // afei='朱雀'
19.2 子节点 childNodes children
<div id="wrap">
阿飞飞
<p>gg</p>
<p>ss</p>
<a href="">gg</a>
</div>
<script>
let oW = document.getElementById("wrap");
console.log(oW.childNodes); //IE不兼容,谷歌连换行也能获取,不实用
//常用 !!!!!!
console.log(oW.children); //只获取子元素节点哦 ,有三个子元素(标签)
//innerHTML是刷新整个内容,要求必须刷新后再get元素,这样很不方便
</script>
19.3 插入节点createElement
- createElement 创建元素节点
- createTextNode 创建文本节点
- appendChild 创建的是子节点
- insertBefore(A,B) 创建子节点,A元素节点放在B元素节点之前
<div id="wrap">
阿飞飞
<p>pp</p>
<p id="on">gg</p>
<a href="#">123</a>
</div>
<script>
let oW = document.getElementById("wrap");
let oN = document.getElementById("on");
let oP = document.querySelector("p");
oP.onclick = function(){ //节点的变化不影响其操作和属性
alert(5);
}
//创建文本节点对象
let text = document.createTextNode("朱雀");
//console.dir(text);
//创建元素节点对象
let oDiv = document.createElement("div");
//从后面添加子节点 appendChild
oW.appendChild(text);
//oW.appendChild(oDiv);
//在某个子元素的前面添加 (a,b) a是新元素节点
//oW.insertBefore(oDiv,oP);
//放在子元素第一位
oW.insertBefore(oDiv,oW.children[0]); //oW.childNodes[0] 所有的第一位
</script>
19.4 修改节点位置
<div id="wrap">
<p>阿飞</p>
<p>朱雀</p>
</div>
<div id="box"></div>
<script>
let oBox = document.getElementById("box");
let aP = document.getElementsByTagName("p");
//转移子元素,原来元素的属性和方法不会改变
oBox.appendChild(aP[0]);
</script>
19.5 删除节点 removeChild()
<div id="wrap">
<p>555</p>
<p>666</p>
</div>
<div class="box"></div>
<script>
//只有父级节点才能删除子节点
let oW = document.getElementById("wrap");
let oBox = document.getElementsByClassName("box")[0];
let oP = document.getElementsByTagName("p")[1];
//父级删除了子节点,但变量oP 仍保留了被删除的节点
oW.removeChild(oP);
document.onclick = function () {
oBox.appendChild(oP); //oP仍可以使用
}
</script>
19.6 获取节点
- firstChild 第一个子节点,一般获取的都是文本节点 ->换行符
- firstElementChild 第一个元素子节点
- nextSibling 下一个兄弟节点
- nextElementSibling 下一个兄弟元素节点
- previousElementSibling 上一个兄弟元素节点
<div id="wrap">
<p>11</p>
<p>22</p>
<p>33</p>
</div>
<script>
let oW = document.getElementById("wrap");
console.log(oW.firstChild); //第一个子节点,文本节点->换行符
console.log(oW.firstElementChild); //第一个元素子节点, <p>11</p>
console.log(oW.children[0]); //第一个元素子节点, <p>11</p>
var aChild = oW.children; //是动态的更新,根据儿子变化而变化,
var p1 = aChild[0]; //元素节点
var p2 = aChild[1];
var p3 = aChild[2];
console.log(p1.nextSibling); //下一个兄弟节点(文本换行符)
//标准浏览器
console.log(p1.nextElementSibling); //下一个兄弟元素(如果没有,打印null)
console.log(p2.nextElementSibling); //
console.log(p3.nextElementSibling); //没有返回null
//上一个兄弟节点 previousElementSibling
console.log(p2.previousElementSibling);
//IE兼容,只有nextSibing,下一个兄弟元素节点
function getNextSibing(ele) {
if(ele.nextElementSibling !== undefined){
return ele.nextElementSibling;
}else{
return ele.nextSibling; //IE的
}
}
console.log(getNextSibing(p1));
console.log(getNextSibing(p2));
console.log(getNextSibing(p3));
</script>
- parentNode 父亲节点
- offsetParent 定位父级,离得最近的拥有定位的父级,都没有时就是body
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#wrap{
position: relative;
}
</style>
</head>
<body>
<div id="wrap">
<p id="btn">4545454</p>
</div>
<script>
let oBtn = document.getElementById("btn"),
oW = document.getElementById("wrap");
console.log(oBtn.parentNode); // === oW typeof oW = "object"
console.log(oW.parentNode); // body
//自删除
//oBtn.parentNode.removeChild(oBtn);
console.log(oBtn.offsetParent); //定位父级 oW
</script>
</body>
19.7 克隆节点 oP.cloneNode()
节点的事件不被克隆
- oP.cloneNode() 默认不复制内容
- oP.cloneNode(true) 包括内容全部复制,但事件不会复制
<div id="wrap">
<p class="gg">745545</p>
</div>
<div id="btn">444</div>
<script>
//节点具有唯一性,只有clone可以 默认不复制里面的内容,参数为true内容也克隆, 事件不能复制
let oP = document.getElementsByClassName("gg")[0],
oBtn = document.getElementById("btn");
oP.onclick =function () {alert(1);}; //事件不能clone
//oBtn.appendChild(oP); 直接appendChild是移动节点,并未增加
let clone = oP.cloneNode(true); //克隆获得一个新的节点对象
oBtn.appendChild(clone);
</script>
19.8 节点替换 replaceChild(A,B) , A将B替换掉
<div id="wrap">
123
</div>
<div id="btn">456</div>
<script>
let oW = document.getElementById("wrap"),
oB = document.getElementById("btn");
oW.replaceChild(oB,oW.childNodes[0]);
</script>
19.9 节点片段 document.createDocumentFragment()
(function () {
let oW = document.getElementById("wrap");
//生成10个小球
(function () {
//节点片段,暂时存放节点的对象
let oF = document.createDocumentFragment();
//生成十个小球,一次性append进oW内,省的渲染多次
for(let i=0;i<10;i++){
let oP = document.createElement("p");
oF.appendChild(oP);
}
oW.appendChild(oF);
})();
//运动
(function () {
let aP = [...oW.children];
let MaxL,MaxT;
window.onresize = (function r(){
MaxL = window.innerWidth - 100;
MaxT = window.innerHeight - 100;
return r;
})();
//随机初始速度
let speedArr = [];
aP.forEach((ele,index)=>{
speedArr[index] = {
stepX : Math.floor(Math.random()*12+4),
stepY : Math.floor(Math.random()*12+4)
};
});
//随机颜色
function changeColor(ele) {
let [r,g,b] = [
Math.floor(Math.random()*256),
Math.floor(Math.random()*256),
Math.floor(Math.random()*256)
];
ele.style.backgroundImage = `radial-gradient(white,rgb(${r},${g},${b}))`;
}
//遍历运动
!function m(){
aP.forEach((ele,index)=>{
let left = ele.offsetLeft + speedArr[index].stepX;
let top = ele.offsetTop + speedArr[index].stepY;
if(left >= MaxL){
left = MaxL;
speedArr[index].stepX = -speedArr[index].stepX;
changeColor(ele);
}
if(left <=0){
left = 0;
speedArr[index].stepX = -speedArr[index].stepX;
changeColor(ele);
}
if(top>=MaxT){
top = MaxT;
speedArr[index].stepY = - speedArr[index].stepY;
changeColor(ele);
}
if(top<=0){
top = 0;
speedArr[index].stepY = - speedArr[index].stepY;
changeColor(ele);
}
ele.style.left = left+'px';
ele.style.top = top + 'px';
});
requestAnimationFrame(m);
}();
})();
})();
20. DOM宽高属性与事件对象
20.1 视图页面宽高,无单位
window.innerWidth
document.documentElement.clientWidth
<div id="wrap"></div>
<script>
/* Window视图属性
获取页面显示区的宽高,IE8及以下不兼容
*/
console.log(window.innerWidth);
console.log(window.innerHeight);
document.body;
document.head;
document.title;
document.documentElement; //获取html元素节点
console.log(document.documentElement === document.querySelector("html")); // true
//Document文档视图 下面的IE兼容
console.log(document.documentElement.clientWidth); //html页面宽度
console.log(document.documentElement.clientHeight); //html页面高度
</script>
20.2 元素宽高,无单位
- getComputedStyle(oWrap).width css样式宽度,有单位
- oWrap.clientWidth 客户端宽度 width+padding 无单位
- oWrap.offsetWidth 客户端宽度 + border
- oWrap.scrollWidth 滚动宽度,一般用在出现滚动条, = 客户端宽度
/*
number类型
clientHeight/clientWidth width+padding
offsetHeight/offsetWidth width + padding + border
scrollHeight/scrollWidth 滚动宽度,超出视图仍显示正常宽度,不管有没有超出隐藏
*/
let oWrap = document.getElementById("wrap");
console.log(getComputedStyle(oWrap).width); //获取元素css样式设置的宽度,有单位
console.log(oWrap.clientWidth); //width + padding
console.log(oWrap.offsetWidth); //width + padding + border
//scrollWidth 元素占用的宽度,生成滚动条,内容不超出时数值等于clientWidth
console.log(oWrap.scrollWidth); //如果有超出部分,正确的反映出超过之后的宽度,不管有没有加超出隐藏
20.3 定位left值offsetLeft与top值offsetTop
只有距离定位父级的左值和上值 ,没有右下
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#wrap{
/*position: relative;*/
margin:50px;
}
p{
width:10px;
height:10px;
background-color: pink;
}
</style>
</head>
<body>
<div id="wrap">
8888
<p></p>
</div>
<script>
/* 只有距离定位父级的左值和上值 */
let oP = document.querySelector("#wrap p");
//wrap没加position,则定位父级是body
console.log(oP.offsetLeft); //到定位父级的距离
console.log(oP.offsetTop); //到定位父级的距离
//获取元素到文档body的距离
function getOffset(ele) {
let dis = {
top:0,left:0
};
while(ele !== document.body){
dis.top += ele.offsetTop;
dis.left += ele.offsetLeft;
ele = ele.offsetParent; //定位父级
}
return dis;
}
console.log(getOffset(oP));
</script>
</body>
</html>
20.4 body的滚动高度,用document.documentElement.scrollTop
<body style="height:2000px;">
<div id="wrap"></div>
<script>
document.onclick = function () {
//页面滚动高
console.log(document.documentElement.scrollTop);
//document.body.scrollTop 谷歌弃用了,但是手机可能还未改
//最好这样写去获取页面的滚动高
console.log(document.body.scrollTop || document.documentElement.scrollTop); //保险起见
}
</script>
</body>
20.5 元素的滚动高,父级的scrollTop
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#wrap{
overflow-y:auto ; /*y竖直方向有滚动条*/
width:300px;
height:500px;
background-color: pink;
margin:50px auto;
}
#wrap p{
height:2000px;
}
</style>
</head>
<body>
<div id="wrap">
<p></p>
</div>
<script>
let oW = document.getElementById("wrap");
oW.onclick = function(){
console.log(oW.scrollTop); //oW元素竖直方向的滚动高度
}
</script>
</body>
</html>
20.6 scrollTop无单位,可以赋值
<body style="height: 2000px">
<div id="wrap"></div>
<script>
document.onclick = function () {
document.documentElement.scrollTop = 500;
}
</script>
</body>
20.7 getBoundingClientRect()获取边界客户端矩形,对象形式,无单位
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#wrap{
/*position: relative;*/
margin:50px;
}
p{
width:10px;
height:10px;
background-color: pink;
}
</style>
</head>
<body>
<div id="wrap">
8888
<p></p>
</div>
<script>
let oP = document.querySelector("#wrap p");
console.log(oP.getBoundingClientRect());
// DOMRect {x: 50, y: 71, width: 10, height: 10, top: 71, bottom:81, left:50, right:60}
//top bottom left right 对应 边 到 body的距离
// x y是坐标
</script>
</body>
</html>
20.8 oW.scrollIntoView(true) 滚动到可视区
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#wrap{
position: absolute;
top:1500px;
width:100px;
height:100px;
background-color: pink;
}
</style>
</head>
<body style="height: 3000px;">
<div id="wrap"></div>
<script>
let oW = document.getElementById("wrap");
document.onclick = function () {
//oW.scrollIntoView(false); //true是跳转到视图顶部,false跳转到视野底部
oW.scrollIntoView(true);
}
</script>
</body>
</html>
20.9 event事件对象
/*
event事件对象
事件函数执行时,第一个形参就是事件对象:存储着和该次事件相关的一些信息
IE8及以下浏览器,使用event全局变量来表示事件对象
该对象里面比较重要的一些属性
clientX/clientY 事件触发时,鼠标距离可视区的距离
pageX/pageY 鼠标距离文档的位置(IE8 不兼容)
*/
//IE的事件函数没有形参
//兼容
document.onclick = function (ev) {
ev = ev || window.event; // IE的Event是全局变量
console.log(ev);
}
20.10 鼠标事件 onmousedown onmousemove onmouseup
document.onmousedown = function () {
console.log("down");
document.onmousemove = function () {
console.log("move");
}
}
document.onmouseup = function () {
console.log("up");
document.onmousemove = null; //默认属性是null
}
20.11 案例:可拖拽的盒子
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
#wrap{
position: absolute;
left: 0;
top:0;
width:100px;
height:100px;
background-color: pink;
}
</style>
</head>
<body>
<div id="wrap"></div>
<script>
let oW = document.getElementById("wrap");
oW.onmousedown = function (ev) {
//获取鼠标初始的位置
let sX = ev.clientX;
let sY = ev.clientY;
//获取按下时,盒子的位置
let sLeft = oW.offsetLeft;
let sTop = oW.offsetTop;
document.onmousemove = function (eve) {
//获取鼠标当前的位置
let mX = eve.clientX;
let mY = eve.clientY;
//计算鼠标位置的变化量
let x = mX - sX;
let y = mY - sY;
//盒子当前的位置 = 盒子按下的位置 + 变化量
oW.style.left = sLeft + x + 'px';
oW.style.top = sTop + y + 'px';
};
};
document.onmouseup = function () {
console.log("up");
this.onmousemove = null;
}
</script>
</body>
</html>
20.12 案例:十球发射
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
<style>
body{font-family: "Microsoft YaHei",serif;}
body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
ol,ul,li{margin:0;padding:0;list-style:none;}
img{border:none;}
div.box{
position: absolute;
left:0;
top:0;
width:100px;
height:100px;
background-color: #db3a45;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="wrap">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<script>
(function () {
let aBox = [...document.getElementsByClassName("box")];
//最大边距
let MaxLeft,MaxTop ;
window.onresize = (function s() {
MaxLeft = window.innerWidth-100;
MaxTop = window.innerHeight-100;
return s;
})();
//步长
let step = [
{
stepX:3,
stepY:4,
},
{
stepX:5,
stepY:6,
},
{
stepX:6,
stepY:7,
},
{
stepX:7,
stepY:8,
},
{
stepX:8,
stepY:9,
},
{
stepX:9,
stepY:10,
},
{
stepX:10,
stepY:11,
},
{
stepX:11,
stepY:12,
},
{
stepX:12,
stepY:13,
},
{
stepX:13,
stepY:14,
},
];
aBox.forEach((ele,index)=>{
ball(ele,index);
});
//rgb函数
function color() {
let r = Math.floor(Math.random()*256),
g = Math.floor(Math.random()*256),
b = Math.floor(Math.random()*256);
return `rgb(${r},${g},${b})`;
}
//小球运动函数
function ball(ele,index) {
//初始位置
let left = ele.offsetLeft,
top = ele.offsetTop;
!function m() {
//步长
left += step[index].stepX;
top += step[index].stepY;
//left
if(left>=MaxLeft){
left=MaxLeft;
ele.style.backgroundColor = color();
step[index].stepX = -step[index].stepX;
}
if(left<=0){
left=0;
ele.style.backgroundColor = color();
step[index].stepX = -step[index].stepX;
}
//top
if(top>=MaxTop){
top = MaxTop;
ele.style.backgroundColor = color();
step[index].stepY = -step[index].stepY;
}
if(top<0){
top = 0;
ele.style.backgroundColor = color();
step[index].stepY = -step[index].stepY;
}
ele.style.left = left+'px';
ele.style.top = top+'px';
requestAnimationFrame(m);
}();
}
})();
</script>
</body>
</html>
21. DOM事件
21.1 事件冒泡
冒泡触发顺序:从子元素开始到窗口
- event.stopPropagation() 主流浏览器阻止冒泡:
- event.cancelBubble = true; IE阻止冒泡
<div id="box">
box1
<div id="box1">
box2
</div>
</div>
<script>
/*
事件的冒泡
子元素触发了事件 如果父元素也有同类型的事件的话,父元素也会触发
触发的顺序是从子级开始,向父级方向
冒泡的触发顺序
box2 -> box1 -> body -> html
冒泡触发顺序
从子元素开始到窗口,(从儿子到爸爸)window
阻止冒泡 event.stopPropagation() 阻止传播 IE不兼容
box2 box1
*/
var box = document.getElementById("box"),
box1 = document.getElementById("box1");
document.onclick = function(){
console.log("我也触发了事件");
}
box.onclick = function () {
console.log(1);
}
box1.onclick = function (event) {
event = event ||window.event;
//event.stopPropagation(); //冒泡停止(主流浏览器)
console.log(2);
//ie阻止冒泡的 属性
//event.cancelBubble = true;
//兼容性写法
event.stopPropagation ? event.stopPropagation():event.cancelBubble=true;
}
</script>
21.2 事件监听
- attachEvent("onclick",cb) IE8
- detachEvent(事件类型,回调方法);
- addEventListener(事件类型,回调方法,捕获|冒泡) 主流浏览器
- removeEventListener(事件类型,回调方法,捕获|冒泡);
捕获与冒泡顺序相反
var oW = document.getElementById("wrap");
//DOM 0级事件, 相同名字的事件被覆盖,只能监听一个事件
oW.onclick = function () {
console.log(1); //被覆盖
};
oW.onclick = function () {
console.log(2);
};
/*
事件监听(默认事件冒泡)
用到事件的地方最好就是使用 DOM2级来监听
监听事件
主流浏览器 事件类型 "click"
ele.addEventListener(事件类型,回调方法,捕获|冒泡)
1.this指向节点本身
2.捕获与冒泡
默认是false 冒泡事件
true为捕获,与冒泡的顺序相反,从最大父级到子级开始(也能使用阻止冒泡的方式)
ie浏览 ie8 事件类型 "onclick"
oW.attachEvent(事件类型,回调方法)
1.this不再指向节点本身,指向window
ie8没有事件捕获,默认是冒泡事件
移除事件
主流浏览器
ele.removeEventListener(事件类型,回调方法,捕获|冒泡);
IE8
ele.detachEvent(事件类型,回调方法);
*/
//事件监听DOM 2级事件
//IE8
oW.attachEvent("onclick",function (e) {
e = e||window.event;
console.log(this); //this 不再指向监听事件的节点本身
console.log(e);
});
/* 主流浏览器 */
oW.addEventListener("click",function () {
console.log("我又监听了一次点击事件,理解一下DOM 2级事件");
})
var callback = function () {
console.log(1);
};
oW.addEventListener("click",callback);
//文档双击,注销事件
//该事件必须事先用变量保存,removeEventListener的参数必须与添加事件监听的参数一样,才能移除
document.ondblclick = function () {
oW.removeEventListener('click',callback);
}
21.3 事件默认行为
- oncontextmenu 默认行为指右键可选事件
- return false; dom0级阻止默认行为
- event.preventDefault(); 阻止默认行为
- event.returnValue = false; IE8阻止默认行为
<div id="wrap">
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
<p>默认行为</p>
</div>
<script>
//事件的默认行为是右边鼠标显示的可选事件 oncontextmenu
/*
阻止默认行为
DOM 0级在事件里面直接 return false,
DOM 2级
主流浏览器
event.preventDefault();
ie
event.returnValue = false;
*/
//DOM 0级在事件里面直接 return false,
document.oncontextmenu = function () {
return false;
}
//DOM 2级 preventDefault
document.addEventListener('contextmenu',function (e) {
e.preventDefault();
})
//IE8
document.attachEvent('oncontextmenu',function (e) {
e = e||window.event;
e.returnValue = false;
})
//阻止默认的滚轮事件
wrap.addEventListener('mousewheel',function (e) {
e.preventDefault();
})
</script>
21.4 滚轮事件
- mousewheel 滚轮事件 event.wheelDelta 滚动的幅度 下负上正 120 谷歌+ie
- DOMMouseScroll 火狐的滚轮事件 event.detail 滚轮的幅度 上负 3
let oW = document.getElementById("wrap");
/*
谷歌以及ie
event.wheelDelta 滚动的幅度
-120 下滚
120 上滚
火狐的 滚动事件名都不一样
DOMMouseScroll 只能通过DOM 二级事件监听
event.detail 滚动的幅度
3 下滚
-3 上滚
只有谷歌和ie有onmousewheel事件属性,默认值为null
火狐根本就没有onmousewheel属性,为undefined
*/
/*
oW.addEventListener("mousewheel",function (e) {
console.log(e.wheelDelta);
})
*/
//只能通过创建一个新的节点来判断兼容
if(document.createElement("div").onmousewheel === null){
console.log("谷歌");
}else{
console.log("火狐");
}
兼容的事件监听
var oW = document.getElementById("wrap");
//元素的事件
var fn = addEvent(oW,'click',function () {
this.style.backgroundColor = 'red';
});
//文档双击移除事件
addEvent(document,"dblclick",function () {
removeEvent(oW,'click',fn);
})
//滚轮事件
addEvent(oW,'mousewheel',function () {
console.log('我滚动了');
})
//添加监听事件
function addEvent(ele,eType,callback,capture) {
//主流浏览器
if(ele.addEventListener){
//兼容一下火狐的滚轮事件
if(eType === 'mousewheel' && document.createElement("div").onmousewheel === undefined){
eType = 'DOMMouseScroll';
}
ele.addEventListener(eType,callback,capture);
return callback;
}else{
//处理ie的this指向,ie低版本不支持bind
var codeCall = function(){
callback.call(ele);
}
ele.attachEvent('on'+eType,codeCall);
return codeCall;
}
}
//移除事件
function removeEvent(ele,eType,callback,capture) {
ele.removeEventListener? ele.removeEventListener(eType,callback,capture)
: ele.detachEvent("on"+eType,callback);
}
兼容的文档滚动
//自定义滚动
addEvent(oW,'mousewheel',function (event) {
event = event || window.event;
var dir;
if(event.detail){ //火狐的滚动值
dir = event.detail / 3; //下滚
}else{
dir = event.wheelDelta / -120; //下滚
}
//console.log(dir);
this.scrollTop += dir*50;
})
21.5 案例 自定义滚动条
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
<style>
#wrap{
position: relative;
width:400px;
height:500px;
margin:20px auto;
overflow: hidden;
user-select: none;
}
#wrap .content{
position: absolute;
left:0;
top:0;
width:370px;
font-size:14px;
}
#wrap .content li{
width:100%;
padding:5px 0 5px 10px;
margin-bottom:1px;
background-color:#eeeef0;
line-height:30px;
}
#wrap .scrollbar{
position: absolute;
right:0;
top:0;
width:20px;
height:496px;
background-color: #ccc;
background-color:rgba(200,200,200,.5);
border-radius: 10px;
border:2px solid #aaa;
box-shadow: 0 0 20px #ccc ;
}
#wrap .scrollbar .bar{
position: absolute;
left:0;
top:0;
width:20px;
height:80px;
background-color: white;
border-radius:10px;
}
</style>
</head>
<body>
<div id="wrap">
<ul class="content">
<li>
<p>1. It is never too old to learn.</p>
<p>活到老,学到老。</p>
</li>
<li>
<p>2. There is no royal road to learning.</p>
<p>学问无坦途。书山有路勤为径,学海无涯苦作舟.</p>
</li>
<li>
<p>3. A man becomes learned by asking questions.</p>
<p>不耻下问才能有学问。</p>
</li>
<li>
<p>4. A young idler, an old beggar.</p>
<p>少壮不努力,老大徒伤悲。</p>
</li>
<li>
<p>5. Study to be what you wish to seem. </p>
<p>学习可成为你所理想的人物。</p>
</li>
<li>
<p>6. By reading we enrich the mind, by conversation we polish it.</p>
<p>读书使人充实,交谈使人精明。</p>
</li>
<li>
<p>7. Books and friends should be few but good.</p>
<p>读书如交友,应求少而精。</p>
</li>
<li>
<p>8. Readingis to the mind while exercise to the body.</p>
<p>读书健脑,运动强身。</p>
</li>
<li>
<p>9. A good beginning makes a good ending.</p>
<p>良好的开端就是成功的一半。 善始者善终。</p>
</li>
<li>
<p>10. No matter how bad your heart has been broken, the world doesn’t stop for your grief. The sun comes right back up the next day.</p>
<p>不管你有多痛苦,这个世界都不会为你停止转动。太阳照样升起。</p>
</li>
<li>
<p>11. Experience is the mother of wisdom.</p>
<p>实践出真知。</p>
</li>
<li>
<p>12. Don't trouble trouble until trouble troubles you.</p>
<p>不要自寻烦恼。</p>
</li>
<li>
<p>13. Everybody dies, but not everybody lives.</p>
<p>人人都会死,但非人人都曾活过。</p>
</li>
<li>
<p>14. Doing is better than saying.</p>
<p>行胜于言。</p>
</li>
<li>
<p>15. Commitment in many, can do. It is just a lie.</p>
<p>承诺再多,都做不到。那也只不是是谎言。</p>
</li>
<li>
<p>16. No cross, no crown.</p>
<p>不经历风雨,怎能见彩虹。</p>
</li>
</ul>
<div class="scrollbar">
<div class="bar"></div>
</div>
</div>
<script>
(function () {
var oW = document.getElementById("wrap"),
oContent = document.querySelector("#wrap .content"),
oScroll = document.querySelector("#wrap .scrollbar"),
oBar = document.querySelector("#wrap .bar"),
docMove= function () {};
//内容区的滚动事件
createEvent(oW,"mousewheel",function (event) {
event = event||window.event; //兼容IE
var sT = oContent.offsetTop;
var dir = 0;
var top = 0;
if(event.detail){ //火狐
dir = event.detail / 3; //下滑
}else{ //谷歌和IE
dir = event.wheelDelta / -120; //下滑值
}
if(dir>0){
top = Math.max((sT-dir*50),-756);
}else{
top = Math.min((sT-dir*50),0)
}
oContent.style.top = top + 'px';
oBar.style.top = -top/1.82 + 'px';
event.stopPropagation ? event.stopPropagation():(event.cancelBubble=true);
},false);
//自定义滚轮区的点击事件
createEvent(oScroll,'click',function (event) {
event = event||window.event;
var y_ = event.clientY - oBar.offsetHeight/2 - oW.offsetTop;
if(y_<=0) y_=0;
if(y_>=416)y_=416;
oBar.style.top = y_+'px';
oContent.style.top = -y_*1.82 + 'px';
//阻止子级冒泡
event.stopPropagation ? event.stopPropagation():(event.cancelBubble=true);
},true);
//自定义滚轮的滚动(点击时拖放)
createEvent(oBar,'mousedown',function (event) {
event = event||window.event;
var sT = oBar.offsetTop;
var sY = event.clientY;
var top = 0;
docMove = createEvent(document,'mousemove',function (event) {
event = event||window.event;
var _Y = event.clientY - sY;
if(_Y>0) top = Math.min((sT+_Y),416);
if(_Y<0) top = Math.max((sT+_Y),0);
oBar.style.top = top+'px';
oContent.style.top = -top*1.82 + 'px';
})
})
//清除移动事件
createEvent(document,'mouseup',function (){
removeEvent(document,'mousemove',docMove);
});
//双击清除移动事件
createEvent(document,"dblclick",function () {
removeEvent(document,'mousemove',docMove);
});
//生成监听事件
function createEvent(ele,eType,callback,capture) {
if(ele.addEventListener){ //主流
//兼容火狐的滚动事件
if(eType === 'mousewheel' && document.createElement("div").onmousewheel === undefined){
eType = "DOMMouseScroll";
}
//生成监听
ele.addEventListener(eType,callback,capture);
return callback;
}else{ //IE8
var codeCall = function(){
callback.call(ele);
}
ele.attachEvent('on'+eType,codeCall);
return codeCall;
}
}
//清除事件
function removeEvent(ele,eType,callback,capture) {
if(ele.removeEventListener){
//兼容火狐的滚动事件
if(eType === 'mousewheel' && document.createElement("div").onmousewheel === undefined){
eType = "DOMMouseScroll";
}
ele.removeEventListener(eType,callback,capture);
}else{
ele.detachEvent("on"+eType,callback);
}
}
})();
</script>
</body>
</html>
22. 表单事件
22.1 表单事件
<div id="wrap"></div>
<a href="" id="x">455454</a>
<form action="" method="" id="form">
<input type="text" name="user">
<input type="radio" name="sex">
<input type="radio" name="sex">
<input type="submit">
</form>
<script>
//表单是 .name 就能直接获取对象
// name相同,获取的是相同name的数组
// checkbox多选框,name不要一样
let oForm = document.getElementById("form");
console.log(oForm.sex); // RadioNodeList(2) [input, input, value: ""]
oForm.user.value = "阿飞飞";
/*
onfocus 焦点事件
onblur 失去焦点事件
并不是所有的元素都能添加焦点事件,只有能获得焦点的元素才能添加焦点事件
页面tab键能获得焦点的元素(document,a,window,以及表单相关的元素可以)
*/
let ox = document.getElementById("x");
x.onfocus = function () { // TAB键触发
console.log("我获得焦点了");
}
x.onblur = function () {
console.log("嘤嘤,我失去焦点了");
}
//window的焦点事件
window.onfocus = function () {
document.title = "乌龙阁的博客";
}
window.onblur = function () {
document.title = "握草,出BUG!快来看看啊";
}
22.2 定时器关闭
/*
页面失去焦点时,定时器setTimeout速度下降,可能影响布局渲染
requestAnimationFrame会立即停止
*/
let num=0;
let timer = null;
function m(){
document.title = ++num;
timer = setTimeout(m,50);
//requestAnimationFrame(m);
};
m();
window.onblur = function () {
clearTimeout(timer);
}
window.onfocus = function () {
clearTimeout(timer);
m();
}
22.3 表单事件 onchange
- onchange 输入框,当失去焦点时与获取焦点时发生改变时触发
- oninput 输入框发生变化时,实时的触发
- onselectstart 选中文字,触发
- onsubmit 表单触发提交事件
- 用select标签的name属性获取选中的option值,如 oForm.gg.value
<form action="" method="" id="form">
<input type="text" name="user">
<input type="radio" name="sex">
<input type="radio" name="sex">
<input type="submit">
<select name="gg" id="h">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
</form>
<div id="wrap">
文字文字文字文字文字文字文字文字
</div>
<script>
/*
输入框的onchange,判断获取焦点时与失去焦点时的差异
oninput 响应实时变化事件
*/
let oForm = document.getElementById("form");
/*
oForm.user.onchange = function () {
console.log(1);
}
*/
/*
oForm.user.oninput= function () {
console.log(1);
}
*/
oForm.gg.onchange=function () {
console.log("选项发生了改变",oForm.gg.value);
}
//onselectstart 选中文字时,触发事件
document.getElementById("wrap").onselectstart = function () {
console.log(2);
return false; //阻止默认操作
}
//表单的提交事件,提交后跳转一个页面
oForm.onsubmit = function () {
console.log("提交");
return false; //拒绝提交(用于判断是否满足提交条件)
}
</script>
22.4 案例,限制焦点
<form action="" method="" id="form">
<input type="text" name="user">
<input type="text" name="user1">
<input type="text" name="user2">
</form>
<button id="btn">
按钮
</button>
<script>
let oForm = document.getElementById("form");
let oBtn = document.getElementById("btn")
/* API
focus() 加焦点
blur() 失去焦点
submit() 提交api
*/
let aInp = [...oForm.children]; //动态的
aInp.forEach((ele,index)=>{
ele.oninput = function () {
if(this.value.length >= 5){ //大于5个离开
this.disabled = true;
aInp[index+1] && aInp[index+1].focus(); //存在则转移到下一个焦点
}
};
ele.onblur = function () {
if(this.value.length<5){ //不满5个不能离开
this.focus();
}
}
})
22.5 window.onready window.onload
//等待全部加载完毕
window.onload = function () {
}
//只需要结构加载完毕即可
window.onready = function () {
}
22.6 键盘事件
- keydown 按键按下
- keyup 按键抬起
/*
按键按下: keydown keypress
keydown 在 keypress之前触发
down响应所有按键
press事件只响应能键入值的按键,enter也能响应,不响应功能键(退格,上下左右)
按键抬起: keyup
按键抬起时响应
*/
document.onkeydown = function () {
console.log("处于按下去状态ing");
}
document.onkeypress = function(){
console.log("press");
}
document.onkeyup = function () {
console.log("按键抬起了!");
}
键值
- 回车键 keyCode = 13
- F12 keyCode = 123
/*
事件event只包含键盘的属性,没有鼠标的信息
e.keyCode
*/
document.onkeydown = function (e) {
console.log(e);
console.dir(e.keyCode);
if(e.keyCode === 123){ // 123 阻止按键 F12 打开调试面板
return false;
}
}
按键控制盒子移动
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
<style>
body{font-family: "Microsoft YaHei",serif;}
body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
ol,ul,li{margin:0;padding:0;list-style:none;}
img{border:none;}
#wrap{
position: absolute;
left:200px;
top:200px;
width:100px;
height:100px;
background-color: pink;
}
</style>
</head>
<body>
<div id="wrap"></div>
<script>
let oW = document.getElementById("wrap");
document.onkeydown = function (ev) {
let keyCode = ev.keyCode;
switch (keyCode) {
case 65: //a
oW.style.left = oW.offsetLeft-5+'px';
break;
case 87: //w
oW.style.top = oW.offsetTop-5+'px';
break;
case 83: //s
oW.style.top = oW.offsetTop+5+'px';
break;
case 68: //d
oW.style.left = oW.offsetLeft+5+'px';
break;
}
};
//运动
</script>
</body>
</html>
多按键同时控制
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
<style>
body{font-family: "Microsoft YaHei",serif;}
body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
ol,ul,li{margin:0;padding:0;list-style:none;}
img{border:none;}
#wrap{
position: absolute;
left:200px;
top:200px;
width:100px;
height:100px;
background-color: pink;
}
</style>
</head>
<body>
<div id="wrap"></div>
<script>
let oW = document.getElementById("wrap");
let ifDown = {
65:{
bool:false,
timer:null,
setTimer(){
oW.style.left = oW.offsetLeft-5+'px';
this.timer = requestAnimationFrame(this.setTimer.bind(this));
},
clearTimer(){
cancelAnimationFrame(this.timer);
}
},
87:{
bool:false,
timer:null,
setTimer(){
oW.style.top = oW.offsetTop-5+'px';
this.timer = requestAnimationFrame(this.setTimer.bind(this));
},
clearTimer(){
cancelAnimationFrame(this.timer);
}
},
83:{
bool:false,
timer:null,
setTimer(){
oW.style.top = oW.offsetTop+5+'px';
this.timer = requestAnimationFrame(this.setTimer.bind(this));
},
clearTimer(){
cancelAnimationFrame(this.timer);
}
},
68:{
bool:false,
timer:null,
setTimer(){
oW.style.left = oW.offsetLeft+5+'px';
this.timer = requestAnimationFrame(this.setTimer.bind(this));
},
clearTimer(){
cancelAnimationFrame(this.timer);
}
}
}
//按下启动定时
document.onkeydown = function (ev) {
let keyCode = ev.keyCode;
if(!ifDown[keyCode]) return;
ifDown[keyCode].bool || ifDown[keyCode].setTimer();
ifDown[keyCode].bool = true;
};
//抬起清除定时
document.onkeyup = function (ev) {
let keyCode = ev.keyCode;
if(!ifDown[keyCode]) return;
ifDown[keyCode].clearTimer();
ifDown[keyCode].bool = false;
}
</script>
</body>
</html>
23. 正则表达式
23.1 有什么用
不用正则时,一般用 !isNaN(121)=true 来提取数字
/*
正则表达式
对象
配合一些api来验证字符串
*/
let a="456阿飞789朱雀12"; //["456","789,"12"]
let b="454sjjdsiaodao5454";
let c="sds45sd45s21a";
console.log(fn(a));
console.log(fn(b));
console.log(fn(c));
console.log("*************************");
console.log(zz(a));
console.log(zz(b));
console.log(zz(c));
function zz(str) {
return str.match(/\d+/g);
}
function fn(str) {
let len = str.length;
let s ="";
let arr = [];
for(let i=0;i<len;i++){
let n=str.charAt(i);
if(!isNaN(n)){ //数字字符不是NaN,其他字符是NaN
//console.log(n);
s+=n;
}else{ //NaN
s && arr.push(s);
s="";
}
}
s && arr.push(s);
return arr;
}
23.2 正则表达式
创建正则表达式对象的两种方法
- let a = /abc/
- let b = new RegExp("abc")
验证正则的方法
- a.test(str) 返回 true or false
/*
正则表达式对象 两种创建方式
1. 双斜杠包括的字符
2. new RegExp("")
*/
let a = /abc/;
console.log(typeof a); //object
let b = new RegExp("abc"); //和第一种创建的效果一样
/*api1
test()
正则.test(字符串)
匹配成功返回true,否则返回false
*/
let a = /abc/; //匹配完整连续的abc字符串
console.log(a.test("阿飞abc朱雀"));;
/*
/ /不能传变量
*/
let s = "abc";
//let a=/s/; //这种定义方式,是没有办法根据变量来制定正则的
let a = new RegExp(s); //可以用变量
console.log(a.test("阿飞abc朱雀"));
23.3 转移符号\的用法
字符串中实现转义 "\\" 打印 "\"
/*
\转义符号,默认在字符串中的\有特殊意义,不能单独出现
*/
console.log("阿飞\"love\"朱雀\n123456\t789021");
//转义符号将有特殊意义的字符变成没有特殊意义
let str = "/\\";
let a=/\/\\/; //用转义字符"\"转义"/"和"\"
console.log(a.test(str));
/*
转义符号配合一些字母使用,有非常独特的意思
\s 各种空格, \t \n \r " "
\S 非空格,\s的补集
\d 数字
\D \d的补集
\w 数字、字母、下划线 一般匹配用户名的
\W
\b 连词符 起始 结束 (空格 以及 (除了\w之外) 所有内容都是独立部分)
\B
*/
let a = /\s/;
let s = " ";
let a=/\d\d/; //连续两个数字
let s="fffff79pppp";
let a = /\w/;
let s = "abc";
/* 算作"afei"独立的字符
"I am afei-1"
"I am afei阿飞"
"I am afei.abc"
\b只能用于匹配英文,中文本身就不独立,不能使用\b独立匹配
*/
let a = /\bafei\b/; //要匹配独立的部分
let s = "I am afei.abc"; //可以 "afeihui"就不行
console.log(a.test(s));
23.4 修饰符 i m g
验证正则的方法 match
- str.match(a) 返回所有匹配正则的元素组成的数组,(a是加了g的全局匹配)
/*
修饰符(写在//后面
i 不区分大小写
g 全局匹配
m 换行匹配
*/
let a = /g/i;
let s = "G";
console.log(a.test(s));
/*
.match()
字符串.match(正则)
寻找匹配的内容,拿到并组成一个数组返回,否则返回null
*/
let a = /xx/ig;
let s = "XxgfxxhxXx"; //xXx只能识别前两个
console.log(s.match(a)); //加了g后是纯粹的数组,没有别的属性
23.5 量词
/*
量词 { }
{n} n个
{n,m} n~m包含n也包含m
{n,} n~无穷大 包含n
默认按多的取(贪婪模式)
量词后面加问号"?"就成了(惰性模式)
几个特殊量词有专属的符号代替
{1,} + 至少一个
{0,} * 至少0个
{0,1} ? 要么有要么没有
*/
let a = /\d\d\d\d\d\d\d\d\d\d\d/g;
let s = "阿飞18860900316阿飞";
let a = /飞\d{11}/g; //{11}只表示\d重复11次
let s = "阿飞18860900316阿飞15357875321";
let a = /\d{2,4}?/g; // 惰性匹配,所以只匹配2个的
let s = "1-23-234-456阿飞18860900316阿飞15357875321";
// ["23", "23", "45", "18", "86", "09", "00", "31", "15", "35", "78", "75", "32"]
let a = /\d{2,}/g; //至少2个
let s = "1-23-234-456阿飞18860900316阿飞15357875321";
// ["23", "234", "456", "18860900316", "15357875321"]
//let a = /\d+/g; //最少一个取
//let a = /\d+?/g; //匹配到后,一个个取
//let a = /\d*?/g; //返回的全是空 相当于 //g
let a = /\d??/g; //全是空
let s = "gh777scsf45dsdsd454s35";
console.log(s.match(a));
23.6 子项()
加了括号的成为子项,使用全局g,则不打印子项
获取第一个子项 s.match(a)[1]
匹配失败,返回null
/*
子项 ( )
*/
let a = /(ab)+/; // 不加括号,只能匹配abbbb
let s = "abababab"; // ["abababab", "ab", index: 0, input: "abababab", groups: undefined]
let a = /gg(ab)+f(f)/; //加了括号的子项也会打印出来,使用全局g,则不打印子项
let s = "ababggababffababa";
//不加g,打印子项["ggababff", "ab", "f", index: 4, input: "ababggababffababa", groups: undefined]
//利用子项,只获取子项中的号码
let a = /阿飞:(\d{11})/;
let s = "阿飞:12121212321,朱雀:32321232123";
console.log(s.match(a),s.match(a)[1]);
// ["阿飞:12121212321", "12121212321", index: 0, input: "阿飞:12121212321,朱雀:32321232123", groups: undefined] "12121212321"
23.7 一个[]字符集只匹配一个字符
/*
| 或者
[] 字符集,一个字符集只匹配一个字符
[a-z] 字符区间("-"在"[]"内有了特殊意义)
[abc] 或者的意思
[^abc] 放在正则字符的首位,表示除了这些,(不放在首位表示一个单纯的字符)
[{}?*.+()] 这些原来有特殊意义的字符放在[]内没有了特殊意义,就是单纯的字符
[a-z]
[A-Z]所有的字母
*/
let a = /abc|edf/g; //或者匹配
let s = "edfabcedfabc";
let a = /(阿飞|朱雀)老师/g; //用子级匹配,加外面公用的
let s = "朱雀老师美,阿飞老师帅";
let a = /1|2|3|4|5|6|7/g; //1或者7中的任何一个
let a = /[1-7]{5}/g; //区间,代表1到7之间任何一个连续5个
//ascii码的匹配,注意要有前后顺序
let a = /[2-B]/g;
let s = "23456789:;C<=>?@AB";
//unicode字符编码也能匹配
let a = /[阿-飞]/g; //意义不大
let s = "阿飞老师";
let a = /[abc0-9]/g; //a或b或c,0到9
let s = "2345abc";
//匹配所有的数字和字母
let a = /[a-zA-Z0-9]/g;
let s = "2345abcAfejnfjGHjfbj";
let a = /[^abc]/g; //除了,取反只能放在首位
let s = "2345abcAfejnfjGHjfbj";
let a = /[{}?*./+()[\]\-]/g; //字符集内的字符失去了特殊意义
let s = "2345abcAfejnfjGHjfbj";
console.log(s.match(a));
23.8 起止字符
/*
起止字符
^ 起始位置
$ 结束位置
*/
let a = /^abc$/; //只能匹配"abc",空格都不可以有
//let s = "gabcgg"; //必须是a起始的字符串才能匹配
let s = "gabcgg";
console.log(s.match(a));
//
console.log("ddabcdd".match(/(a|^)bc/)); // abc a是子项
console.log("bcjfjfjfjfj".match(/(a|^)bc/)); // bc 子项为""
23.9 .字符
/*
. 匹配任意字符 除了换行等之外 \n \r
[.]的.是单纯的匹配字符.
*/
let a = /./g;
let s = ".123\r46\n5";
console.log(s.match(a));
//匹配所有的字符
/[\s\S]/
/[\w\W]/
23.10 应用案例
/*
/a/
new RegExp()
\s \S \w \W \d \D \b \B
修饰词 igm
量词{} *+? 惰性?取短的
子项()
字符集[]
| ^ $ .
*/
let reg={
//qq:5~10,只能是数字,第一位不是0
qq: /^[1-9]\d{4,9}$/,
//用户名:6~18,数字字母_,必须要字母开头
user:/^[a-z]\w{5,17}$/i,
//密码:6~18,数字字母_所有符号
pwd:/^[\w<>,.?/\-+=*@#$%^&()[\]`~|\\{}<>]{6,18}$/,
//手机号:
tel:/^1[3-9]\d{9}$/,
//邮箱
mail:/^[a-z1-9_]\w{0,17}@[0-9a-z]{2,}(\.[a-z]{2,4}){1,2}$/i,
//身份证
IDCard:/^[1-9]\d{5}(18|19|20)\d{2}(0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])|(0[469]|11)(0[1-9]|[12][0-9]|30)|(02(0[1-9]|[12][0-9]))\d{3}[0-9x]$/i,
}
// let a = reg.qq;
let b = reg.mail;
// let s = "3045282682";
// console.log(a.test(s));
console.log(b.test("1886@163.com"));
// let a = reg.IDCard;
// console.log(a.test("341221199411178765"));
//大月
//31天
/*
/(0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])/
//30天
/(0[469]|11)(0[1-9]|[12][0-9]|30)/
//2月
/(02(0[1-9]|[12][0-9]))/
//一起
/(0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])|(0[469]|11)(0[1-9]|[12][0-9]|30)|(02(0[1-9]|[12][0-9]))/
/((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01])|(0[469]|11)(0[1-9]|[12][0-9]|30)|(02(0[1-9]|[12][0-9])))/
*/
23.11 捕获组
捕获的是子项 RegExp.$1 最近的一次正则结果中的子项
捕获用 \n 表示,代表一个子项
let a = /a(b)(c)/;
let s = "abc";
console.log(a.test(s));
let a = /(阿飞|朱雀)老师/;
let s = "abc阿飞老师";
let s1 = "abc朱雀老师";
a.test(s);
s1.match(a);
console.log(RegExp.$1); //离它最近一次正则结果的子项1 朱雀
console.log(RegExp.$9); //最多存9个子项 没有就是 空
//捕获组,1表示重复第1个子项,没有加g,所以第一次匹配到后就结束匹配
let a = /(\d)\1/; //捕获组,重复子项 aa bb
let a = /(\d\d)\1/; //捕获组,重复子项 abab
let a = /(\d(\d))\1\2/; //捕获组,重复子项 ababb
let a = /(\d\d)\1{9}/; //捕获组,可以用量词 abab*n
let a = /(\d(\d))\2\1/; //捕获组,重复子项 abbab
let s = "797994545545";
console.log(s.match(a));
23.12 案例 表单验证
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
<style>
body{font-family: "Microsoft YaHei",serif;}
body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
ol,ul,li{margin:0;padding:0;list-style:none;}
img{border:none;}
#wrap{
position: relative;
width:430px;
height:550px;
margin:50px auto 0;
background-color: #00baff;
}
#wrap .title{
height:40px;
line-height: 40px;
background-color: #008ccf;
color:white;
font-size: 24px;
text-align: center;
font-weight: bold;
}
#wrap input{
display: inline-block;
width:250px;
height:40px;
padding-left: 20px;
margin-left: 80px;
margin-top:20px;
}
#wrap input.error{
border: 2px solid red;
}
#wrap input.ok{
border:2px solid #479552;
}
#wrap img{
display: none;
width:30px;
height:30px;
vertical-align: middle;
}
#wrap input[type=submit]{
width:270px;
padding:0;
background-color: #008ccf;
outline-style: none;
color:white;
font-weight: bold;
cursor:pointer;
}
#wrap label{
overflow: hidden;
display: block;
height:0;
margin-left: 80px;
color:red;
font-size: 12px;
}
#alert{
position: absolute;
left: 0;
right:0;
top:0;
bottom:100px;
visibility: hidden;
width:150px;
height:40px;
margin: auto;
background-color: black;
color:white;
text-align: center;
line-height: 40px;
opacity: 0;
transition: bottom .4s,opacity .5s ;
}
#alert.on{
visibility:visible;
bottom: 0;
opacity: 1;
}
</style>
</head>
<body>
<div id="wrap">
<p class="title">注册</p>
<form action="" method="" id="form">
<input type="text" name="name" id="name" placeholder="请输入您的用户名">
<img src="img/yes.png">
<label for="name">错误:用户名以字母开头,长度为6~16位</label>
<input type="password" name="pwd" id="pwd" placeholder="请输入您的密码">
<img src="img/yes.png">
<label for="name">错误:注意密码长度为6~18位</label>
<input type="password" name="repwd" id="repwd" placeholder="请再次输入您的密码">
<img src="img/yes.png">
<label for="name">错误:两次密码输入不一致</label>
<input type="text" name="phonenumb" id="phonenumb" placeholder="请输入您的手机号">
<img src="img/yes.png">
<label for="name">错误:手机号格式不正确</label>
<input type="text" name="qq" id="qq" placeholder="请输入您的QQ号">
<img src="img/yes.png">
<label for="name">错误:QQ号码格式不正确</label>
<input type="text" name="mail" id="mail" placeholder="请输入您的邮箱">
<img src="img/yes.png">
<label for="name">错误:邮箱格式不对,请重新输入</label>
<input type="submit" value="提交" id="submit">
<div id="alert">请先输入密码!</div>
</form>
</div>
<script>
(function () {
let aLabel = document.querySelectorAll("#wrap label"),
aImg = document.querySelectorAll("#wrap img"),
oName = document.getElementById("name"),
oPwd = document.getElementById("pwd"),
oRepwd = document.getElementById("repwd"),
oPnumb = document.getElementById("phonenumb"),
oQQ = document.getElementById("qq"),
oMail = document.getElementById("mail"),
alert = document.getElementById("alert")
;
//验证规则
let reg={
//用户名
name:/^[a-z]\w{5,15}$/i,
//密码
pwd:/^[\w~`!@#$%^&*()\-+=[\]{}'";:,.<>/?\\]{6,18}$/,
//手机号
tel:/^1[3-9]\d{9}$/,
//qq
qq:/^[1-9]\d{4,9}$/,
//邮箱
mail:/^[a-z1-9_]\w{0,17}@[0-9a-z]{2,}(\.[a-z]{2,6}){1,2}$/i
};
let isCheck=[];
//定义添加验证函数
function addCheckEvent(ele,reg,index) {
//输入时,取消对勾
ele.addEventListener("focus",function () {
aImg[index].style.display = "none";
})
//离开时验证
ele.addEventListener("blur",function () {
if(!ele.value){
ele.className="";
ele.className="";
aImg[index].style.display = "none"; //不显示对勾
aLabel[index].style.height = 0+'px'; //错误不提示
return;
}; //未填写则返回
//验证成功
if(reg.test(ele.value)){
ele.className="ok"; //绿框
isCheck[index]=true; //表示验证过
aImg[index].style.display = "inline-block"; //对勾
aLabel[index].style.height = 0+'px'; //错误不提示
}else{
ele.className="error"; //红框
isCheck[index]=false; //未验证通过
aImg[index].style.display = "none"; //不显示对勾
aLabel[index].style.height = 16+'px'; //提示错误
ele.focus(); //锁定焦点
}
});
}
//1. 验证用户名
addCheckEvent(oName,reg.name,0);
//2.验证密码
addCheckEvent(oPwd,reg.pwd,1);
//3.二次密码focus
oRepwd.addEventListener("focus",function () {
//先取消对勾
//aImg[2].style.display = "none";
//判断第一次密码输入状态
if(!oPwd.value){ //密码未输入
setTimeout(function () {
alert.classList.add("on"); //动画提示
oPwd.focus();
});
setTimeout(function () {
alert.classList.remove("on"); //定时消失
},2000);
}
})
//二次密码验证blur
oRepwd.addEventListener("blur",function () {
if(!oRepwd.value){
oRepwd.className="";
aImg[2].style.display = "none"; //对勾
aLabel[2].style.height = 0+'px'; //错误不提示
return;
}; //未填写则返回
if(isCheck[1]){ //第一次密码已经验证
if(oRepwd.value === oPwd.value){ //密码一样
oRepwd.className="ok"; //绿框
isCheck[2]=true; //表示验证过
aImg[2].style.display = "inline-block"; //对勾
aLabel[2].style.height = 0+'px'; //错误不提示
}else{ //不通过
oRepwd.className="error"; //绿框
isCheck[2]=false; //表示验证过
aImg[2].style.display = "none"; //对勾
aLabel[2].style.height = 16+'px'; //错误不提示
oPwd.focus(); //锁定第一次输入密码
}
}
})
//4.验证手机号
addCheckEvent(oPnumb,reg.tel,3);
//5.验证QQ号
addCheckEvent(oQQ,reg.qq,4);
//6.验证邮箱
addCheckEvent(oMail,reg.mail,5);
})();
</script>
</body>
</html>
23.13 正向断言(?=a)
/*
断言,JS只有正向断言,放在后面,括号不算子项
(?=a) 格式限定后面紧接着必须是a,但不希望匹配结果中有a
(?!a) 格式限定后面紧接着不能是a
*/
// let r = /(阿飞|朱雀)老师,\1老师/;
// let s = "阿飞老师,阿飞老师";
let r = /Window(?=XP)/; //希望格式是WindowXP,但不希望结果中有XP,所有用? 这个()不是子项
let s = "WindowXPx";
let r = /Window(?!XP)/; //不希望格式是Window后接着XP,?! 这个()不是子项
let s = "Window111";
console.log(s.match(r));
console.log(RegExp.$1);
23.14 replace
/*
replace
str.replace(正则,字符串|函数);
替换匹配到的内容变成第二个参数的内容
(如果是字符串直接替换,如果是函数,替换返回值)
*/
let reg = /(阿飞|风屿|海文)(老师|先生|大大)/g;
let str = "阿飞老师是个纯粹的大猪蹄,风屿先生真自恋,海文大大脾气不好";
let newStr = str.replace(reg,"小浪");
let newStr = str.replace(reg,(...rest)=>{
//经过了很多运算之后,得到用来替换的字符串
console.log(rest);
return '小浪';
});
let newStr = str.replace(reg,(a,b,c)=>{
//经过了很多运算之后,得到用来替换的字符串
console.log(a,b,c); //a表示正则形参,b表示第一个子项,c表示第二个子项
return '小浪'+c+c.slice(1);
});
console.log(newStr);
23.15 脏字过滤器
<div id="wrap">
<input type="text">
<button class="btn">发送</button>
<ul></ul>
</div>
<script>
let Btn = document.getElementsByClassName("btn")[0],
Input = document.getElementsByTagName("input")[0],
oU = document.getElementsByTagName("ul")[0]
;
Btn.onclick = function () {
let str = Input.value;
if(str === "")return;
let reg=/傻[,./<>\-+=\d]*逼|草|操|cao|艹|你[爸妈]|王八蛋|/g;
str = str.replace(reg,($0)=>{
let s="";
[...$0].forEach(()=>s+="□")
return s;
})
let oLi = document.createElement("li");
oLi.innerText = str;
oU.appendChild(oLi);
Input.value="";
}
</script>
24. cookie
24.1 cookie
/*
适合小数据的存储,字符串缓存,存在本地的
1.不同的浏览器存放的cookie位置不一样,也是不能通用的
2.cookie的存储是以域名形式进行区分的
3.cookie的数据可以设置名字的
4.一个域名下存放的cookie的个数是有限制的,不同的浏览器存放的个数不一样
5.每个cookie存放的内容大小也是有限制的,不同的浏览器存放大小不一样
本地文件不支持cookie,火狐浏览器支持,通过Webstorm打开支持
*/
/*
如果不给cookie设置过期时间,那么浏览器关闭之后,cookie就清除了
在存储本地cookie肯定是需要设置过期时间的
expires 一个日期对象转换成的字符串,默认是UTC时间
*/
//每条cookie都需要单独设置,不支持一次赋值设置多个cookie
document.cookie = "user=阿飞;pwd=123"; 没用的
let date = new Date(new Date().getTime()-7*24*3600*1000);
document.cookie = "goudan=阿飞;expires="+date.toUTCString(); //date转成UTC时间进行赋值
document.cookie = "pwd=123";
//获取全部cookie
console.log( document.cookie );
24.2 封装cookie的增删改查API
let Cookie ={
//设置,修改
set(mJson,day) {
//设置过期时间,不设置day默认undefined,计算时 = NaN,此时设置的cookie关闭浏览器释放
let date = new Date(new Date().getTime()+day*24*3600*1000).toUTCString();
Object.entries(mJson).forEach(([key,value])=>{
document.cookie = `${key}=${value};expires=${date}`;
})
},
//获取
get(key) {
//不传值返回全部cookie构建的对象
if(!key){
let json=document.cookie;
let obj={};
while(json){
let reg=/(^|\s)(\w+)=([^;]+)(;|$)/;
let arr = json.match(reg);
json = json.split(arr[0])[1].toString();
obj[RegExp.$2]=RegExp.$3;
}
return obj;
}else{
let str = document.cookie;
// /(^|\s)aaa=([^;]+)(;|$)/
let reg = new RegExp("(^|\\s)"+key+"=([^;]+)(;|$)");
if(reg.test(str)){
return RegExp.$2;
}else{
return undefined; //匹配不成功返回undefined
}
}
},
//删除
remove(key) {
Cookie.set({
[key]:"" //清空
},-1);
}
};
Cookie.set({
a:'阿飞',
b:123,
goudan:"afei"
},7); //7天
//测试get
console.log(Cookie.get("goudan"));
//删除cookie
Cookie.remove("b");
24.3 ES6的Object的API
//ES6写法 ,属性名的变量写法
let a = "name";
let obj= {
[a]:"阿飞" // 这里a加【】代指变量 “name”
};
console.log(obj);
let afei= {
name :"阿飞",
age:18,
sex:0
};
console.log(Object.keys(afei)); //提取对象所有属性名,返回数组
console.log(Object.values(afei)); //提取对象所有值,返回数组
console.log(Object.entries(afei)); //提取对象的键值,返回二位数组
24.4 案例,cookie记录访问时间
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
</head>
<body>
<div id="wrap">
欢迎访问本站!您上次访问本站的时间为:2018-11-10,20:50:20
</div>
<script>
//封装的cookie
let Cookie ={
set(mJson,day) {
let date = new Date(new Date().getTime()+day*24*3600*1000).toUTCString();
Object.entries(mJson).forEach(([key,value])=>{
document.cookie = `${key}=${value};expires=${date}`;
})
},
get(key) {
//不传值返回全部cookie构建的对象
if(!key){
let json=document.cookie;
let obj={};
while(json){
let reg=/(^|\s)(\w+)=([^;]+)(;|$)/;
let arr = json.match(reg);
json = json.split(arr[0])[1].toString();
obj[RegExp.$2]=RegExp.$3;
}
return obj;
}else{
let str = document.cookie;
let reg = new RegExp("(^|\\s)"+key+"=([^;]+)(;|$)");
if(reg.test(str)){
return RegExp.$2;
}else{
return undefined; //匹配不成功返回undefined
}
}
},
remove(key) {
Cookie.set({
[key]:"" //清空
},-1);
}
};
(function () {
//lastTime存储上一次的时间
let oW = document.getElementById("wrap");
let lastTime = Cookie.get("lastTime");
let date = new Date().getTime();
function showText(lastTime) {
if(lastTime){
let date = new Date(lastTime-0);
return `欢迎访问本站!您上次访问本站的时间为:${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()},${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
}else{
return "您是第一次访问本站哟!";
}
}
oW.innerText = showText(lastTime) ;
Cookie.set({
lastTime:date
},9999);
})();
</script>
</body>
</html>
25. ajax
/*
Ajax
异步的javascript和xml
同步
一心一意
异步
三心二意
功能
无刷新页面的情况下,实现与后台的数据交互,同时在页面进行更新
跨域
默认不允许跨域请求资源
安全问题
前端能不能请求到数据,是后端说了算
*/
//创建 ajax对象
const ajax = new XMLHttpRequest();
//监听状态的改变
/*
0~4
0 初始化状态 ajax已经被创建
1 open()方法已经调用
2 send()方法已调用
3 所有的响应已经收到
4 http响应已经完全接收
*/
ajax.onreadystatechange = function(){
if(ajax.readyState === 4 & ajax.status === 200){
//前端 就能够接收到数据了
//console.log(ajax.response);
//把对应的数据 转换成对应的数据类型
console.log(JSON.parse(ajax.response));
}
}
//路径不能出现中文
//本地测试
//ajax.open('get','./data.php',true); //通过什么样的方式,向什么样的后端服务器 发送什么的请求(true表示异步)
//ajax.send(); //执行请求命令
//真实服务器, 数据先行, 数据驱动视图
ajax.open('get','http://www.tanzhouweb.com/48/data.php',true);
ajax.send();
25.1 封装一个ajax
//调用方式
ajax({
url:"www.baidu.com",
method:"get",
data:{
name:"peter",
age:18
},
success:function(msg){
},
error:function(err){
}
})
function ajax(json){
var method = json.method.toUpperCase() || "GET";
var data = json.data || {};
var xhr = new XMLHttpRequest();
switch(method){
case 'GET':
xhr.open(method,json.url+"?"+jsonUrl(json.data),true);
xhr.send(null);
break;
case 'POST':
xhr.open(method,json.url,true);
//设置post请求头
xhr.setRequestHeader('content-type','application/x-www-form-urlencoded');
xhr.send(jsonUrl(json.data));
break;
}
}
xhr.onreadystatechange=function(){
if(xhr.readyState === 4){
if(xhr.status>=200 || xhr.status<=300 || xhr.status === 304){
json.success(xhr.responseText); //responseText 才是服务器返回数据
}else{
json.error(xhr.status);
}
}
}
function jsonUrl(data){
var arr=[];
for(var key in data){
arr.push(key+'='+data[key]);
}
return arr.join("&");
}
25.2 jsonp跨域解决方案
/*
jsonp 一种跨域问题的解决方案
*/
function getData(data) {
console.log(data);
}
//核心本质 就是后端服务器 返回一个函数调用 getData('js')
createJsonp();
function createJsonp() {
const s = document.createElement('script');
// s.src='http://www.tanzhouweb.com/48/jsonp.php?callback=getData';
s.src='http://localhost/data.php?callback=getData';
document.body.appendChild(s);
}
25.3 CORS服务器允许跨域
设置响应头,res.writeHeader(200,{'Access-Control-Allow-Origin':'*'})
/*
cmd检测nodejs的安装
node -v
npm -v
*/
//通过 node的原生模块 http 搭建服务器 提供数据接口
const http = require('http');
http.createServer(function () {
res.writeHeader(200,{
'Access-Access-Control-Allow-Origin':'*'
})
res.end("hi~这里是node服务器返回的数据");
}).listen(6060);
express
const express = require('express');
const app = express();
//在中间件设置允许前后端跨域
app.use((req,res,next)=>{
res.set('Access-Control-Allow-Origin','*');
next();
})
26. 面向对象
26.1 封装一个对象函数
/*
OOP
封装 继承 多态
*/
var afei = teacher(1111,'阿飞',18);
var zhuque = teacher(2222,'朱雀',20);
//封装一个对象函数
function teacher(id,name,age) {
var o = {};
o.id = id;
o.name=name;
o.age=age;
o.showID = function () { //堆内存占用了多个
alert(this.id);
}
return o;
}
26.2 new
/*
new Date()
new Image()
new XMLHttpRequest()
new RegExp()
new Array()
new 关键词 后面紧跟一个 函数
通过new执行函数对函数的影响:
①:函数内部生成一个全新的对象,函数的this指向这个对象
②:函数默认返回上述对象
*/
//fn(); //函数自执行;非严格模式指向window,严格模式指向undefined
function fn() {
// console.log(this); //new的this指向全新的对象,只有this能指向这个对象
this.x = 10;
}
new fn(); //先初始化一个空{},然后将{}的proto即隐式原型指向fn的prototype,然后执行了fn.call({})将this作用域交予{},完成实例化
console.log(new fn()); // fn {x: 10}
var afei = new Teacher(1111,'阿飞',18);
var zhuque = new Teacher(2222,'朱雀',20);
console.log(afei.showID === zhuque.showID); //false 每个对象都占用一个堆内存存放函数
//构造函数 / 类
function Teacher(id,name,age) {
this.id = id;
this.name=name;
this.age=age;
this.showID = function () { //堆内存占用了多个
alert(this.id);
}
}
26.3 原型
/*
原型
prototype 是一个对象数据类型
它是构造函数的一个属性
每一个实例都共享这个原型的属性
*/
//构造函数
function Teacher(id,name,age) {
this.id = id;
this.name=name;
this.age=age;
}
// console.dir(Teacher);
Teacher.prototype.x = 10; //原型也是对象
Teacher.prototype.showID=function () { //所有实例公用一个showID属性
alert(this.id);
}
var afei = new Teacher(1111,'阿飞',18); // 实例
var zhuque = new Teacher(2222,'朱雀',20);
console.log(afei);
console.log(afei.x,zhuque.x,afei.__proto__===zhuque.__proto__);
console.log(afei.__proto__ === Teacher.prototype); //实例的__proto__ 全等于 构造函数的 prototype属性
// 构造函数的原型是对象数据类型 {x: 10, showID: ƒ, constructor: ƒ}
//afei.showID();
console.log(afei.showID === zhuque.showID); // true 共享一个堆内存
26.4 原型链
/*
当访问对象的属性时,先从自身找,自身没有,才进入原型中找;原型找不到去原型的原型里面找,直到Object.prototype 为止,因为Object没有__proto__属性,原型链到此结束
实例没有 prototype 属性;Object没有__proto__属性
构造函数的隐式原型是Function: A.__proto__ === Function.prototype
构造函数的原型是其实例的隐式原型:A.prototype === new A().__proto__
Function比较特殊 Function.__proto__.__proto__ === Object.prototype
goudan.__proto__ = Fn.prototype
Fn.prototype.__proto__ = Object.prototype
*/
function Fn() {
this.x=10; //实例的x属性
}
Fn.prototype.x=20; //原型的x属性
console.log(Fn.prototype.constructor === Fn); //true 构造属性
var goudan = new Fn(); // 实例
console.log(goudan.x);
console.log(goudan.__proto__ === Fn.prototype); //true Fn的原型
console.log(Fn.prototype);
console.log(Fn.prototype.__proto__ === Object.prototype); //true Fn.prototype 是 Object的原型
// 构造函数的原型 是 Object 的实例化对象
//Object不存在 .__proto__ 属性,
/*
私有属性写在构造函数里面
公共属性写在原型上
先有原型,再有实例
*/
function Teacher(n,a,i) {
this.name = n;
this.age = a;
this.id = i;
}
/*
Teacher.prototype.showID=function () {
alert(this.id);
}
*/
Teacher.prototype = { //重写了 prototype属性,注意保留constructor属性
constructor:Teacher,
showID:function () {
alert(this.id);
},
showName:function () {
alert(this.name);
},
showAge:function () {
alert(this.age);
}
}
var afei = new Teacher("阿飞",18,1111);
afei.showID();
/*
原型链继承
构造函数的原型 = 一个函数的实例化对象 实现继承该函数的原型链
*/
function C() {}
C.prototype.x = 10;
function B() {}
B.prototype = new C(); // B的原型指向C
function A() {}
A.prototype = new B();
Object.prototype.x = 40; //顶层链
var a = new A();
console.log(a.x); // 10 原型链查找,就近原则
/*
得到一个实例的构造函数
*/
function A() {}
var a = new A();
console.log(a.constructor); // A(){} a没有constructor,实际上是原型 A.prototype.constructor
//注意。原型链可能导致不确定
function B() {}
B.prototype = {}; // 这里将原型置为{},上一级原型不存在constructor,
var b = new B();
console.log(b.constructor); // Object() { [native code] } 再向上级找,找到Object原型的构造函数
//所有大括号构建对象都相当于new一个Object对象
// let x={}; // 原型 = Object.prototype
let x = new Object();
26.5 ES5的继承
先继承私有属性,然后是原型
function A(n,a) {
this.name = n;
this.age = a;
}
A.prototype.getName = function () {
return this.name;
}
//ES5实现继承(组合继承)
function B(n,a,i) {
A.call(this,n,a); //1.继承了A的私有属性
this.id = i; //新增的私有属性
}
//2.再继承A的原型,这里只继承原型,所以使用中间构造函数,如果用new A(),原型会有A的属性
function Fn(){};
Fn.prototype = A.prototype;
B.prototype = new Fn(); //这里只传递了原型,但原型缺少构造函数
// 新增原型
B.prototype.constructor = B; // 补上构造函数
B.prototype.xx=10; // 新增原型
var afei = new A('阿飞',18);
var xinai = new B('心艾',20,5555);
console.log(afei);
console.log(xinai);
26.6 instanceof实现对象的深拷贝
/*
instanceof运算符用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置
对象 instanceof 构造函数(一般是顶层构造函数Object,Array,Function)
*/
function deepclone(obj) {
var o = obj instanceof Array?[]:{};
for(var key in obj){
if(typeof obj[key] === 'object'){
o[key] = deepclone(obj[key]);
}else{
o[key] = obj[key];
}
}
return o;
}
var a = {
a:20,
b:50,
k:{ //不支持复杂类型
aa:1,
cc:{
h:2333
}
}
}
var b = deepclone(a); //深拷贝后,引用值类型不会被影响
b.c = 40;
b.k.bb = 2;
b.k.cc.i=120;
console.log(a);
console.log(b);
26.7 JSON的API实现对象拷贝
/*
JSON只会传数字和字符串,不能存 函数 等其他类型
*/
var a = {
a:20,
b:50,
k:{
aa:1,
cc:{
h:2333
}
},
f:function () { //JSON 不支持函数类型,所以过滤掉
console.log(1)
}
}
console.log(JSON.stringify(a)); //没有函数 f
var b = JSON.parse(JSON.stringify(a)); //这样实现的b也和a不一样了
b.z=30;
b.k.o=80;
console.log(b);
console.log(a);
26.8 对象案例,选项卡
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
<style>
body{font-family: "Microsoft YaHei",serif;}
body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
ol,ul,li{margin:0;padding:0;list-style:none;}
img{border:none;}
#wrap,#wrap1{
position: relative;
width:300px;
height:300px;
border:1px solid pink;
margin:50px auto;
}
#wrap .con,#wrap1 .con{
position: absolute;
top:30px;
left:0;
width:300px;
height: 270px;
}
#wrap .con ul,#wrap1 .con ul{
width:100%;
height:100%;
}
#wrap .con li,#wrap1 .con li{
display: none;
position: absolute;
width:100%;
height:100%;
}
#wrap .con li.active,#wrap1 .con li.active{
display: block;
}
#wrap .tab,#wrap1 .tab{
position: absolute;
left:0;
top:0;
width:100%;
height:30px;
}
#wrap .tab li,#wrap1 .tab li{
float: left;
width:99px;
height:30px;
border-right:1px solid red;
background-color: #abcded;
cursor: pointer;
}
#wrap .tab li.active,#wrap1 .tab li.active{
background-color: pink;
}
</style>
</head>
<body>
<div id="wrap">
<div class="con">
<ul>
<li class="active" style="background-color: red">A内容</li>
<li style="background-color: #06aaff">B内容</li>
<li style="background-color: #f9a886">C内容</li>
</ul>
</div>
<div class="tab">
<ul>
<li class="active">A</li>
<li>B</li>
<li>C</li>
</ul>
</div>
</div>
<script>
(function () {
//对象
function Tab({conEle,tabEle,conClass='active',tabClass='active'}){
this.conEle = conEle;
this.tabEle = tabEle;
this.conClass = conClass;
this.tabClass = tabClass;
this.lenth = this.tabEle.length;
this.index = 0;
this.addClick();
}
Tab.prototype = {
constructor : Tab,
addClick:function () {
for(var i=0;i<this.lenth;i++){
(function (i) { //函数作用域形成闭包
this.tabEle[i].onclick=function () {
this.change(i);
}.bind(this);
}).call(this,i);
}
},
change:function (i) {
this.conEle[this.index].classList.remove(this.conClass);
this.tabEle[this.index].classList.remove(this.tabClass);
this.index = i;
this.conEle[this.index].classList.add(this.conClass);
this.tabEle[this.index].classList.add(this.tabClass);
}
};
//实例化
new Tab({
conEle:document.querySelectorAll("#wrap .con li"),
tabEle:document.querySelectorAll("#wrap .tab li"),
});
})();
</script>
</body>
</html>
26.9 对象继承案例,自动轮播选项卡
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
<style>
body{font-family: "Microsoft YaHei",serif;}
body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
ol,ul,li{margin:0;padding:0;list-style:none;}
img{border:none;}
#wrap2{
position:relative;
width:780px;
height:380px;
margin:50px auto 0;
user-select:none;
}
#wrap2 .img{
width:100%;
height:330px;
}
#wrap2 .img ul{
width:100%;
height:330px;
}
#wrap2 .img ul li{
position:absolute;
width:100%;
height:330px;
opacity: 0;
transition: opacity .3s;
}
#wrap2 .img ul li.active{
opacity: 1;
z-index:2;
}
#wrap2 .tab{
position:absolute;
left:0;
bottom:0;
width:100%;
height:50px;
}
#wrap2 .tab ul{
width:100%;
height:50px;
}
#wrap2 .tab ul li{
float:left;
z-index:4;
width:20%;
height:100%;
background-color: #121112;
color:#fff;
text-align:center;
line-height:50px;
cursor: pointer;
}
#wrap2 .tab ul li.active{
background-color: #303030;
color:#e9c06c;
}
</style>
</head>
<body>
<div id="wrap2">
<div class="img">
<ul>
<li class="active"><img src="img/1.jpg" alt=""></li>
<li><img src="img/2.jpg" alt=""></li>
<li><img src="img/3.jpg" alt=""></li>
<li><img src="img/4.jpg" alt=""></li>
<li><img src="img/5.jpg" alt=""></li>
</ul>
</div>
<div class="tab">
<ul>
<li class="active">开黑吗?</li>
<li>我压缩贼六</li>
<li>只要E的够快</li>
<li>队友的问号</li>
<li>就追不上我</li>
</ul>
</div>
</div>
<script>
(function () {
//对象
function Tab({conEle,tabEle,conClass='active',tabClass='active'}){
this.conEle = conEle;
this.tabEle = tabEle;
this.conClass = conClass;
this.tabClass = tabClass;
this.lenth = this.tabEle.length;
this.index = 0;
this.addClick();
}
Tab.prototype = {
constructor : Tab,
addClick:function () {
for(var i=0;i<this.lenth;i++){
(function (i) {
this.tabEle[i].onclick=function () {
this.change(i);
}.bind(this);
}).call(this,i);
}
},
change:function (i) {
if(this.index === i)return;
this.conEle[this.index].classList.remove(this.conClass);
this.tabEle[this.index].classList.remove(this.tabClass);
this.index = i;
this.conEle[this.index].classList.add(this.conClass);
this.tabEle[this.index].classList.add(this.tabClass);
}
};
function TabAuto({conEle,tabEle,conClass='active',tabClass='active',wrap}) {
Tab.call(this,{conEle,tabEle,conClass,tabClass}); //继承私有属性
this.wrap = wrap;
this.timer = null;
this.autoplay();
this.addTimer();
}
function Fn(){}
Fn.prototype = Tab.prototype;
TabAuto.prototype = new Fn(); //继承原型
TabAuto.prototype.constructor = TabAuto;
TabAuto.prototype.autoplay = function () {
this.timer = setInterval(function () {
var i = this.index;
i++;
i = i%this.lenth;
this.change(i);
}.bind(this),2000);
}
TabAuto.prototype.addTimer = function () {
this.wrap.onmouseenter = function () {
clearInterval(this.timer);
}.bind(this);
this.wrap.onmouseleave = function () {
this.autoplay();
}.bind(this);
}
//实例化
new TabAuto({
conEle:document.querySelectorAll("#wrap2 .img li"),
tabEle:document.querySelectorAll("#wrap2 .tab li"),
wrap:document.getElementById("wrap2")
});
})();
</script>
</body>
</html>
26.10 多态
function fn(x) {
if(x<10){
return '0'+x;
}else{
return ''+x;
}
}
26.11 ES6面向对象class
/*
ES5的构造函数和原型是分开的,ES6的类都定义在一个{}内
*/
function A(n,a) {
this.name = n;
this.age = a;
}
A.showName = function () { // 这里的函数是 构造函数A的属性,并不属于原型的函数
alert(this.name);
}
A.prototype.showName = function(){ //这里才是给原型的函数,A的实例化对象能调用的函数
alert(this.name)
}
/*ES6
构造函数,也就是私有属性,写在constructor里面
其他内容就是原型里面的内容
原型里面加属性(可以在外面加,A.prototype.x=10)
每个方法结束后,千万不要写 , 号
*/
class A{
constructor(n,a) {
this.name = n;
this.age = a;
}
showName(){
}
x(){
return 10;
}
}
//
A.prototype.x=10;
26.12 ES6继承extends
class A{
constructor(n,a) {
this.name = n;
this.age = a;
}
showName(){
alert(this.name);
}
showAge(){
alert(this.age);
}
x(){
return 10;
}
}
class B extends A{
constructor(n,a,id){
super(n,a); //必要的super,把父类的私有属性继承一下(传参),类似ES5的 call
this.id = id;
}
x(){
//return A.prototype.x()+10; //原型的super代表 A.ptototype
return super.x()+10;
}
}
let a = new A('阿飞',18);
let b = new B('朱雀',81,111);
console.log(a); // {name: "阿飞", age: 18}
console.log(b); // {name: "朱雀", age: 81, id: 111}
console.log(a.x()); // 10
console.log(b.x()); // 20
26.13 选项卡案例 ES6对象
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="keywords" content="关键词">
<meta name="description" content="描述">
<meta name="author" content="Danew">
<style>
body{font-family: "Microsoft YaHei",serif;}
body,dl,dd,p,h1,h2,h3,h4,h5,h6{margin:0;}
ol,ul,li{margin:0;padding:0;list-style:none;}
img{border:none;}
#wrap2{
position:relative;
width:780px;
height:380px;
margin:50px auto 0;
user-select:none;
}
#wrap2 .img{
width:100%;
height:330px;
}
#wrap2 .img ul{
width:100%;
height:330px;
}
#wrap2 .img ul li{
position:absolute;
width:100%;
height:330px;
opacity: 0;
transition: opacity .3s;
}
#wrap2 .img ul li.active{
opacity: 1;
z-index:2;
}
#wrap2 .tab{
position:absolute;
left:0;
bottom:0;
width:100%;
height:50px;
}
#wrap2 .tab ul{
width:100%;
height:50px;
}
#wrap2 .tab ul li{
float:left;
z-index:4;
width:20%;
height:100%;
background-color: #121112;
color:#fff;
text-align:center;
line-height:50px;
cursor: pointer;
}
#wrap2 .tab ul li.active{
background-color: #303030;
color:#e9c06c;
}
</style>
</head>
<body>
<div id="wrap2">
<div class="img">
<ul>
<li class="active"><img src="img/1.jpg" alt=""></li>
<li><img src="img/2.jpg" alt=""></li>
<li><img src="img/3.jpg" alt=""></li>
<li><img src="img/4.jpg" alt=""></li>
<li><img src="img/5.jpg" alt=""></li>
</ul>
</div>
<div class="tab">
<ul>
<li class="active">开黑吗?</li>
<li>我压缩贼六</li>
<li>只要E的够快</li>
<li>队友的问号</li>
<li>就追不上我</li>
</ul>
</div>
</div>
<script>
(function () {
class Tab{
constructor({conEle,tabEle})
{
this.conEle = conEle;
this.tabEle = tabEle;
this.index = 0;
this.lenth = this.tabEle.length;
this.addClick();
}
addClick(){
[...(this.tabEle)].forEach((ele,index)=>{
ele.onclick = function() {
this.change(index);
}.bind(this);
})
}
change(i){
if(this.index === i)return;
this.conEle[this.index].classList.remove('active');
this.tabEle[this.index].classList.remove('active');
this.index = i;
this.conEle[this.index].classList.add('active');
this.tabEle[this.index].classList.add('active');
}
}
class TabAuto extends Tab{
constructor({conEle,tabEle,wrap}){
super({conEle,tabEle}); // 继承父类私有属性
this.wrap = wrap;
this.timer = null;
this.autoplay();
this.addTimer();
}
autoplay() {
this.timer = setInterval(()=>{
let i = this.index;
i++;
i = i%this.lenth;
this.change(i);
},2000);
}
addTimer() {
this.wrap.onmouseenter = ()=> {
clearInterval(this.timer);
};
this.wrap.onmouseleave = ()=>{
this.autoplay();
};
}
};
//实例化
new TabAuto({
conEle:document.querySelectorAll("#wrap2 .img li"),
tabEle:document.querySelectorAll("#wrap2 .tab li"),
wrap:document.getElementById("wrap2")
});
})();
</script>
</body>
</html>
27. ES6
27.1 默认值
/*
函数的小括号,会被当成作用域
*/
let x=5;
function fn(x,y=x) {
console.log(x,y);
}
fn(1); // 1 1
27.2 for of只限于遍历iterator接口
作用是遍历拿到数组的value值
对象使用for of
遍历时,先拿到对象的成员, for (let [key,value] of Object.entries(obj))
let arr=[
'阿飞',
'风屿',
'小浪',
'海文'
];
console.log(Object.keys(arr),Object.values(arr)); // 一维数组
console.log(Object.entries(arr)); // 二维数组
let obj={
name:'afei',
age:18,
sex:'男',
marry:true
}
/*
for of只限于用于 iterator接口
*/
for (let string of arr) {
console.log(string); //拿到数组的值value
}
for (let objElement of Object.values(obj)) {
console.log(objElement);
}
for (let objElement of Object.entries(obj)) { //打印数组
console.log(objElement);
}
for (let [key,value] of Object.entries(obj)) { //结合使用适合遍历obj的键和值
console.log(key,value);
}
27.3 ...用于对象合并
- 合并后的对象是新的对象
- 合并对象时同名属性被覆盖
let x={
aa:1,
bb:2
};
let y={
bb:0,
cc:3,
dd:4
};
let z = {...x,...y}
x.aa=10;
console.log(x);
console.log(z);
27.4 symbol
Object.getOwnPropertySymbols(obj);
获取对象内部所有的symbol属性,返回一个数组
Symbol.for('a')
的名字比如a相同,就代表相同的Symbol
//独一无二的Symbol
console.log(Symbol() === Symbol()); //false
let obj = {name:'阿飞'};
let n=Symbol(); //独一
obj[n]='朱雀';
n=Symbol(); //n被赋值,只是‘朱雀’取不到了,但仍存在
obj[n]='心艾';
console.log(obj[n]); //获取的是 心艾
obj[Symbol.for('name')]='朱雀'; // obj中添加一个属性
// {name: "阿飞", Symbol(): "朱雀", Symbol(): "心艾", Symbol(name): "朱雀"}
//获取所有的Symbol
let symbolArr = Object.getOwnPropertySymbols(obj); // [Symbol(), Symbol(), Symbol(name)]
console.log(obj[symbolArr[0]]); //找到朱雀
//传值是别名
console.log(Symbol('a'),Symbol.for('a'));
//Symbol的名字相同,仍不同
console.log(Symbol('a')===Symbol('a')); //false
//Symbol.for的名字相同,就代表相同的Symbol
console.log(Symbol.for('a') === Symbol.for('a')); //true
27.5 Set
new Set(data)
data必须是能被迭代的数据
实例的add方法,可以追加数据到对象内
/*
对象
特点:没有重复值
只接收一个参数,必须能被迭代的数据,字符串,数组,NodeList,argument,Set,Net
*/
let set = new Set([1,2,3]);
let set = new Set("阿飞老师阿飞老师朱雀老师"); //默认去重
set.add('心艾'); //add的内容被 当成一条数据传入,不被拆开
set.add('心');
console.log(set); // 心艾 和 心 并不会去重
//去重
let arr=[1,2,4,5,6,1,2,4,2,3];
let s = new Set(arr);
console.log([...s]);
27.6 Map
map.set(key,value);
队列设置
/*
Map可以使用一个对象当成键名
支持各种数据类型当键使用,对象,实例,
*/
let map = new Map();
// let key = 'name';
// let value = '阿飞';
let key = {goudan:'狗蛋'}; //对象当成键
let value = 'afei';
map.set(key,value);
console.log(map);
//取值
console.log(map.get(key));
27.7 Object的toString方法
var a={m:'n'};
var b= a.toString();
console.log(b,typeof b,b.length); // [object Object] string 15
27.8 Proxy
//Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,
// 因此提供了一种机制,可以对外界的访问进行过滤和改写。
let o ={
a:1,
b:2
}
let obj = new Proxy(o,{
//拦截对象的获取
get(target,key,receive){
console.log(target); // {a: 1, b: 2}
console.log(key); // a
console.log(receive); // Proxy {a: 1, b: 2}
return target[key]; // 1
},
//拦截对象的赋值
set(target,key,value,receive){
console.log(target); //{a: 1, b: 2}
console.log(key); //a
console.log(value); //123
console.log(receive); // Proxy {a: 1, b: 2}
}
//... 针对框架开发使用
})
console.log(obj.a); //触发get
obj.a = 123; //触发set
27.9 Promise
new Promise()
返回一个promise对象
Promise.all([new Promise(),newPromise()]).then().catch()
批量执行,all传入的是数组包裹的promise对象,都成功走then回调,都失败,走catch回调,只显示失败的
Promise.race([new Promise(),newPromise()]).then().catch()
竞争执行,哪个实例先改变状态(不论resolve还是reject),那么then和catch就走哪个实例
//回调地狱->解决异步编程
setTimeout(()=>{
console.log("123")
},0)
console.log("abc")
//resolve 表示成功 reject表示失败
let x = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("200"); //成功,永远在当前环境的最后执行
console.log("我先打印,再进入resolve事件")
},0)
}).then((val)=>{ //then表示成功回调
console.log("成功回调"+val);
},(err)=>{ //第二个函数是失败回调
console.log("失败回调"+err);
})
//all 只有数组成员都成功才执行then
let p = Promise.all([
new Promise((resolve,reject)=>{
resolve('1');
}),new Promise((resolve,reject)=>{
resolve('1');
}),new Promise((resolve,reject)=>{
reject('0');
})
]).then(data=>{
console.log(data); //都成功[1,1,0]
}).catch(err=>{
console.log(err); //有一个失败,就走失败,这里只显示失败的 '0'
})
/*
Promise.race() 有竞争的意思
只要`p1`、`p2`、`p3`之中有一个实例率先改变状态,`p`的状态就跟着改变。
那个率先改变的 Promise 实例的返回值,就传递给`p`的回调函数。
*/
let p1 = Promise.race([
new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('1');
},100);
}),new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('2');
},101);
}),new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('3');
},99);
})
]).then(data=>{
console.log('resolve '+data); //只显示最快的 3,无论是 resolve还是reject
}).catch(err=>{
console.log('reject '+err);
})