DOM获取元素
web api基本认识
作用和分类
- 作用: 就是使用JS去操作HTML和浏览器
- 分类:DOM(文档对象模型)、BOM(浏览器对象模型)
什么是DOM
- DOM(文档对象模型)是用来呈现以及与任意HTML或XML文档交互的API
- 作用
- 开发网页内容特效和实现用户交互
DOM树
- 将HTML文档以树状结构直观的表现出来,称为文档树或DOM树
- 描述网页内容关系的名词
- 作用: 文档树直观的体现了标签和标签之间的关系
DOM对象
- 浏览器根据HTML标签生成的JS对象
- 所有的标签属性都可以在这个对象上面找到
- 修改这个对象的属性会自动映射到标签身上
<button>点击</button>
<script>
let btn = document.querySelector('button')
//DOM对象
console.dir(btn)
</script>
- DOM的核心思想
- 把网页内容当做对象来处理
- document对象
- 是DOM里提供的一个对象
- 所以它提供的属性和方法都是用来访问和操作网页内容的
- 网页所有内容都在document里面
获取DOM对象
- 根据CSS选择器来获取DOM元素
- 选择匹配的第一个元素
- 语法
document.querySelector('css选择器')
- 参数
- 包含一个或多个有效的css选择器字符串
- 返回值
- css选择器匹配的第一个元素,一个HTMLElement对象
- 如果没有匹配到,则返回null
<button>点击</button>
<button>点击按钮</button>
<button class = "three">点击按钮</button>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
//js 获取元素
let btn = document.querySelector('button')
//获取第三个HTMLElement对象
let btnt = document.querySelector('.three')
//获取ul的最后一个子标签
let li = document.querySelector('ul li:last-child')
//DOM对象
console.dir(btn)
</script>
- 选择匹配的多个元素
- 语法
document.querySelectorAll('css选择器')
- 参数
- 包含一个或多个有效的css选择器字符串
- 返回值
- css选择器匹配的NodeList对象集合
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> let lis = document.querySelectorAll('ul li') console.log(lis) </script>
- document.querySeletorAll(’ ')获取到的是一个伪数组
- 有长度有索引号的数组
- 但是没有pop() push()等数组方法
- 通过遍历的方式获取数组的每一个元素
- 根据id获取一个元素
document.getElementById('标签id属性值')
- 根据标签获取一类元素 获取页面中所有标签
doucument.getElementsByTagName('标签名')
- 根据类名获取元素 获取页面 所有类名的元素
doucument.getElementsByClassName('类名')
设置/修改DOM元素内容
- 修改标签元素里面的内容
- document.write()方法
- 只能将文本内容追加到</body>前面的位置
- 文本中包含的标签会被解析
- 对象.innerText
- 将文本内容添加/更新到任意标签位置
- 不能解析标签
<div>标签内容</div> <script> //获取标签 let div = document.querySelector('div') //修改标签元素 div.innerText = '修改标签内容' </script>
- 对象.innerHTML
- 将文本内容添加/更新到任意标签位置
- 能解析标签
<div>标签内容</div> <script> //获取标签 let div = document.querySelector('div') //修改标签元素 div.innerHTML = '<b>修改标签内容</b>' </script>
- document.write()方法
设置/修改DOM元素属性
设置/修改元素常用属性
- 通过JS设置/修改标签元素属性
- 常见的属性比如: href、title、src等
- 语法
对象名.属性 = 值
//获取元素
let pic = document.querySeletor('img')
//操作元素
pic.src = './images/mhg.jpg'
pic.title = '这是内容图片'
设置/修改元素样式属性
- 通过style属性操作css
- 语法
对象名.style.样式属性 = 值
//1.获取元素对象 let box = document.querySeletor('.box') //2.修改背景颜色 box.style.backgroundColor = 'red' box.style.width = '300px' box.style.marginTop = '50px'
- 注意事项
- 修改样式通过style属性引出
- 如果属性有-连接符,需要转换为小驼峰命名法
- 赋值的时候,需要加css单位
- 操作类名(className)操作css
- 修改样式比较多,直接通过style属性修改比较繁琐,可以通过借助于css类名的形式修改
- 语法
元素.className = 'active'
- 注意
- 由于css是关键词,所以使用className去代替
- className是使用新值换旧值,如果需要添加一个类,需要保留之前的类名
//样式
.active {
width: 300px;
height: 300px;
background-color: red;
margin-left: 100px
}
//获取元素
let box = document.querySeletor('div')
//设置样式
box.className = 'active'
- 通过classList操作类控制CSS
- 为了解决className容易覆盖以前的类名,可以通过classList方式追加和删除类名
- 语法
//追加一个类 元素.classList.add('类名') //删除一个类 元素.classList.remove('类名') //切换一个类 元素.classList.toggle('类名')
<style>
div {
width: 200px;
height: 200px;
background-color: antiquewhite;
}
.active {
width: 300px;
height: 300px;
background-color: aqua;
margin-left: 100px;
}
</style>
<div class = 'one'></div>
<script>
//获取元素
let box = document.querySelector('.one')
//add是方法 添加(追加)
box.classList.add('active')
//remove是方法 移除
box.classList.remove('active')
//toggle是方法 切换
box.classList.toggle('active')
</script>
设置/修改表单元素属性
- 正常的有属性取值,跟其他的标签属性没有任何区别
- 获取:DOM对象.属性名
- 设置:DOM对象.属性名 = 新值
<input type="text" value="请输入"> <button disabled></button> <script> //1.获取元素 let input = document.querySelector('input') //禁用按钮 let btn = document.querySelector('button') //2.设置值 //得到 console.log(input.value) //设置 input.value = '华为手机' input.type = 'password' //启用按钮 btn.disabled = false
定时器-间歇函数
定时器函数介绍
- 每间隔一段时间执行一次,不需要手动触发
定时器函数基本使用
- 开启定时器
- 语法
setInterval(函数,间隔时间(单位:ms))
setInterval(function() {
console.log('获取100点经验值')
},1000)
- 关闭定时器
- 语法
let 变量名 = setInterval(函数,间隔时间) clearInterval(变量名)
DOM事件基础
事件
- 事件是在编程时,系统内发生的动作或发生的事情
事件监听
- 让程序检测是否有事件发生,一旦事件触发,就立即调用一个函数做出响应,也称为注册事件
- 语法
元素.addEventListener('事件',要执行的函数)
- 事件监听三要素
- 事件源: 那个DOM元素被事件触发了,要获取DOM元素
- 事件: 用什么方式触发,事件类型必须是字符串
- 事件调用的函数: 要做什么事
<button>点击</button>
<script>
let btn = document.querySeletor('button')
btn.addEventListener('click',function(){
console.log('你刚刚点击了')
})
</script>
拓展(事件监听版本)
- DOM L0
- 语法
事件源.on事件 = function(){}
- DOM L2
- 语法
//第三个boolean值,可以是true或false,根据传入的值来指定事件的执行方式(捕捉或冒泡阶段执行) 事件源.addEventListener(事件,事件处理函数,[true||false])
- 名词解释
- 捕获: 事件捕获,从DOM结构上到下,window.addEventListener()先document.addEventListener()被捕获
- 冒泡: 事件冒泡,从DOM结构底层向上传递,document.addEventListener()先于window.addEventListener()被触发
<a id = 'a'>aa</a><br> <a id = 'b'>bb</a><br> <a id = 'c'>cc</a><br> <a id = 'd'>dd</a> <script> function showa(){ let ida = document.querySeletor('#a') } function showb(){ let idb = document.querySeletor('#b') } function showc(){ let idc = document.querySeletor('#c') } function showd(){ let idd = document.querySeletor('#d') } window.addEventListener('click',showa,true) window.addEventListener('click',showb,false) document.addEventListener('click',showc,true) document.addEventListener('click',showd,false) </script>
事件类型
- 鼠标事件
- click 鼠标点击
- mouseenter 鼠标经过
- mouseleave 鼠标离开
- dbclick 鼠标双击按钮
- mousedown 鼠标按下任意按钮
- mouseout 鼠标移出元素,或移到它的子元素
- 焦点事件
- focus 获得焦点
- blur 失去焦点
- 键盘事件
- keydown 键盘按下触发
- keyup 键盘抬起触发
- keypress 除了shfit、Fn、CapsLock外的任意被按住
- 文本事件
- input 用户输入事件
高阶函数
-
call()、apply()、bind()函数
- 语法
//第二个参数可选,传入一个数组或类数组对象,如果参数的值为null或underfined,表示不需要传入任何参数 func.apply(thisArg,[argsArray]) //第二个参数为参数列表 func.apply(thisArg,arg1,arg2,...) //目标函数被调用时,被预置入绑定函数的参数列表中的参数 func.bind(thisArg[,arg1[,arg2[,...]]])
- call,apply,bind函数都是为了改变this的指向
- call,apply的出现是为了改变函数内部this的指向
let str = "我是傻逼" let obj = { str: '我是废物', foo: function(...args){ console.log(this.str,this,...args) } } //此时的this是obj obj.foo() //我是废物 {str: '我是废物', foo: ƒ} //此时的this是window let ff = obj.foo ff() //undefined Window {window: Window, self: Window, document: document, name: '', location: Location, …} ff.call(obj,1,2,3)//我是废物 {str: '我是废物', foo: ƒ} 1 2 3 ff.call(obj,[1,2,3])//我是废物 {str: '我是废物', foo: ƒ} (3) [1, 2, 3] ff.apply(obj,[1,2,3],4,5)//我是废物 {str: '我是废物', foo: ƒ} 1 2 3 ff.apply(obj,1,2,3)//CreateListFromArrayLike called on non-object..
- call和apply都用于去改变this的指向问题,第一个参数为this所指向的对象
- call和apply都为直接函数,返回值就为调用函数的返回值
- call的第二个位置和之后传递参数列表,当向call中传递数组时,则视为只传递了一个参数
- apply的第二个位置只能传递参数数组,在参数数组之后传递参数,均失效
-
call()函数
- 语法
function.call(thisArg,arg1,arg2,...)
- 参数
- thisArg 可选参数,在function函数运行时使用的this值,this可能不是该方法看到的实际值;函数处于非严格模式下,则指定为null或underfined时会自动替换为指向全局对象,原始值会被包装
- arg1,arg2,… 指定的参数列表
- 返回值
- 使用调用者提供的this值和参数调用改函数的返回值;若该方法没有返回值,则返回underfined
- 示例
- 使用call方法调用父构造函数
function Product(name, price) { this.name = name; this.price = price; } function Food(name, price) { Product.call(this, name, price); this.category = 'food'; } function Toy(name, price) { Product.call(this, name, price); this.category = 'toy'; } var cheese = new Food('feta', 5); var fun = new Toy('robot', 40);
- 使用call方法调用匿名函数
var animals = [ { species: 'Lion', name: 'King' }, { species: 'Whale', name: 'Fail' } ]; for (var i = 0; i < animals.length; i++) { (function(i) { this.print = function() { console.log('#' + i + ' ' + this.species + ': ' + this.name); } this.print(); }).call(animals[i], i); }
- 使用call方法调用函数并且指定上下文’this’
function greet() { var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' '); console.log(reply); } var obj = { animal: 'cats', sleepDuration: '12 and 16 hours' }; greet.call(obj); // cats typically sleep between 12 and 16 hours
-
applyl()函数
- 语法
func.apply(thisArg,[argsArray])
-
参数
- thisArg 必选的。在 func 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。
- argsArray 可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 null 或 undefined,则表示不需要传入任何参数
-
示例
- 用 apply 将数组各项添加到另一个数组
var array = ['a', 'b']; var elements = [0, 1, 2]; array.push.apply(array, elements); console.info(array); // ["a", "b", 0, 1, 2]
-
bind()函数
- 语法
function.bind(thisArg[, arg1[, arg2[, ...]]])
- 参数
- thisArg 调用绑定函数时作为 this 参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用 bind 在 setTimeout 中创建一个函数(作为回调提供)时,作为 thisArg 传递的任何原始值都将转换为 object。如果 bind 函数的参数列表为空,或者thisArg是null或undefined,执行作用域的 this 将被视为新函数的 thisArg
- arg1,arg2,… 当目标函数被调用时,被预置入绑定函数的参数列表中的参数
- 示例
- 创建绑定函数
this.x = 9; // 在浏览器中,this 指向全局的 "window" 对象 var module = { x: 81, getX: function() { return this.x; } }; module.getX(); // 81 var retrieveX = module.getX; retrieveX(); // 返回 9 - 因为函数是在全局作用域中调用的 // 创建一个新函数,把 'this' 绑定到 module 对象 // 新手可能会将全局变量 x 与 module 的属性 x 混淆 var boundGetX = retrieveX.bind(module); boundGetX(); // 81
- 偏函数
function list() { return Array.prototype.slice.call(arguments); } function addArguments(arg1, arg2) { return arg1 + arg2 } var list1 = list(1, 2, 3); // [1, 2, 3] var result1 = addArguments(1, 2); // 3 // 创建一个函数,它拥有预设参数列表。 var leadingThirtysevenList = list.bind(null, 37); // 创建一个函数,它拥有预设的第一个参数 var addThirtySeven = addArguments.bind(null, 37); var list2 = leadingThirtysevenList(); // [37] var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3] var result2 = addThirtySeven(5); // 37 + 5 = 42 var result3 = addThirtySeven(5, 10); // 37 + 5 = 42 ,第二个参数被忽略
-
高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回
防抖函数
- 任务频繁触发的情况下,只有任务触发的间隔超过指定间隔的事件,任务才会执行
function debounce(fn, interval) {
let timer = null
return function() {
// 如果用户在设定的时间内再次触发,就清除掉
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, interval);
}
}
节流函数
- 指定时间间隔内只会执行一次任务
function throttle(fn, interval) {
let timer,
firstTime = true // 是否是第一次执行
return function () {
let _this = this
if (firstTime) {
fn.apply(_this, arguments) // 第一次不需要延迟执行
return firstTime = false
}
if (timer) { // 如果定时器还在 说明前一次还没有执行完
return false
}
timer = setTimeout(() => {
clearTimeout(timer)
timer = null
fn.apply(_this, arguments)
}, interval || 500);
}
}
// 不考虑定时器的情况 直接加一个节流阀
function throttle(fn, interval) {
let canRun = true //节流阀
return function() {
if(!canRun) {
return
}
canRun = false
setTimeout(() => {
fn.apply(this, arguments)
canRun = true
}, interval);
}
}
惰性函数
- 同名函数覆盖
function createXHR() {
var xhr
if(typeof XMLHttpRequest !== 'undefined') {
xhr = new XMLHttpRequest()
createXHR = function() {
return new XMLHttpRequest()
}
} else {
try {
xhr = new ActiveXObject('Msxml2.XMLHTTP')
createXHR = function() {
return new ActiveXObject('Msxml2.XMLHTTP')
}
} catch(e) {
try {
xhr = new ActiveXObject('Microsoft.XMLHTTP')
createXHR = function() {
return new ActiveXObject('Microsoft.XMLHTTP')
}
} catch(e) {
createXHR = function() {
return null
}
}
}
}
return xhr
}
级联函数
- 链式调用,原理也就很简单,在每个方法中将对象本身return出去
function Person() {}
// 添加几个方法
Person.prototype = {
setName: function (name) {
this.name = name
return this //
},
setAge: function (age) {
this.age = age
return this
},
setSex: function (sex) {
this.sex = sex
},
}
// 别忘了重新指定一下构造函数
Person.constructor = Person
let person = new Person()
// 这样看起来做了很多重复的事情,稍微修改一下,在每个方法中将 this return 出来就可以达到 链式调用的效果
person.setName('游荡de蝌蚪')
person.setAge(18)
person.setSex('male')
// 修改之后
person.setName('游荡de蝌蚪').setAge(18).setSex('male')
console.log(person)
柯里化
- 收集参数,延后执行
// 编写一个 add 函数,实现以下功能
add(1)(2)(3) // 6
add(1)(2, 3)(4) //10
add(1, 2)(3) (4, 5) // 15
function add() {
let args = Array.prototype.slice.call(arguments)
let adder = function() {
// 利用闭包的特性保存 args 并且收集参数
args = args.concat(Array.prototype.slice.call(arguments))
return adder
}
// 利用 toString 隐式转换的的特性返回最终计算的值
adder.toString = function() {
return args.reduce((a, b) => {
return a + b
})
}
return adder
}
add(1)(2)(3) // 6
add(1)(2, 3)(4) // 10
add(1, 2)(3)(4, 5) // 15
// 当然,我们也可以借助ES6的方法简化这个函数
function add1(...args) {
let adder = (..._args) => {
args = [...args, ..._args]
return adder
}
adder.toString = () => args.reduce((a, b) => a + b)
return adder
}
环境对象
- 环境对象指的是函数内部特殊的变量this,它代表着当前函数运行时所处的环境
function fn() {
console.log(this)
}
fn()
//同上,一般书写都省略window
window.fn()
编程思想
- 排他思想
<style>
.pink {
background: pink;
}
</style>
<button>点击1</button><button>点击2</button><button>点击3</button><button>点击4</button>
<script>
let btns = document.querySeletorAll('buttton')
for(let i = 0;i < btns.length;i++){
btns[i].addEventListener('click',function(){
for(let j = 0;j < btns.length;j++){
btns[j].classList.remove('pink')
}
this.classList.add('pink')
})
}
</script>
DOM节点操作
DOM节点
- DOM树里面每个内容都称为节点
- 节点类型
- 元素节点
- 所有标签 比如body、 div等
- html是根节点
<div></div>
- 属性节点
- 所有的属性 比如href
<a href=""></a>
- 文本节点
- 所有文本
<button>按钮</button>
- 其他
- 元素节点
查找节点
父节点
- parentNode属性
- 返回最近一级的父节点,找不到返回null
子元素.parentNode
<div class="father">
<div class="son">子节点</div>
</div>
<script>
//获取元素
let sonNode = document.querySelector(".son");
//隐藏父节点
sonNode.parentNode.style.display = 'none'
console.log(sonNode.parentNode)
</script>
//获取当前节点的父亲(操作)
this.parentNode
子节点
- childNodes
- 获取所有子节点,包括文本节点(空格、换行)、注释节点等
父元素.childNodes
- children
- 仅获得所有元素节点
- 返回的还是一个伪数组
父元素.children
<button>点击获取子节点</button> <ul> <li>数组</li> <li>元素</li> <li>下标</li> <li>内容</li> </ul> <script> let btn = document.querySelector('button') btn.addEventListener('click',function() { let uls = document.querySelector('ul') for(let i = 0; i < uls.children.length;i++){ uls.children[i].style.color = 'red' } }) </script>
兄弟节点
- 下一个兄弟节点
nextElementSibling 属性
- 上一个兄弟节点
previousElementSibling 属性
<button>点击获取子节点</button>
<ul>
<li>数组</li>
<li>元素</li>
<li>下标</li>
<li>内容</li>
<li>坐标</li>
<li>日期</li>
<li>节点</li>
</ul>
<script>
let btn = document.querySelector('button')
btn.addEventListener('click',function() {
let uls = document.querySelector('ul')
let lis = uls.children
lis[2].nextElementSibling.style.color = 'green'
lis[5].previousElementSibling.style.color = 'red'
})
</script>
增加节点
- 创建新的节点
document.createElement('标签')
- 放到指定位置
//插入到这个元素父标签的最后
父元素.appendChild(要插入的元素)
//插入到父元素的某个子元素的前面
父元素.insertBefore(要插入的元素,在哪个元素前面)
<ul>
<li>元素</li>
<li>伪数组</li>
</ul>
<script>
let ul = document.querySelector('ul')
let li = document.createElement('li')
li.innerHTML = '周期'
//追加节点 父元素.appendChild(子元素) 后面追加
ul.appendChild(li)
let ali = document.createElement('li')
ali.innerHTML = '指定元素添加'
let lis = document.querySelector('ul').children
//追加节点 父元素.insertBefore(子元素,指定元素前面)
ul.insertBefore(ali,lis[2])
</script>
新增节点(补充知识点)
- insertAdjacentHTML()
- insertAdjacentHTML()方法将指定的文本解析为Element元素,并将结果节点插入到DOM树中的指定位置;它不会重新解析正在使用的元素,这可以避免额外的序列化,比直接使用innerHTML操作更快
- 语法
element.insertAdjacentHTML(position,text)
- position
- beforebegin: 元素自身的前面
- afterbegin: 插入元素内部的第一个子节点之前
- beforeend: 插入元素内部的最后一个子节点之后
- afterend: 元素自身的后面
- text
- 需要被解析为HTML或XML元素,并插入到DOM树中DOMString
- position
克隆节点
- 语法
//克隆一个已有的元素节点
元素.cloneNode(布尔值)
- cloneNode会克隆出一个跟原标签一样的元素,括号内传入布尔值
- 若为true,则代表克隆时会包含后代节点一起克隆
- 若为false,则代表克隆时不包含后代节点
- 默认为false
<ul>
<li>标签</li>
<li>数据</li>
</ul>
<script>
let ul = document.querySelector('ul')
//克隆 ul标签 默认值为false,当boolean值为false时,不克隆子节点;为true时,克隆子节点
let newUl = ul.cloneNode(true)
document.body.appendChild(newUl)
</script>
删除节点
- 若一个节点在页面中已不需要时,可以删除它
- 在JS原生DOM操作中,要删除元素必须通过父元素删除
- 语法
父元素.removeChild(要删除的元素)
- 注意点
- 如不存在父子关系则删除失败
- 删除节点和隐藏节点(display:none)有区别的:隐藏节点还是存在的,但是删除,则从html中删除节点
<button>点击</button>
<ul>
<li>数组</li>
<li>元素</li>
</ul>
<script>
//绑定点击事件
let btn = document.querySelector('button')
let ul = document.querySelector('ul')
//获取子节点
let lis = ul.childNodes
btn.addEventListener('click',function () {
//删除节点
ul.removeChild(lis[1])
})
</script>
DOM事件高级
时间对象
- 实例化
- 在代码中发现了new关键词时,一般将这个操作称为实例化
- 获取当前时间
let date = new Date()
- 获取指定时间
//指定时间为1949-10-01 let date = new Date('1949-10-01')
- 时间对象方法
- 能够使用时间对象中的方法写出常见日期
方法 | 作用 | 说明 |
---|---|---|
getFullYear() | 获得年份 | 获取四位年份 |
getMonth() | 获得月份 | 取值为0~11 |
getDate() | 获取月份中的某一天 | 不同月份取值也不相同 |
getDay() | 获取星期 | 取值为0~6 |
getHours() | 获取小时 | 取值为0~23 |
getMinutes() | 获取分钟 | 取值为0~59 |
getSeconds() | 获取秒 | 取值为0~59 |
<script>
let date = new Date()
//获取年份
console.log(date.getFullYear())
//获取月份中的某一天
console.log(date.getDate())
</script>
- 时间戳
- 是指1970年01月01日00时00分00秒起至现在的毫秒数,它是一种特殊的计量时间的方式
- 获取时间戳的方法(三种方式)
- 第一种
let date = new Date() date.getTime()
- 第二种
let times = +new Date()
- 第三种
Date.now()
//指定时间的时间戳
+new Date('2020-10-01')
重绘和回流
- 回流(重排)
- 当Render Tree中部分或者全部元素的尺寸、结构、布局等发生改变时,浏览器就会重新渲染部分或全部文档的过程称为回流
- 重绘
- 由于节点(元素)的样式的改变并不会影响它的文档流中的位置和布局时,称为重绘
- 重绘不一定引起回流,而回流一定会引起重绘
- 解析(Parser)HTML,生成DOM树(DOM Tree)
- 同时解析(Parser) CSS,生成样式规则(Style Rules)
- 根据DOM树和样式规则,生成渲染树(Render Tree)
- 进行布局Layout(回流/重排):根据生成的渲染树,得到节点的几何信息(位置,大小)
- 进行绘制Painting(重绘):根据计算和获取的信息进行整个页面的绘制
- Display:展示在页面上
事件对象
获取事件对象
- 对象,这个对象里有事件触发时的相关信息
- 获取
- 在事件绑定的回调函数的第一参数就是事件对象
- 一般命名为event、ev、e
元素.addEventListener('click',function(e){})
事件对象常用属性
- type
- 获取当前的事件类型- clientX/clientY
- 获取光标相对于浏览器可见窗口左上角的位置
- offsetX/offsetY
- 获取光标相对于当前DOM元素的左上角的位置
- key
- 用户按下的键盘的值
- 现在不提倡使用keyCode
- clientX/clientY
事件流
事件流与两个阶段的说明
- 事件流指的是事件完整执行过程中的流动路径
事件捕获和事件冒泡
- 事件冒泡
- 当一个元素的事件被触发时,同样的事件(同名事件)将会在该元素的所有祖先元素中依次触发,这个过程被称为事件冒泡
- 当一个元素触发事件后,会依次向上调用所有父级元素的同名事件
- 事件冒泡是默认存在的
<style>
.father {
margin: 100px auto;
width: 500px;
height: 500px;
background-color:aqua;
}
.son {
width: 200px;
height: 200px;
background-color: blanchedalmond;
}
</style>
<div class = "father" >
<div class = "son"></div>
</div>
<script>
let fat = document.querySelector('.father')
let son = document.querySelector('.son')
fat.addEventListener('click',function(){
alert('我是你爹')
})
son.addEventListener('click',function(){
alert('你是我儿')
})
//点击son不会触发该事件,该事件不属于同一类型事件
document.addEventListener('dblclick',function(){
alert('我是你爷爷')
})
</script>
- 事件捕获
- 从DOM的根元素开始去执行对应的事件(从外到里)
- 事件捕获需要写对应代码才能看到效果
- 代码
DOM.addEventListener(事件类型,事件处理函数,是否使用捕获机制)
- 说明
- addEventListener第三个参数传入true代表是捕获阶段触发(不常见)
- 若传入false代表冒泡阶段触发,默认就是false
- 若是用L0事件监听,则只有冒泡阶段,没有捕获
<!--捕获-->
<script>
let fat = document.querySelector('.father')
let son = document.querySelector('.son')
fat.addEventListener('click',function(){
alert('我是你爹')
},true)
son.addEventListener('click',function(){
alert('你是我儿')
},true)
document.addEventListener('dblclick',function(){
alert('我是你爷爷')
},true)
</script>
阻止事件流动
- 因为默认就有冒泡模式的存在,所有容易导致事件影响到父级元素
- 若想把事件就限制在当前元素内,就需要阻止事件流动
- 阻止事件流动需要拿到事件对象
- 语法
事件对象.stopPropagation()
<div class = "father" >
<div class = "son"></div>
</div>
<script>
let fat = document.querySelector('.father')
let son = document.querySelector('.son')
fat.addEventListener('click',function(){
alert('我是你爹')
})
son.addEventListener('click',function(e){
alert('你是我儿')
//阻止流动 限制到当前元素内触发
e.stopPropagation()
})
document.addEventListener('click',function(){
alert('我是你爷爷')
})
</script>
- 补充
- 鼠标经过事件
- mouseover 和 mouseout会有冒泡效果
- mouseenter 和 mouseleave没有冒泡效果(推荐使用)
- 鼠标经过事件
<div class = "father" >
<div class = "son"></div>
</div>
<script>
let fat = document.querySelector('.father')
let son = document.querySelector('.son')
fat.addEventListener('mouseenter',function(){
alert('我是你爹')
})
son.addEventListener('mouseenter',function(e){
alert('你是我儿')
//阻止流动 限制到当前元素内触发
//e.stopPropagation()
})
document.addEventListener('mouseenter',function(){
alert('我是你爷爷')
})
</script>
- 阻止默认行为,比如链接点击不跳转,表单域的不提交
- 语法
e.preventDefault()
<a href="http://www.baidu.con">百度一下</a>
<script>
let a = document.querySelector('a')
a.addEventListener('click',function(e){
//阻止默认事件 上面的百度一下,点击之后,就不会跳转了
e.preventDefault()
})
</script>
注册事件(两种)
- 传统on注册(L0)
- 同一个对象,后面注册的事件会覆盖前面注册(同一个事件)
- 直接使用null覆盖就可以实现事件解绑
- 都是冒泡阶段执行的
- 语法
//元素.on事件 = function(){} 元素.onclick = function(){} //解绑事件 元素.onclick = null
- 事件监听注册(L2)
- 语法
addEventListener(事件类型,事件处理函数,是否使用捕获)
- 后面注册的事件不会覆盖前面注册的事件(同一个事件)
- 可以通过第三个参数去确定是在冒泡或捕获阶段执行
- 必须使用removeEventListener(事件类型,事件处理函数,获取捕获或者冒泡阶段)解绑
- 匿名函数无法被解绑
<button>点击事件</button>
<script>
let btn = document.querySelector('button')
//绑定点击事件
btn.addEventListener('click',add)
function add() {
alert('第一次')
}
//接触绑定事件 匿名函数不可解绑,这里把函数提出来
btn.removeEventListener('click',add)
</script>
事件委托
- 优点
- 给父级元素加事件(可以提高性能)
- 原理
- 事件委托其实是利用事件冒泡的特点,给父级元素添加事件,子元素可以触发
- 实现
- 事件对象.target可以获取真正触发事件的元素
<ul>
<li>数组</li>
<li>元素</li>
<li>标签</li>
<li>可控量</li>
<li>数字化</li>
</ul>
<script>
//不需要给每个li标签注册事件 而是把事件委托给父级标签
//利用了事件的冒泡原理
let ul = document.querySelector('ul')
ul.addEventListener('click',function(e) {
alert('点击事件触发')
//得到当前的元素
e.target.style.color = 'red'
})
</script>
DOM网页特效
手风琴效果案例
<style>
ul {
list-style: none;
}
* {
margin: 0;
padding: 0;
}
div {
width: 1200px;
height: 400px;
margin: 50px auto;
border: 1px solid red;
overflow: hidden;
}
div li{
width: 240px;
height: 400px;
float: left;
transition: all 500ms;
}
div ul {
width: 1200px;
}
</style>
<div id="box">
<ul>
<li><a href="#"><img src="C:\Users\lc181\Desktop\素材\01.webp" alt=""></a></li>
<li><a href="#"><img src="C:\Users\lc181\Desktop\素材\06.webp" alt=""></a></li>
<li><a href="#"><img src="C:\Users\lc181\Desktop\素材\03.webp" alt=""></a></li>
<li><a href="#"><img src="C:\Users\lc181\Desktop\素材\04.webp" alt=""></a></li>
<li><a href="#"><img src="C:\Users\lc181\Desktop\素材\05.webp" alt=""></a></li>
</ul>
</div>
<script>
//获取元素
let lis = document.querySelector('ul').children
//绑定事件
for(let i = 0;i < lis.length; i++){
lis[i].addEventListener('mouseenter',function() {
//利用排他思想实现
for(let j = 0; j < lis.length; j++ ){
lis[j].style.width = '100px'
}
this.style.width = '800px'
})
//鼠标离开事件
lis[i].addEventListener('mouseleave',function(){
for(let j = 0;j < lis.length; j++){
lis[j].style.width = '240px'
}
})
}
</script>
滚动事件和加载事件
滚动事件
- 事件名
- scroll
- 监听整个页面滚动
- 语法
//页面滚动事件 window.addEventListener('scroll',function(){ //TODO })
- 给window或document添加scroll事件
- 监听某个元素的内部滚动直接给某个元素添加即可
<script>
window.addEventListener('scroll',function(){
})
</script>
加载事件一
- 加载外部资源(如图片\外联css和JS等)加载完毕时触发的事件
- 事件名
- load
- 监听页面所有资源加载完毕
- 语法
//页面加载事件 window.addEventListener('load',function(){ //TODO })
- 不光可以监听整个页面资源加载完毕,也可以针对某个资源绑定load事件
加载事件二
- 当初始化的HTML文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表、图像等完全加载
- 事件名
- DOMContentLoaded
- 监听页面DOM加载完毕
- 给document添加DOMContentLoaded事件
document.addEventListener('DOMContentLoaded', function() { //执行的操作 })
元素大小和位置
scroll家族
- 获取宽高
- 获取元素的内容总宽高(不包含滚动条)返回值不带单位
- scrollWidth 和 scrollHeight
- 获取位置
- 获取元素内容往左、往上滚出去看不到的距离
- scrollLeft 和 scrollTop
- 这两个属性是可以修改的(不用单位)
//锁定往上滚出去的距离 元素.scrollTop = 500
<div>
内容更新中....
内容更新中....
内容更新中....
内容更新中....
内容更新中....
内容更新中....
内容更新中....
内容更新中....
内容更新中....
内容更新中....
内容更新中....
内容更新中....
内容更新中....
</div>
<script>
//scrollWidth scrollHeight 内容的宽高
let div = document.querySelector('div')
console.log(div.scrollWidth) //不带单位 133
console.log(div.scrollHeight) //不带单位 210
//scrollLeft scrollTop 被卷去的头部和左侧
div.addEventListener('scroll',function(){
console.log(this.scrollTop)
})
</script>
- 检测页面滚动距离
window.addEventListener('scroll',function(){
//document.documentElement 获取整个文档,返回HTML标签
//document.documentElement.scrollTop 获得当前页面被卷去的头部
})
offset家族
- 获取宽高
- 获取元素的自身的宽高、包含元素自身的设置的宽高、padding、border
- offsetWidth 和 offsetHeight
<script>
//scrollWidth scrollHeight 内容的宽高
let div = document.querySelector('div')
console.log(div.scrollWidth) //不带单位 133
console.log(div.scrollHeight) //不带单位 210
// offsetWidth offsetHeight 盒子的宽和高 + padding + border
console.log(div.offsetWidth) //不带单位 150
console.log(div.offsetHeight) //不带单位 150
//scrollLeft scrollTop 被卷去的头部和左侧
div.addEventListener('scroll',function(){
console.log(this.scrollTop)
})
</script>
- 获取位置
- 获取元素距离自己定位父级元素的左、上距离
- offsetLeft 和 offsetTop 注意是只读属性
client家族
- 获取宽高
- 获取元素的可见部分宽高(不包含边框\滚动条等)
- clientWidth 和 clientHeight
<style>
div {
width: 150px;
height: 150px;
background-color: aqua;
overflow: auto;
}
</style>
<script>
//scrollWidth scrollHeight 内容的宽高
let div = document.querySelector('div')
console.log(div.scrollWidth) //不带单位 133
console.log(div.scrollHeight) //不带单位 210
// offsetWidth offsetHeight 盒子的宽和高 + padding + border
console.log(div.offsetWidth) //不带单位 150
console.log(div.offsetHeight) //不带单位 150
//client 当前可视区域 不包含滚动条 边框等
console.log(div.clientWidth) //不带单位 133
console.log(div.clientHeight) //不带单位 150
//scrollLeft scrollTop 被卷去的头部和左侧
div.addEventListener('scroll',function(){
console.log(this.scrollTop)
})
</script>
-
获取位置
- 获取左边框和上边框宽度
- clientLeft 和 clientTop 注意是只读属性
-
在窗口尺寸改变的时候触发事件
- resize
window.addEventListener('resize',function(){ //TODO })
-
检测当前屏幕的宽度
- 语法
//获取屏幕的宽度 document.documentElement.clientWidth
BOM操作浏览器
window对象
BOM(浏览器对象模型)
- BOM(Browser Object Model)是浏览器对象模型
- window是浏览器内置中的全局对象,学习的所有web APIs的知识内容都是基于window对象实现的
- window对象下包含navigator、location、document、history、screen 5个属性,即所谓的BOM
- document是实现DOM的基础,它其实是依附于window属性
- 依附与windows对象的所有属性和方法,使用时可以省略window
定时器-延时函数
- JS内置的一个用来让代码延迟执行的函数setTimeout
- 语法
setTimeout(回调函数,等待的毫秒数)
- setTimeout仅仅只执行一次,可以理解为就是把一段代码延迟执行,平时省略window
- 清除定时器
- 语法
clearTimeout(定时器对象)
<button>解除定时器</button>
<script>
let btn = document.querySelector('button')
let stt = setTimeout(function(){
console.log(111)
},3000)
//点击 解除定时器
btn.addEventListener('click',function(){
clearTimeout(stt)
})
</script>
- 递归函数
- 自己调用自己就是递归函数
- 延迟函数结合递归函数实setInterval一样的功能
<div class="clock"></div>
<script>
let clock = document.querySelector('.clock')
function myInterval(){
let date = new Date()
clock.innerHTML = date.toLocaleString()
//延迟任务,自调用
setTimeout(myInterval,1000)
}
//启动定时任务
myInterval()
</script>
JS执行机制
- JS语言的一大特点就是单线程,也就是说,同一个事件只能做一件事,因为JS这个脚本语言诞生的使命所致–JS是为了处理页面中用户交互,以及操作DOM而诞生
- 同步和异步
- 为了解决这个问题,利用多核CPU的计算能力,HTML5提出web Worker标准,允许JS脚本创建多个线程,于是,JS出现了同步和异步
- 同步任务
- 同步任务都在主线程上执行,形成一个执行栈
- 异步任务
- JS的异步是通过回调函数实现的
- 一般而言,异步任务有以下三种类型:
- 普通事件 如click 、resize等
- 资源加载 如load 、error等
- 定时器 如setInterval 、setTimeout等
- 异步任务相关添加到任务队列中(任务队列也称为消息队列)
- 同步任务和异步任务执行顺序
- 先执行执行栈的同步任务
- 异步任务放入任务队列中
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行
<script>
console.log(111)
setTimeout(function(){
console.log(222)
},0)
console.log(333)
</script>
// 111 333 222
location对象
- location的数据类型是对象,它拆分并保存了URL地址的各个组成部分
- 常用属性和方法
- href属性获取完整的URL地址,对其赋值时用于地址的跳转
<style> span { color: aqua; } </style> <a href="http://www.bilibili.com">支付成功,<span>5</span>秒之后跳转首页</a> <script> let a = document.querySelector('a') let num = 5 let timer = setInterval(function(){ num-- a.innerHTML = `支付成功,<span>${num}</span>秒之后跳转首页` if(num === 0){ clearInterval(timer) location.href = 'http://www.bilibili.com' } },1000) </script>
- search属性获取地址中携带的参数,符号?后面部分
- hash属性获取地址中的哈希值,符号#后面部分
- reload方法用来刷新当前页面,传入参数true时表示强制刷新
//默认值为false为刷新 传入值为true强制刷新ctrl+F5 强制刷新不会在缓存中加载页面,从服务器加载 location.reload(true)
navigator对象
- navigator的数据类型是对象,该对象下记录了浏览器自身的相关信息
- 常用属性和方法
- userAgent检测浏览器的版本及平台
navigator.userAgent
histroy对象
- history的数据类型是对象,该对象与浏览器地址栏的操作相对应,如前进、后退、历史记录等
- 常用属性和方法
history对象方法 | 作用 |
---|---|
back() | 可以后退功能 |
forward() | 前进功能 |
go(参数) | 前进后退功能 参数如果是1,前进一个页面;如果是-1,后退一个页面 |
swiper插件
<style>
.box {
width: 600px;
height: 350px;
background-color: aqua;
margin: 100px auto;
}
html,
body {
position: relative;
height: 100%;
}
body {
background: #eee;
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 14px;
color: #000;
margin: 0;
padding: 0;
}
.swiper {
width: 100%;
height: 100%;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
}
.swiper-slide img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.swiper {
margin-left: auto;
margin-right: auto;
}
</style>
<div class="box">
<!-- Swiper -->
<div class="swiper mySwiper">
<div class="swiper-wrapper">
<div class="swiper-slide">Slide 1</div>
<div class="swiper-slide">Slide 2</div>
<div class="swiper-slide">Slide 3</div>
<div class="swiper-slide">Slide 4</div>
<div class="swiper-slide">Slide 5</div>
<div class="swiper-slide">Slide 6</div>
<div class="swiper-slide">Slide 7</div>
<div class="swiper-slide">Slide 8</div>
<div class="swiper-slide">Slide 9</div>
</div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
<div class="swiper-pagination"></div>
</div>
</div>
<script src="D:\PTool\vscode\plugins\swiper8\swiper-bundle.min.js"></script>
<script>
var swiper = new Swiper(".mySwiper", {
slidesPerView: 1,
spaceBetween: 30,
loop: true,
pagination: {
el: ".swiper-pagination",
clickable: true,
},
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
});
</script>
本地存储
本地存储特性
- 随着互联网的快速发展,基于网页的应用越来越普遍,同时也变得越来越复杂,为了满足各种各样得需求,会经常性在本地存储大量的数据,HTML5规范提出了相关解决方案
- 数据存储在用户浏览器中
- 设置、读取方便、设置页面刷新不丢失数据
- 容量较大,sessionStorage和localStorage约5MB左右
localStorage
- 生命周期永久生效,除非手动删除,否则关闭页面也会存在
- 可以多窗口(页面)共享(同一浏览器可以共享)
- 以键值对的形式存储使用
存储数据
- 语法
localStorage.setItem(key,value)
- 使用
<script>
//存储数据
localStorage.setItem('uname', 'admin')
</script>
获取数据
- 语法
localStorage.getItem('键')
- 使用
localStorage.getItem('uname')
删除数据
- 语法
localStorage.removeItem(key)
- 使用
localStorage.removeItem('uname')
存储复杂数据类型
- 本地只能存储字符串,无法存储复杂数据类型,需要将复杂数据类型转换成JSON字符串,在存储到本地
- JSON.stringify(复杂数据类型)
- 将复杂数据类型转换成JSON字符串 存储 本地存储中
- JSON.parse(JSON字符串)
- 将JSON字符串转换成对象, 取出 使用
let person = {
uname: '张三',
age: 12,
address: '四川省成都市'
}
//复杂类型转换成JSON字符串
localStorage.setItem('person',JSON.stringify(person))
let obj = localStorage.getItem('person')
//将JSON字符串转换成对象
console.log(JSON.parse(obj))
sessionStorage(了解)
- 生命周期为关闭浏览器窗口
- 在同一个窗口下数据可以共享
- 以键值对的形式存储使用
- 用法跟localStorage基本相同
正则表达式
介绍
- 正则表达式是用于匹配字符串中字符组合的模式,在JS中,正则表达式也是对象
- 通常用来查找、替换那些符合正则表达式的文本,许多语言都支持正则表达式
语法
定义正则表达式
- 语法
let 变量名 = /表达式/
- 其中 / /是正则表达式字面量
- 使用
<script>
//定义正则规则 reg 存储的对象
let reg = /前端/
let arr = ['前端','后端','大数据','人工智能']
//检测是否匹配
console.log(reg.test(arr))//true
</script>
元字符
普通字符
- 大多数的字符仅能够描述它们本身,这些字符称作普通字符
- 普通字符只能够匹配字符串中与他们相同的字符
元字符
-
是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能
-
对元字符分类
- 边界符(表示位置、开始和结尾)
- 正常表达式中边界符(位置符)用来提示字符所处的位置,主要有两个字符
边界符 说明 ^ 表示匹配行首的文本(以谁开始) $ 表示匹配行尾的文本(以谁结束) console.log(/数/.test('数组'))//true console.log(/^数/.test('数组'))//false cosole.log(/组$/.test('数组'))//true //精确匹配 console.log(/^数$/.test('数'))//true
-
量词(表示重复次数)
- 量词用来 设定某个模式出现的次数
量词 说明 * 重复零次或更多次 + 重复一次或更多次 ? 重复零次或一次 {n} 重复n次 {n,} 重复n次或更多次 {n,m} 重复n次到m次
console.log(/a*/.test(''))//true console.log(/a*/.test('a'))//true console.log(/a*/.test('b'))//true
- 字符类(比如\d表示0~9)
-
[ ]匹配字符集合
- 后面的字符串只要包含abc中任意一个字符,都返回true
console.log(/[abc]/.test('andy'))//true console.log(/[abc]/.test('deth'))//false
- 使用连字符 - 表示一个范围
console.log(/^[a-z]$/.test('c'))//true console.log(/^[abc]$/.test('a'))//true console.log(/^[abc]$/.test('ab'))//false
- [a-z]表示a到z 26个英文字母都可以
- [a-zA-Z]表示大小写都可以
- [0-9]表示0~9的数字都可以
- 后面的字符串只要包含abc中任意一个字符,都返回true
-
[ ]里面加上^取反符号
- [^a-z]匹配除了小写字母以外的字符
- 注意要写到中括号里面
-
.匹配除换行符之外的任何单个字符
-
预定义:指的是某些常见模式的简写方式
-
- 边界符(表示位置、开始和结尾)
预定类 | 说明 |
---|---|
\d | 匹配0~9之间的任意数字,相当于[0-9] |
\D | 匹配所有0-9以外的字符,相当于[^0-9] |
\w | 匹配任意的字母、数字和下划线,相当于[A-Za-z0-9] |
\W | 除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9] |
\s | 匹配空格(包括换行符、制表符、空格符等),相当于[\t\r\n\v\f] |
\S | 匹配非空的字符,相当于[^\t\r\n\v\f] |
修饰符
- 修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等
- 语法
/表达式/修饰符
- i是单词ignore的缩写,正则匹配时字母不区分大小写
- g是单吃global的缩写,匹配所有满足正则表达式的结果
console.log(/a/i.test('a'))//true console.log(/a/i.test('A'))//true
- 替换replace
- 语法
字符串.replace(/正则表达式/,'替换的文本')
- 案例
<textarea name="" id="" cols="30" rows="10"></textarea> <button>发布</button> <div></div> <script> let btn = document.querySelector('button') let text = document.querySelector('textarea') let div = document.querySelector('div') btn.addEventListener('click',function(){ //过滤用户输入内容 只会过滤输入文本第一个相关词汇 div.innerHTML = text.value.replace(/香烟/,'**') //过滤用户输入全部内容 把所有匹配的词汇都过滤了 div.innerHTML = text.value.replace(/香烟|槟榔/g,'**') }) </script>