js基础_ecamscript语法+DOM+BOM
一、初识javascript
- Javascript是什么
- 运行在客户端的脚本语言
- 脚本语言:不需要编译,运行过程中由Js解释器(js引擎)逐行来进行解释并执行
- Node.js可用于服务端的编程
- 高级编程语言
- js作用
- 表单动态检验(js产生的最初目的)
- 网页特效
- 服务端的开发(node.js)
- 桌面程序(Electron)
- App(Cordova)
- 控制硬件-物联网(Ruff)
- 游戏开发(cocos2d-js)
- 浏览器执行Js的方式
- 浏览器分为两部分:渲染引擎和js引擎
- 渲染引擎:用来解析Html和css,即为内核,比如:chrome浏览器的blink,老版本的webkit
- js引擎:js解释器,用来读取网页中的js代码,对其处理后运行,比如:chrome:V8,也即:执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以js语言归为脚本语言,会逐行解释执行
- 运行js分为两步
- 预解析
- js代码执行
- 运行js分为两步
- js组成
- ECMAScript(JavaScript语法)
- Javascript(网景公司)和jscript(微软公司)是ecmascript的实现和扩展
- 规定了js的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套js语法工业标准
- DOM(页面文档对象模型)
- 是w3c组织推荐的处理可扩展标记语言的标准编程接口
- 通过dom提供的接口可以对页面上的各种元素进行操作
- BOM(浏览器对象模型)
- 提供了独立于内容的、可以与浏览器窗口进行互动的对象结构,通过bom可以操作浏览器窗口。
- 其中DOM 和BOM都属于WebAPIS
- API 应用程序编程接口
- webApi是浏览器提供的一套操作浏览器功能和页面元素的API
- ECMAScript(JavaScript语法)
- 规定
- html使用双引号,js使用单引号
- 输入输出
- alert()
- console.log()
- prompt()输入
- 以上都是归属于浏览器的
- doucument.write()向页面的Body标签输入内容
二、ecmascript语法
2.1变量
-
声明:var
-
同时声明多个变量
var name_my = 'zt', age = 18, money = 20; // 效果跟以下一样 var name_my = 'zt'; var age = 18; var money = 20; var age1 = age2 = age3 = 2; //效果跟以下一样 var age1 = 2; age2 = 2; age3 = 2;
-
声明变量的特殊情况
- 只声明不赋值直接使用 undifined
- 不声明不赋值直接使用 报错
- 不声明直接赋值使用 可以
- 不声明的变量作为window对象的属性
- 可以删除,但是声明的变量不可以删除
2.2数据类型
- 总览
-
数字型数据
- 二进制 0b开头
- 八进制 0开头
- 十六进制 0x开头
- 数值中的最大值和最小值
- Number.MAX_VALUE
- Number.MIN_VALUE
- 三个特殊值
- Infinity无穷大
- -Infinity无穷小
- NaN 非数字数据
- 判断当前数据是否为非数字 isNaN(data)
- 是非数字 true
-
字符串类型
- 双引号
- 单引号
- js推荐为单引号
- 引号匹配为就近匹配
- 外双内单
- 内双外单
- 字符串换行
- \n换行
- \\斜杠
- \t tab缩进
- \b空格
- 字符串长度
- length属性
- ‘hhh’.length
- 字符串拼接
- +
-
布尔值类型
-
true参与加法运算当1 看
-
false参与加法运算当0看
-
console.log(true + 1);// 2 console.log(false + 0);// 1
-
-
undefined 类型数据
-
出现场景:声明但是没有赋值的变量直接拿来使用的时候 undefined
-
与 数值相加-> NaN
-
var num; console.log(num); num = undefined; console.log(num + 'pink');//undefinedpink console.log(num + 1);//NaN console.log(true + num);//NaN
-
-
null 类型数据
-
里面存储的是空值
-
与数值相加 等于数值
-
var num = null; console.log(num + 1);//1 console.log(num + true);//true
-
-
获取数据 数据类型
-
typeof
-
console.log(typeof null);//object
-
-
字面量
- 源代码中一个固定值的表示方法
-
数据类型的转换
-
转换为字符串类型
-
toString() 显示转换
-
String() 强制转换
-
+ 隐私转换
-
var num = 19; console.log(num.toString()) console.log(String(true)) console.log(null + '')
-
-
转换为数值类型
-
parseInt()转换为整数
console.log(parseInt('3.14'))// 3 console.log(parseInt('3.94'))// 3 不会进位 console.log(parseInt('120px'))// 120 截取 console.log(parseInt('pa120'))// NaN
-
parseFloat转换为浮点数
情况与parseInt()类似
-
Number()强制转换(int和Float都可以 但是不支持截取)
console.log(Number('1.34')) // 1.34 console.log(Number('1.34px')) // NaN
-
- * / 隐私转换
// - * / console.log('123' - 120);// 3
-
-
转换为Boolean数据类型
- Boolean()
- 代表空、否定的值都转换为false(’’ 0 NaN null undefined)
- 其他的都为true
-
2.3标识符
1. 开发人员为变量、属性、函数、参数取的名字
2. 标识符不能为关键字/保留字
2.4运算符
-
算术运算符
- 注意点
- 浮点数进行运算存在精度问题 不准确
- 避免浮点数比较
- 0.1 + 0.2 == 0.3 //false
- 注意点
-
递增/递减运算符
- a++ ++a
- a-- --a
-
比较运算符
-
== 默认会转换数据类型
console.log(18 == '18'); // true
-
=== 全等 要求数据类型也需要一致
-
-
逻辑运算
-
赋值运算符 +=
-
运算符优先级
2.5流程控制分支
-
顺序结构
-
分支结构
-
if语句
if() { } else if() { } else { }
-
switch语句
- 注意点
- 匹配关系为全等
- 注意点
-
三元表达式
条件表达式?表达式1:表达式2
-
-
循环
- for循环
- while循环
- do…while循环
-
continue
-
break
2.6命名规范
- 变量 用名词
- 函数名称用动词
- 操作符规范 操作符两侧有空格
- 单行注释规范 单行注释前面注意有一个空格
- 其他规范
- if () 括号两侧预留空格
- for () 括号两侧预留空格
2.7数组
-
创建数组
-
new方式创建数组
var var_a = new Array(2);// 创建两个空数组 var var_b = new Array(2,4);// 创建包含两个元素 2,4的数组[2,4]
-
字面量创建数组
var var_b = [];
-
-
可以存放任意的数据类型数据
-
获取数组的长度 arr.length属性获取
-
新增数组的元素
-
修改length的长度
增加的元素位置为undefined
-
修改数组索引号来追加数组元素
不要直接将数组名进行赋值,原因:数组名即为变量 直接赋值改变了变量的存储数据
es5新增数组方法
-
-
迭代(遍历方法)
-
forEach()
-
语法:
array.forEach(function(currentValue,index,arr))
-
currentValue:数组当前项的值
-
Index:数组当前项的索引
-
arr:数组对象本身
var arr = [1,2,3]; arr.forEach(function (value, index, array) { console.log(value + index + array); })
-
-
map()
- 存储键值对的方式,可以将数组转换为map对象之后再采用map遍历方法进行遍历,但是不怎推荐使用这种方式,原因是数组有自己的方式进行元素的遍历
-
filter() 筛选数组
-
语法:
arr.filter(function(currrentValue,index,arr))
-
返回一个满足条件的新数组
-
currentValue:数组当前项的值
-
Index:数组当前项的索引
-
arr:数组对象本身
-
var arr = [1,2,3,-8,-4,-5,-2,-1]; console.log(arr.filter(function (value, index, array) { var temp = value * index + 2; return temp > 0; }));
-
-
some() 查找某个元素是否存在于该数组中
-
语法
arr.some(function(currrentValue,index,arr))
-
currentValue:数组当前项的值
-
Index:数组当前项的索引
-
arr:数组对象本身
-
返回布尔值,找到第一个满足要求的元素即会返回
var arr = [1,2,3,-8,-4,-5,-2,-1]; console.log(arr.some(function (value, index, array) { var temp = value * index + 2; return temp > 0; }));
-
-
every() 判断是否所有的元素都符合要求
-
语法
arr.every(function(currrentValue,index,arr))
-
currentValue:数组当前项的值
-
Index:数组当前项的索引
-
arr:数组对象本身
-
返回布尔值,只有所有的数组元素都满足要求才返回true
-
-
-
es6扩展方法
-
find()
-
用于找出第一个符合条件的数组成员,如果没有找到返回undefined
-
用例:
let arr = [1,2,3]; console.log(arr.find(item => item < 3)); let arr2 = [{ id: 1, uname: 'zt' },{ id: 2, uname: 'zztt' } ]; console.log(arr2.find((item,index) => item.id == 2));// 其中item.id == 2为查找条件(返回查找条件)
-
-
findindex()
- 用于找出第一个符合条件的数组成员的索引,如果没有找到返回-1
- 用法与find一样
-
includes()
-
表示某个数组是否包含给定的值,返回布尔值
-
用例:
console.log([1,2,3].includes(2));// true
-
注:
-
对象的比较看的是地址,因此不容易进行查找
console.log([{ id:1},2,3].includes({ id:1}));// false
-
-
-
2.8函数
-
函数的声明
- 命名函数
function 函数名() { //函数体 }
-
匿名函数 函数表达式的形式进行声明
var 变量名 = function() { };
-
通过new Function()方式创建 不推荐使用 太麻烦
-
每个函数都是Function函数的实例对象
-
每个函数都是一个对象,因此也具有原型对象等属性对象
-
var func = new Function('参数1','参数2','函数体');
-
函数形参和实参个数匹配的问题
- 实参个数大于形参个数 根据形参个数来进行一一匹配
- 实参个数小于形参个数 多余的形参为未声明的变量 undefined 如果直接使用 可能会产生NaN的情况
- arguments使用
- 场景:当不确定实参个数的情况下,通过arguments进行获取
- js中,arguments为当前函数的内置对象,对象中存储了传递的所有实参
- arguments实际上是一个伪数组
- 具有length属性
- 按索引方式存储数据
- 不具有数组的push,pop等方法
-
return返回值
-
return 只返回一个值 即使多个值用逗号隔开,但是只返回最后一个值
-
function test() { return 1,2; } console.log(test());//2
-
如果函数内部没有写return 但是还是使用了函数的返回机制 则返回的是undefined
function test() { } console.log(test());//undefined
-
-
作用域 es6之前
-
全局作用域 scrptit标签之中
-
局部作用域
-
没有块级作用域(es6之前) {}包含,即{}定义的变量 其内定义的变量 在{}外是可以进行使用的
if () { var num = 1; } console.log(num);// 1 可以进行使用
-
-
作用域链
对于作用域嵌套级联的情况,通过链式就近查找的方式进行查找
2.9预解析
-
定义
js引擎会把js里面所有的var 还有function提升到当前作用域的最前面
-
分类
-
变量预解析(变量提升)
-
将所有变量声明提升到当前的作用域最前面 不进行赋值操作
-
场景一
console.log(num);// 结果为undefined var num = 12; //变量提升过程 var num; console.log(num); num = 12;
-
场景二
fun();// 报错 var fun = function() { console.log(1); } // 函数提升过程 var fun; fun(); fun = function() { console.log(1); }
-
-
函数预解析(函数提升)
-
将所有的函数声明提升到当前作用域的最前面 不调用函数
-
不管在函数之前调用还是在调用之后使用,都是可以使用的
function fun() { console.log(1); } fun();// 正常调用 fun();// 正常调用 function fun() { console.log(1); }
-
-
2.10对象
-
创建对象
-
字面量的形式创建
var obj = { uname: 'zt', age: 18, sayHi: function() { consoloe.log('hi~'); } }
- 使用
console.log(obj.uname); console.log(obj['uname']);
-
new Object()方式创建对象
var obj = new Object(); obj.uname = 'zt';// 追加属性的方式进行添加对象属性 obj.sayHi = function() { console.log('hi'); }
-
-
采用构造函数的方式进行创建对象(类似于java类)
-
方式
function Obj(uname,age) { this.uname = uname; this.age = age; } var obj = new Obj('name',18);
-
注意点:
- 可以作为函数一样进行考虑:arguments一样适用,参数不对应的情况
- 构造函数名(类名)首字母大写
-
-
es6,通过class关键字进行创建
-
定义新属性/修改原有的属性
- 通过点语法
- es5中方法:Object.defineProperty(obj,prop,descriptor),只有通过这个方式进行设置,以下的参数的默认值才会对对象有效
- obj:修改的对象
- prop:目标属性
- descriptor:以对象形式{}书写
- value:设置属性的值,默认为undefined
- wirtable:值是否可以重写,true|false默认为false
- enumerable:目标属性是否可以被枚举。true|false默认为false,则不允许遍历
- configurable:目标属性是否可以被删除或是否可以再次修改特效true|false,默认为false,则不允许修改特性
2.11内置对象
-
Date
-
时间戳 距离 1970年1月1日过了多少毫秒数
-
通过valueOf() getTime()获得
var date = new Date(); console.log(date.valueOf()); console.log(date.getTime());
-
简单写法 +new Date()获取
console.log(+new Date());
-
H5 新增
console.log(Date.now());
-
-
-
Array
-
检测是否为数组
-
instanceof
var arr = []; console.log(arr instanceof Array);// true
-
Array.isarray() H5新增 ie9以上版本才支持
var arr = { }; console.log(Array.isArray(arr));// false
-
-
增加/删除数组元素
-
添加
- push
var arr = []; arr.push(2,'pink');// 返回新数组长度
- unshift 数组开头添加元素
var arr = []; arr.unshift(2,'pink');// 返回新数组的长度
-
删除
- pop 返回删除的元素
- shift 返回删除的元素
-
数组排序
-
reverse() 翻转
-
sort() 排序
-
存在问题 只能对个位数进行排序
-
解决
var arr = [1,3,56,12]; arr.sort(function(a,b) { return a - b; })
-
-
-
查找某个数组元素返回索引号
- indexOf() 从头开始查找
- lastIndexOf() 从尾开始查找
-
数组转换为自符串
- toString() 默认逗号分隔
- join() 可以跟分隔符
-
-
-
字符串
-
·基本包装类型
将简单的数据类型包装成复杂的数据类型 ,即打造了三个引用类型 String Number Boolean
-
存在不可变性 开辟新的内存空间 字符串的修改不会改变原字符串
-
返回字符位置
- indexOf()
- lastIndexOf()
-
根据位置返回字符
- charAt()
- charCodeAt() 返回字符的ASCII
- str[index] H5新增
-
转换为数组
split()
-
去除左右两边空格 返回新的字符串
trim()
-
es6新增方法
-
startWith():表示参数字符串是否在原字符串的头部,返回布尔值
-
endsWith():表示参数字符串是否在原字符串的尾部,返回布尔值
-
repeat():表示将原字符串重复n次,返回一个新字符串
'x'.repeat(n);
-
-
2.12 简单类型
-
简单类型
基本数据类型/值类型,在存储的时候存储的是数据本身
string number boolean undefined null
-
复杂类型
引用类型,在存储变量的时候存储的仅仅是地址
先在栈中存放地址 十六进制表示 然后这个地址指向堆里面的数据
复杂类型传参传递的是地址
2.13堆栈
- 由操作系统自动分配释放存放函数的参数值、局部变量的值等。简单数据类型存放到栈中
- 存储复杂类型,一般由程序员分配释放,若不释放,由垃圾回收机制回收。复杂数据类型存放到堆里面。
- js没有堆栈的概念
三、DOM
3.1简介
处理可扩展标记语言的标准编程接口
3.2DOM树
-
文档
一个页面就是一个文档,DOM中使用document表示
-
元素
页面中的所有标签都是元素,DOM中使用element表示
-
节点
网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示
-
以上所有内容被DOM都视为对象
3.3获取页面元素
-
获取ID元素
-
document.getElementById() 返回element对象
-
通过console.dir() 打印返回的元素对象,更好的查看属性和方法
-
注意
-
由于html文档是自上而下进行解析的,因此包含页面元素的获取js文件需要在整个网页加载完成之后进行引入才可以获取页面元素
-
html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>practice1</title> <link href="../css/practive1.css" rel="stylesheet"/> </head> <body> <div> <a href="" id="phone">手机 电话卡</a> <a href="">电视 盒子</a> <a href="">笔记本 平板</a> <a href="">出行 穿戴</a> <script type="text/javascript" src="../js/practice1.js"></script> </div> </body> </html>
-
-
-
根据标签名获取
-
获取页面中某个元素
console.dir(document.getElementByTagName('ul'));// 返回的是当前标签名元素的伪数组
-
通过单对象父元素进行获取
console.dir(document.getElementById('id').getElementByTagName('ul'));// 返回的是当前标签名元素的伪数组
-
-
根据类名获取页面元素
console.dir(document.getElementByClassName('id'));// 返回的是当前标签名元素的伪数组
-
h5新增选择器
-
document.querySelector() 选择符合选择器的第一个元素
-
document.querySelectorAll() 选择符合选择器的所有元素
-
以上参数符合css选择器方式
-
console.log(document.querySelector('a')); console.log(document.querySelectorAll('#phone'));
-
-
获取特殊元素
-
获取Body元素
console.log(document.body);
-
获取html元素
console.log(document.documentElement);
-
-
点语法:标签对象.自定义属性 = “自定义属性值”
<div></div>
var div = document.querySelector('div');
div.index = 1;// 添加自定义属性
3.4 元素操作
-
组成
- 事件源 事件被触发的对象
- 事件类型
- 事件处理程序 通过函数赋值的方式完成
-
例子
document.querySelector('button').onclick = function () { alert('我被点击了 呜呜呜'); }
-
操作元素
-
利用DOM操作元素来改变元素里面的内容、属性
-
改变元素内容
- innerText
- 不识别html标签
- 非标准
- 去除空格和换行
- innerHTML
- 识别html标签
- W3C标准
- 保留空格和换行
- 推荐使用
- innerText
-
修改元素属性 src alt id等等
document.querySelector('button').onclick = function () { document.querySelector('#phone').href = 'https://www.baidu.com'; this.disabled = true;// this 指向事件的调用者 }
-
改变样式属性
-
element.style
-
属性采取的是驼峰命名法
-
改变的是行内样式 权重更高
-
适合改变样式比较少的情况
-
document.querySelector('#phone').onclick = function () { this.style.width = '200px'; this.style.backgroundColor = 'red'; }
-
-
element.className
- 适合改变的样式特别多的情况
- 覆盖原来的类名
-
-
获取元素属性
-
element.属性 获取Js内置属性
-
element.getAttribute(‘属性’)
-
主要获取自定义属性
-
<div index="1"></div> console.log(document.querySelector('div').getAttribute('index'));// 1
-
-
-
设置元素属性
-
element.属性 = new属性
-
elment.setAttribute(‘属性’,‘new属性’)
-
<div index="1" class="nav"></div> var div = document.querySelector('div'); div.className = 'newNav'; div.setAttribute('class','newNav');// class比较特殊 其他都是按名字设置
-
-
移除属性
- element.removeAttribute(‘属性’);
-
H5自定义属性
-
自定义属性目的
为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
-
规范:data-名称
原因:为了更好的区分是内置属性还是自定义属性的方法
-
获取自定义属性 ie11以上支持
element.dataset.名称或者element.dataset[‘名称’]
<div data-index="1" data-my-name="zt"></div> var div = document.querySelector('div'); console.log(div.dataset.index); console.log(div.dataset.myName);// 争对多个命名 采用驼峰命名法
-
-
3.5节点操作
-
使用原因:
由于文档内容都可以视为节点,并且相对于DOM操作,节点操作的逻辑性更强
-
节点至少拥有以下几个基本属性
- 节点类型nodeType
- nodeType = 1 元素节点
- nodeType = 2 属性节点
- nodeType = 3 文本节点(文字、空格、换行等)
- 节点名称
- 节点值
- 节点类型nodeType
-
节点层级
-
父级节点
-
node.parentNode
-
返回某节点的父节点,即离当前节点最近的一个节点
-
<div class="demo"> <div class="child"></div> </div> var child = document.querySelector('.child'); console.log(child.parentNode); // 得到的是包含子节点在内的父节点
-
-
子节点
- childNodes 标准
- 返回包含指定节点的子节点的集合,其中包含了元素节点、文本节点等,需要过滤(通过nodeType来过滤)之后才能使用,一般很少使用
- children 非标准
- 获取节点的子节点集合,只包含元素节点,常用
- 不存在兼容性问题
- childNodes 标准
-
获取第一个子节点/最后一个子节点
- firstChild/lastChild
- 获取的子节点包括文本节点和元素节点
- firstElementChild/lastElemenChild
- 获取的子节点只包括元素节点
- 但是只有ie9以上才支持
- 总结:采用children方式获取第几个节点
- firstChild/lastChild
-
兄弟节点
- 上一个兄弟节点/下一个兄弟节点
- previousSiblings/nextSibings
- 获取包括文本节点等的所有节点
- previousElementSiblings/nextElementSibings
- 获取元素节点
- ie9以上支持
- previousSiblings/nextSibings
- 上一个兄弟节点/下一个兄弟节点
-
创建元素节点
-
document.createElement
-
-
添加元素节点
-
追加元素节点
-
node.appendChild(newNode);
-
-
在某个子节点前面添加元素节点
-
node.insertBefore(newNode,某个子节点);
-
-
-
删除元素节点
- node.removeChild(child); 返回删除的节点元素
-
克隆节点
- node.cloneNode();返回调用该方法的节点的一个副本
- 如果括号为空/为false,则为浅拷贝,之复制标签不复制里面的子节点
- 只有当括号内为true,才为深拷贝,拷贝标签以及其内的所有内容
-
三种创建元素节点方式的区别
-
document.write()
-
当页面加载完成之后,也即页面文档流加载完毕之后,再调用该语句会造成页面重绘
-
document.write('<a href="#">删除</a>')
-
-
element.innerHTML
- 采取字符串拼接的方式 时间为3秒 效率很低 原因:每次创建新的字符串都需要开辟新的内存空间,很消耗内存
- 采取数组形式拼接 时间为几毫秒 效率很高
-
document.createElement()
- 时间为几十毫秒
-
总结: 不同浏览器下,innerHTML效率比createElement高
-
-
3.6高级事件
3.6.1注册事件(绑定事件)/ 删除事件
-
概述
给元素添加事件,包括传统方式和方法监听注册方式
-
传统方式
-
利用on开头的事件:onclick
-
方式有两种
-
<button onclick="alert('hi')"></button>
-
btn.onclick = function() { }
-
-
特点:
- 注册事件的唯一性
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
-
-
方法监听注册方式
-
w3c标准
-
利用addEventListener()方式进行监听注册
-
ie9版本以上支持
-
ie9版本以下采用attachEvent() // 但是找不到这个函数,不知道为啥
-
非标准,经量不要在生产环境中使用
-
只适用于IE浏览器
-
使用方式
-
eventTarget.attachEvent(eventNameWithOn,callback);
-
参数说明
- eventNameWithOn:事件类型字符串,比如:onclick,此处要带上On
- callback:事件处理函数
-
-
-
特点
- 同一个元素同一个事件可以注册多个监听器
- 按照注册顺序依次执行
-
用法
-
eventTarget.addEventListener(type,listener[,useCapture])
-
将指定得监听器注册到eventTarget(目标对象上),当该对象触发指定得事件时,就会执行事件处理函数
-
参数说明
- type:事件类型字符串,比如:click,此处不带on
- listener:事件处理函数,事件发生时,会调用该监听函数
- userCaptuer:可选参数,为一个布尔值,默认为false,涉及到DOM事件流。
-
-
注册事件兼容性解决方案
-
兼容性处理原则:首先照顾大多数浏览器,再处理特殊浏览器
-
/** * 注册事件 * @param element 元素对象 * @param eventName 事件名称 * @param fn 注册监听事件 */ function addEventListener(element,eventName,fn) { // 判断当前浏览器是否支持 addEventListener 方法 (ie9以上) if (element.addEventListener) { element.addEventListener(eventName,fn); } else if (element.attachEvent) { // ie9 以下且为IE浏览器 element.attachEvent('on' + eventName,fn); } else { // 通用 element['on' + eventName] = fn; // 类似于 element.onclick = fn; } }
-
-
删除事件
-
应用场景:
由于某对象绑定某注册事件之后,直到页面销毁才消失,当只需要一次事件调用得时候,就需要删除事件
-
删除事件方式
-
传统注册方式
-
btn.onclick = null
-
var btn = document.querySelector('button'); btn.onclick = function () { alert('1'); btn.onclick = null; // 解绑函数 }
-
-
方法监听注册方法
-
eventTarget.removeEventListener(type,listener[,useCapture]);
-
var btn = document.querySelector('button'); function fn() { alert('1'); btn.removeEventListener('click',fn); } btn.addEventListener('click',fn);
-
eventTarget.detachEvent(eventNameWithOn,callback);
-
var btn = document.querySelector('button'); function fn() { alert('1'); btn.detachEvent('click',fn); } btn.attachEvent('click',fn);
-
-
-
-
删除事件兼容性解决方案
/** * 删除事件 * @param element 元素对象 * @param eventName 事件名称 * @param fn 注册监听事件 */ function removeEventListener(element,eventName,fn) { // 判断当前浏览器是否支持 removeEventListener 方法 (ie9以上) if (element.removeEventListener) { element.removeEventListener(eventName,fn); } else if (element.detachEvent) { // ie9 以下且为IE浏览器 element.detachEvent('on' + eventName,fn); } else { // 通用 element['on' + eventName] = null; } }
-
3.6.2 DOM事件流
-
概述
-
事件流
描述的是页面中接收事件的顺序
-
DOM事件流
事件发生时会在元素节点之间按照特点的顺序传播,该传播过程称为DOM事件流
-
-
分为三个阶段 只是一个过程而已
- 捕获阶段
- 网景公司最早提出,由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接收的过程。
- 当前目标阶段
- 当前元素
- 冒泡阶段
- IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程。
- 捕获阶段
-
注意
-
JS代码只能执行捕获或者冒泡其中的一个阶段,但是如果写了本质上是可以按照不同阶段来执行的
-
onclick和attachEvent只能得到冒泡阶段
-
addEventListener(type,listener[,useCapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是false,表示在事件冒泡阶段调用事件处理程序。
-
实际开发中常关注事件冒泡
-
有些事件没有冒泡,比如:onblur onfocus onmounseenter onmouseleave
-
3.6.3 事件对象
-
概述
侦听函数的形参,事件发生的一系列相关数据的集合,由系统自动创建
-
例子
var son = document.querySelector('.son'); son.onclick = function (e) { console.log(e); }
-
存在兼容性问题,ie6/7/8 通过window.event获取,而不是通过侦听函数形参进行获取
-
如果使用eventTarget.onclick = function() {}写法,兼容性写法如下:
son.onclick = function (e) { e = e || window.event; }
-
-
事件对象常见属性和方法
-
e.target 返回触发事件的对象(元素)
-
与this不同点在于:this 返回的是绑定事件的对象(元素) this 与 e.currentTarget获得内容是一致的
-
例子:
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> var ul = document.querySelector('ul'); ul.addEventListener('click',function (e) { console.log(e.target); // 如果点击的是li标签 返回的是li console.log(this); // 返回绑定事件对象 ul })
-
兼容性问题
-
ie6/7/8不支持 只能通过window.event.srcElement获取
-
解决兼容性
ul.onclick = function (e) { e = e || window.event; var target = e.target || e.srcElement; console.log(target); }
-
-
-
e.type 返回事件类型
-
e.preventDefault() 阻止默认行为(事件)
-
即:链接不跳转,提交按钮不能提交
-
案例:
a.addEventListener('click',function (e) { e.preventDefault(); })
-
传统注册方式
a.onclick = function (e) { e = e || window.event; // 普通浏览器 可采用此方式 e.preventDefault(); // 低版本浏览器 ie6/7/8 可采用此属性 e.returnValue; // 没有兼容性问题, 但是也仅仅只限于传统的注册方式 并且之后的代码也不再执行 return false; }
-
-
e.stopPropagation() 阻止冒泡
-
阻止当前对象事件冒泡 ,对当前事件对象添加
-
案例
a.addEventListener('click',function (e) { alert('dianji'); e.stopPropagation(); })
-
兼容性问题
-
ie6/7/8采用e.cancelBubble属性的方式进行阻止冒泡行为
-
a.onclick = function (e) { if (e && e.stopPropagation) { e.stopPropagation(); } else { window.event.cancelBubble = true; } }
-
-
-
事件委托
-
也称为事件代理,在jQuery里面称为事件委派
-
事件委托原理
给父节点添加事件侦听器,利用事件冒泡影响每一个子节点。
相对于以前给每个子节点单独设置事件监听器不同的是,此时事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
例子:给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,便会触发事件监听器
-
事件委托的作用
只操作了一次DOM,便提升了程序的性能
-
-
3.6.4常用的鼠标事件
1.
-
禁止鼠标右键菜单
-
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下菜单
-
document.addEventListener('contextmenu',function (e) { e.preventDefault(); })
-
-
禁止鼠标选中
-
selectstart
-
document.addEventListener('selectstart',function (e) { e.preventDefault(); })
-
-
mouseenter与mouseover的区别
- 都是鼠标移到元素上时会触发事件
- 区别在于:mouseenter/mouseleave不会冒泡,而mouseover/mouseout会冒泡
3.6.5鼠标事件对象
- MouseEvent
- e.clientX/e.clientY
- 返回鼠标触发事件处相对于浏览器窗口可视区的X/Y坐标
- e.pageX/e.pageY
- 返回鼠标触发事件处相对于文档页面的X/Y坐标 ie9以上支持
- e.screenX/e.screenY
- 返回鼠标相对于电脑屏幕的X/Y坐标
3.6.6常用键盘事件
- keyup 按键弹起时执行
- keydown 按键按下时执行
- keypress 按键按下时执行 但是不识别功能键 ctrl shift 左右箭头等
- 三个执行顺序keydown -> keypress -> keyup
3.6.7键盘事件对象
- keyBoardEvent
- e.key获取按下得建
- e.keyCode得到相应键得ASCII值
- keyup 和 keydown 事件不区分字母大小写
- keypress事件区分字母大小写
四、BOM
4.1概述
-
BOM提供独立于内容而与浏览器窗口进行交互的对象,其核心对象是window
-
BOM缺乏标准,javascript语法的标准化组织是ECMA,DOM的标准化组织是W3C,BOM最初是NEtscape浏览器标准的一部分
-
与DOM的区别
DOM BOM 文档对象模型 浏览器对象模型 DOM将文档当作一个对象看待 BOM把浏览器当作一个对象看待 DOM的顶级对象是document BOM的顶级对象是window DOM主要学习的是操作页面元素 BOM学习的是浏览器窗口交互的一些对象 DOM是W3C标准规范 BOM是浏览器厂商在各自浏览器上定义的,兼容性较差
4.2 BOM的组成
- window对象是浏览器的顶级对象,具有双重角色
- 是js访问浏览器窗口的一个接口
- 它是一个全局对象.定义在全局作用域中的变量、函数都会变成window对象的属性和方法
- 在调用window对象方法的时候,一般可以省略window
4.3 window对象常见事件
4.3.1窗口加载事件
-
使用
window.onload = function () { } 或 window.addEventListener('load',function () { })
-
窗口加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、css文件等),就会调用该处理函数
-
window.onload = function () {} 传统的注册事件只能写一次,以最后一个为准
-
window.addEventListener(‘load’,function () {})没有限制
-
使用
document.addEventListener('DOMContentLoaded',function () { alert('ll'); })
- DOMContentLoaded事件触发时,仅当DOM加载完成,不包括样式表,图片Flash等
- ie9以上才支持
- 应用场景
- 如果页面图片较多,从用户访问到onload触发可能需要较长的时间,交换效果不能实现,必然影响用户体验,此时可以用DOMContentLoaded事件比较合适
4.3.2 窗口大小调整
-
使用
window.onresize = function () { }; window.addEventListener('resize',function () { });
-
调整窗口大小加载事件,当触发时就调用处理函数
-
只要窗口大小发生像素变化,就会触发这个事件
-
使用场景
-
完成响应式布局,window.innerWidth获取当前屏幕宽度
window.addEventListener('load',function () { var div = document.querySelector('div'); window.addEventListener('resize',function () { if (window.innerWidth < 800) { div.style.display = 'none'; } else { div.style.display = 'block'; } }) })
-
4.3.3 定时器
-
setTimeout()定时器
-
用法
window.setTimeout(调用函数(回调函数),[延迟的毫秒数]);
-
用于设置一个定时器,该定时器在定时器到期后执行调用函数
-
注意
- window可以省略
- 这个调用函数可以直接写函数,或者写函数名,或者采取字符串’函数名()'三种形式,第三种不推荐。
- 延迟的毫秒数省略默认为0
-
停止计时器
-
window.clearTimeout(timer);
-
window可以省略
-
取消先前通过调用setTimeout建立的定时器
-
里面的参数为定时器标识符,也即定时器的别名
-
function closeBox() { var div = document.querySelector('div'); div.style.display = 'none'; } var timer = setTimeout(closeBox,5000); window.addEventListener('load',function () { var button = document.querySelector('button'); button.addEventListener('click',function () { clearTimeout(timer); }) })
-
-
-
setInterval()定时器
-
window.setInterval(调用函数(回调函数),[延迟的毫秒数]);
-
用法与setTimeout一样,主要区别是,该函数会每隔一定事件便调用回调函数,反复调用
-
停止定时器 clearInterval(timer);
-
4.3.4 this指向
- this最终指向的是那个调用它的对象
- 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)
- 方法调用中谁调用this便指向谁
- 构造函数中this指向构造函数的实例
4.3.5 js执行机制
-
js最大特点是单线程的,单线程意味着所有任务需要排队,这样会导致一个问题:如果js执行时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
-
为了解决这个问题,利用多核CPU的计算能力,HTML5提出Web Worker标准,允许javascript脚本创建多个线程,于是js出现了同步和异步。
-
js执行将任务分为同步任务和异步任务
-
同步任务
同步任务都在主线程上执行,形成一个执行栈
-
异步任务
js的异步是通过回调函数实现的,分为以下三类
- 普通事件:click等
- 资源加载:onload等
- 定时器:setTimeout等
-
-
js执行机制实现
-
先执行执行栈中的同步任务
-
异步任务(回调函数)放入任务队列中。
-
一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行操作。
-
由于主线程不断的重复获得任务、执行任务,再获得任务,再执行,这种机制被称为事件循环
-
-
用例分析
console.log(1); document.onclick = function () { console.log('click'); }; console.log(2); setTimeout(function () { console.log(3); },3000);
将上述js代码按照从上往下的次序放入执行栈中,如下图所示:
执行过程:
-
依次执行打印1,将onclick事件交由异步处理程序,打印2,将setTimeout事件交由异步处理程序
-
在setTimeout设置的3秒之前点击页面
-
异步进程在点击页面事件开始后,将处理函数(回调函数打印click)交由任务队列中
-
3秒之间完成之后,异步处理程序将回调函数(打印3)交由任务队列中
-
事件循环在主线程完成之后不断监听任务队列是否为空,不为空,将任务按照先进先出的原则将任务交由主线程进行执行
-
因此打印的结果如下:
-
-
在setTimeout设置的3秒之后点击页面
-
3秒之间完成之后,异步处理程序将回调函数(打印3)交由任务队列中
-
异步进程在点击页面事件开始后,将处理函数(回调函数打印click)交由任务队列中
-
事件循环在主线程完成之后不断监听任务队列是否为空,不为空,将任务按照先进先出的原则将任务交由主线程进行执行
-
因此打印的结果如下:
-
4.4 location对象
4.4.1 概述
window对象给我们提供了一个location属性用于获取或设置窗体的url,并且可以用于解析url,因为这个属性返回的是一个对象,因此也将这个属性称为location对象
4.4.2 location对象的属性
location对象属性 | 返回值 |
---|---|
location.href | 获取或者设置整个url |
location.host | 返回主机/域名 |
location.port | 返回端口号 |
location.pathname | 返回路径 |
location.serach | 返回参数 |
location.hash | 返回锚点 |
4.4.3 location对象方法
location对象方法 | 返回值 |
---|---|
location.assign() | 跟href一样,可以跳转页面(也称为重定向页面),记录历史,可以后退页面 |
location.replace() | 替换当前页面,不记录历史,不可以后退页面 |
location.reload() | 重新加载页面,相当于刷新按钮或者f5 如果参数为true 强制刷新CTRL+f5 |
4.4 navigator对象
-
navigator对象包含有关浏览器的信息,很多属性,最常用的是userAgent,该属性可以返回由客户机发送服务器的user-agent头部的值
-
实现根据打开终端的不同跳转页面
if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|ios|iPad|Android|Mobile|BlackBerry|IEMobile |MQQBrowser|JUC|Fennec|woSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) { window.location.href = "https://m.jd.com/";// 手机 } else { window.location.href = "https://www.jd.com/";// 电脑 }
4.4 history对象
-
与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL
-
history对象方法 作用 back() 后退 forward() 前进 go(参数) 前进/后退 参数是1 前进一个页面, -1 后退一个页面