DOM&BOM总结
BOM
Browser Object Model 浏览器对象模型
用于操控浏览器相关的内容(地址栏 前进 后退 版本...)
1.window
js的顶级对象
全局的变量会作为window的属性
全局的函数会作为window的方法
window.onresize
//监听浏览器的大小变化 如果变化了 会自动执行后面的回调函数
window.onresize=function(){
console.log(111)
}
window.onscroll
//监听浏览器的滚动 会触发的回调函数
window.onscroll=function(){
console.log(222)
}
2.history 历史记录***
// history 历史记录 ********
console.log(window.history)
console.log(history)//简写
history.back() //后退一页
history.forward() //前进一页
history.go() //任意前进或者后退 里面写数字 1前进一页 -2后退两页
3.location 地址栏 ****** **
console.log(window.location)
console.log(location)//简写
console.log(location.href) //当前的 url=》统一资源定位符
location.href = 'http://www.baidu.com' //修改url
console.log(location.protocol) //拿的是协议名
console.log(location.host) //拿的是主机名称和端口号
console.log(location.hostname) //拿的是主机名称
console.log(location.port) //拿的是端口号
console.log(location.pathname) //拿的是路径部分
console.log(location.search) //拿的是查询部分
console.log(location.hash) //那的是锚点部分
4.navigator 浏览器版本名称等
console.log(navigator.appName) //浏览器的名称(mdn已弃用,在任何浏览器该属性的值都是Netscape,此属性仅出于兼容性目的而保留)
console.log(navigator.appCodeName) //浏览器的内核 同上 Mozilla
console.log(navigator.appVersion) //浏览器的版本
DOM
1.事件
事件的三要素:
事件源(承受的这一方)
事件类型 点击 移入移出...
事件回调 放置你想要执行的功能 回调函数
//事件是可以重复执行的
2.修改元素的属性
2.1天生属性之普通属性
如src href id ... 元素对象本来就自带的属性
window.onload = function () {
var imgNode = document.getElementById('imgNode')
console.log(imgNode.scr = 'https://www.baidu.com') //修改天生属性之普通属性的值
// 如果一个元素的id属性存在 那么可以不用dom方法获取 直接使用id那个名字就可以了
btn.onclick = function () {
aNode.href = 'http://www.jd.com' //点击修改href属性值
pNode.id = 'ppppppp'//点击修改p元素的id属性值
}
2.2天生属性之特殊属性
特殊属性 checked disabled 如果属性和属性值同名 尽量用true和false表示
class 操作类名属性不可以用class 因为他是js中的一个关键字 你必须用className这个名字
如 p.class='pp' ×,p.className='pp' √
可以使用.语法 也可以使用[]语法 dom对象元素对象 本质也是对象
pNode.id = 'ppp'
pNode['id'] ='pppp'
#p.clssList 可以拿到一个元素的所有类名,p.classList.add('a'),p.classList.remove('a') 添加移出类名
2.3自定义属性
为了区分自定义属性和天生属性的区别,用p.dataset.attr='自定义属性' ,浏览器显示:data-attr='自定义属性'
pNode.getAttribute('class')//获取自定义属性,特殊的是其操作class不需要写为'className'
pNode.setAttribute('xxx', 'zzz')//修改自定义属性
3.获取DOM元素的方法
1.通过id名获取
document.getElementById('divNode') //id值唯一
2.通过标签名获取
document.getElementByTagName('div') //不管是多少div 都会返回一个伪数组
3.通过类名获取
document.getElementByClassName('divNodes') //不管是多少div 都会返回一个伪数组
4.通过css选择器获取
document.querySelector('#ulNode') //通过id选择器获取
document.querySelectorAll('.one')//返回为数组
4.操作元素内容
读:
内部没有其他元素:innerHTML可以拿到换行和空白以及文本,innerText只能文本(若设置隐藏,则读取不到)
内部有其他元素: innerHTML不光能拿到文本内容还可以拿到内部的标签, innerText只能拿到文本
改:
内外没有其他元素:两者一样都会替代原有的
内部有其他元素: innerHTML 可以让元素渲染到页面上;innerText 只能让内容渲染到页面上 元素当作普通文本对待
如:box.innerHTML = '<h1>哈哈哈</h1>' 会以h1的样式显示‘哈哈哈’,而innerText则是'<h1>哈哈哈</h1>'
textContent可以拿到隐藏元素的内容,其他与innerText一样
innerText拿不到隐藏元素的内容
5.操作元素样式
#js中操作的样式都是行内样式 确保优先级!!
window.onload = function () {
//获取元素节点
var btn = document.querySelector('#btn')
var box = document.querySelector('#box')
//添加事件
btn.onclick = function () {
//事件回调
box.style.width = '300px'
box.style.height = 300 + 'px'
box.style.backgroundColor = '#0ff' //-不符合变量写法,这里统一遇到改字母大写
//我试了下用background复合属性的写法也可以,颜色模式浏览器都解析成rgb()
}
6.排他、标志位等
//点击某个li 让这个li内容变呵呵 其他的变嘿嘿 练习 方法1
var liNodes = document.querySelectorAll('li') //获取所有li 一个伪数组
for (var i = 0; i < liNodes.length; i++) { //点击某个 说明可能每个都点击,那么全要访问到
liNodes[i].onclick = function () { //确定事件源和点击事件以及事件回调
for (var j = 0; j < liNodes.length; j++) { //排他思想就是先全部 再排它 所有再for
liNodes[j].innerHTML = '嘿嘿'
}
this.innerHTML = '呵呵' //在事件回调当中this指向你当前的事件源 这里不能直接用liNodes【i】去获取li了,因为i在点击前全部循环完了
}
}
方式二:
window.onload = function () {
var liNodes = document.querySelectorAll('li') //获取所有事件源,返回一个伪数组
for (i = 0; i < liNodes.length; i++) {
liNodes[i].index = i //给每一个li加一个index属性 用于记录i 是几,因为循环不等点击 会喀喀喀全执行,到时候下面的liNodes[i],都是4
//都用到了this,但是方向不一样,这里是通过对象加属性 来记录下标 调用属性
liNodes[i].onclick = function () {
for (j = 0; j < liNodes.length; j++) {
liNodes[j].className = ''
}
liNodes[this.index].className = 'changeRed'
}
}
}
````````````````````````````````````````````````````````````````````````````````````````````````````````````
2.二级菜单:
1.获取dom对象
var liNodes = document.querySelectorAll('.list>li')
var ulNodes = document.querySelectorAll('li ul')
// 2.给每个li绑定移入移出事件
for (var i = 0; i < liNodes.length; i++) {
// 给每个li对象添加index属性 属性值为下标 取下标的意义在于 li和li内部的ul用的下标是同一个
liNodes[i].index = i
liNodes[i].onmouseenter = function () {
// ulNodes[this.index] 就是咱们想显示的ul
ulNodes[this.index].style.opacity = 1
}
liNodes[i].onmouseleave = function () {
ulNodes[this.index].style.opacity = 0
}
}
````````````````````````````````````````````````````````````````````````````````````````````````````````````
3.幽灵按钮
//获取dom对象
var wrap = document.querySelector('#wrap')
var boxs = document.querySelectorAll('#wrap div')
//添加事件
wrap.onmouseover = function () {
boxs[0].style.width = '200px'
boxs[1].style.width = '200px'
this.style.backgroundColor = '#f0f'
this.style.color = '#fff'
}
wrap.onmouseout = function () {
boxs[0].style.width = '0'
boxs[1].style.width = '0'
this.style.backgroundColor = '#069A8E'
this.style.color = 'red'
}
7.事件相关
7.1事件对象
事件对象:
每个事件回调 都不是咱们自己调用 是系统帮你调用 那么系统调用得时候给你偷摸塞了个东西
每一个事件回调 所有跟这个事件回调相关的信息都在事件对象身上
inp.onkeyup = function (e) {
// e 就是事件对象 形参
console.log(e)
}
7.2鼠标事件
window.onload=function(){
var box = document.querySelector('#box')
// onclick 点击
// 如果说对某个dom对象绑定同一事件多次 最后的那一次会执行 覆盖
box.onclick=function(){
console.log('我是点击2')
}
box.onclick=function(){
console.log('我是点击1')
}
box.onclick=function(){
console.log('我是点击3')
}
// 移入移出 onmouseover onmouseout 成对使用
box.onmouseover=function(){
console.log('我是移入')
}
box.onmouseout=function(){
console.log('我是移出')
}
// 移入移出 onmouseenter onmouseleave 成对使用
box.onmouseenter=function(){
console.log('我是移入')
}
box.onmouseleave=function(){
console.log('我是移出')
}
#注意:enter leave这一对切换看不到 不能用这一对去做事件委派!!! 父子切换 不显示的
//时间对象兼容性处理
window.onload = function () {
var box = document.getElementById('box')
// 事件对象 每一个事件都会有各自的事件对象 系统给的
box.onclick = function (e) {
// 兼容性处理
e = e || window.event // 能拿到e就拿,拿不到用winddow.event
// e = event||window.event
// event = event||window.event
console.log(e) //低级浏览器不能通过形参拿到事件对象
console.log(window.event) //低级浏览器 事件对象在window身上的event属性
}
}
7.2.1鼠标事件练习
1.表格隔行变色
window.onload = function () {
var trNodes = document.querySelectorAll('tr')
//每行都要变颜色
for (var i = 0; i < trNodes.length; i++) {
//隔行变色 需要判断单双 取余判断
if (i % 2 == 0) {
trNodes[i].style.backgroundColor = '#0ff'
}
else {
trNodes[i].style.backgroundColor = '#f00'
}
}
}
--------------------------------------------------------------------
2.开关控制盒子变色
window.onload=function(){
var box = document.querySelector('.box')
var flag = true //用flag这个变量来模拟开关
box.onclick=function(){
if(flag){//true 蓝色变成红色
box.style.backgroundColor = 'red'
// 更改开关得状态
// flag = false
}else{//false 红色变成蓝色
box.style.backgroundColor = 'skyblue'
// 更改开关得状态
// flag = true
}
// 不管颜色变成哪个 if或者else之后得代码一定会执行
// 状态取反
flag = !flag
}
}
--------------------------------------------------------------------
3.开关控制风车停转
window.onload = function () {
var btn = document.querySelector('button')
var ulNode = document.querySelector('ul')
var flag = true
btn.onclick = function () {
if (flag) { //默认是true true代表正在转
ulNode.style.animationPlayState = 'paused'
} else { //false 停
ulNode.style.animationPlayState = 'running'
}
// 状态取反
flag = !flag
}
}
7.3键盘事件
onkeydown 键盘按下 //按键不抬起就会一致触发
onkeyup 键盘抬起 //只会执行一次 (常用)
*****************学键盘事件就是在学习区分是哪个键
场景:百度的搜索框 输入内容 自动联想
// 判断是不是回车抬起事件
inp.onkeyup = function (e) {
// e 就是事件对象 形参
var a = 0
if (e.keyCode == 13) {
console.log('回车抬起事件')
} else if (e.keyCode == 32) {
console.log('空格抬起事件')
}
console.log(e)
}
7.4焦点事件
onfocus 获取焦点
onblur 失去焦点
var inp = document.querySelector('input')
// onfocus 获取焦点
inp.onfocus = function () {
console.log('获取焦点')
}
// onblur 失去焦点
inp.onblur = function () {
console.log('失去焦点')
}
7.4.1焦点事件练习
// 当失去焦点的时候让input的背景颜色随机改变(变色龙)
window.onload = function () {
var inp = document.querySelector('input')
// 获取焦点
inp.onfocus = function () {
this.style.backgroundColor = 'skyblue'
this.style.color = 'cyan'
}
// 失去焦点
inp.onblur = function () {
// 这三个变量 给随机背景色用
var r1 = Math.floor(Math.random() * 256)
var g1 = Math.floor(Math.random() * 256)
var b1 = Math.floor(Math.random() * 256)
// 这三个变量 给随机的字体颜色去用
var r2 = Math.floor(Math.random() * 256)
var g2 = Math.floor(Math.random() * 256)
var b2 = Math.floor(Math.random() * 256)
// 拼串得时候 要注意 最好按我得方式来 不容易拼错
this.style.backgroundColor = 'rgb(' + r1 + ',' + g1 + ',' + b1 + ')' //除了变量 其他都是字符串
this.style.color = 'rgb(' + r2 + ',' + g2 + ',' + b2 + ')' //这里也可以改变r1,g1,b1的顺序 但我觉得不严谨
}
}
7.5案例
window.onload = function () {
var btns = document.querySelectorAll('button')
var inps = document.querySelectorAll('input')
// 全选的逻辑
btns[0].onclick = function () {
for (var i = 0; i < inps.length; i++) {
inps[i].checked = true
}
}
// 全不选的逻辑
btns[1].onclick = function () {
for (var i = 0; i < inps.length; i++) {
inps[i].checked = false
}
}
// 反选的逻辑
btns[2].onclick = function () {
for (var i = 0; i < inps.length; i++) {
#新的状态要依托于之前的状态 取反
inps[i].checked = !inps[i].checked
}
}
}
8.兼容性问题
浏览器的兼容性:
Chrome fireFox IE safari opera
浏览器分为高级浏览器和低级浏览器
以IE8为分水岭,包含IE8在内以下的就是低级浏览器
IE8以上和其它的都是高级浏览器
(兼容性处理将会越来越少)
window.onload = function () {
// 兼容性问题 了解即可 不用你刻意得去记
// getElementsByClassName 高级可以用 低级用不了
// querySelector 高级可以用 低级用不了
// querySelectorAll 高级可以用 低级用不了
var box = document.getElementById('box')//id名获取 ,高低都行
// var box1 = document.getElementsByClassName('content')//类名获取
var box2 = document.getElementsByTagName('div')//标签名获取 高低都行
// var box3 = document.querySelector('.content')//选择器获取
console.log(box)
// console.log(box1)
console.log(box2)
// console.log(box3)
}
#通过兼容性练习函数封装
innerText和innerHTML 高级浏览器和低级浏览器都可以用
textContent 只能高级浏览器去用
function clearContent(node, content) {
// 在读取内容
if (arguments.length == 1) { //arguments属性获取函数实际参数 低级浏览器是undefined 布尔值就是false
// return node.textContent ? node.textContent : node.innerText 优化1
return node.textContent || node.innerText //也可以这样写
//在设置内容
} else if (arguments.length == 2) {
node.textContent ? node.textContent = content : node.innerText = content
// (node.textContent || node.innerText )=content //这样写报错的,因为做左边是一个表达式的值,值赋值肯定不对的
}
}
9.节点 、元素
//节点在dom中的展示
nodeName(次要关注) nodeType(主要关注) nodeValue
元素节点 标签名大写 1 null
文本节点 #text 3 文本内容
注释节点 #comment 8 注释内容
//每一个换行都是是文本节点 text
1.子节点 childNodes(包括文本 元素 注释)
2.子元素节点 children(只拿子元素节点)
//父节点和父元素节点 出来的结果都是父元素节点
3.父节点 parentNode
4.父元素节点 parentElement
//特殊节点
document.documentElement 获取页面当中的html元素
document.body 获取页面当中的body元素
document.head 获取页面当中的head元素
//查找节点的其他方式
var liNode = document.getElementById('item') 获取这些节点的时候 只要名字带Element 低级浏览器全用不了(兼容性现在考虑的少)
// 父子关系
// childNodes children parentNode parentElement
// 第一个子节点 firstChild
console.log(list.firstChild)
// // 第一个子元素节点 firstElementChild
console.log(list.firstElementChild)
// // 最后一个子节点 lastChild
console.log(list.lastChild)
// // 最后一个子元素节点
console.log(list.lastElementChild)
// 兄弟关系
// 上一个兄弟节点 previousSibling
console.log(liNode.previousSibling)
// // 上一个兄弟元素节点 previousElementSibling
console.log(liNode.previousElementSibling)
// 下一个兄弟节点
console.log(liNode.nextSibling)
// 下一个兄弟元素节点
console.log(liNode.nextElementSibling)
``````````````````````````````````````````````````````````````````````````````````````````
//封装获取最后一个子元素节点
(获取这些节点的时候 只要名字带Element 低级浏览器全用不了)
var ulNode = document.getElementById('list')
// 封装函数返回某个节点的最后一个元素节点
function getElementLastChild(node) { //函数声明
// 区分开是低级还是高级
if (node.LastElementChild) {
return node.LastElementChild //高级浏览器 直角返回就好
} else {//低级
var result = node.lastChild//拿节点的最后一个节点
// 特殊处理 某个节点当中没有子元素节点
while (result !== null && result.nodeType !== 1) {//如果不是子元素节点 那么就取他的上一个兄弟节点再进来判断
result = result.previousSibling
}
return result
}
}
console.log(getElementLastChild(ulNode))
}
//重在练习函数封装 兼容性处理会越来越少了
10.添加节点的方式
<script>
window.onload = function () {
var pNode = document.getElementById('pp')
// 添加节点的三种方式
// 1. 基本不用 可以把里面的标签渲染到结构中 但是会覆盖我之前就渲染好的结构
document.write('<h2>我是内容</h2>')
// 2. innerHTML += 很少用
document.body.innerHTML = '<h2>我是第二种方式</h2>'
document.body.innerHTML += '<h2>我是第二种方式</h2>' 不覆盖
// 3. 常用 三个步骤 缺一不可 ************
// 3.1 创建dom对象
var divNode = document.createElement('div') //创建一个元素 传递的参数是你要创建的元素名字
// 3.2 给这个新创建的dom对象增加内容
divNode.innerHTML = '我是新创建的div'
// 3.3 把这个新创建的dom对象 放在dom树上 *******
document.documentElement.appendChild(divNode)//appendChild是dom对象身上的方法 可以再某个节点中(内部)末尾增加一个子节点
}
11.操作节点的方法
// 节点增删改 让父元素去使用的!!!
window.onload=function(){
// 增加节点 (末尾) 父元素调用
var list =document.querySelector('ul')
var liNode = document.createElement('li')
liNode.innerHTML = '星际穿越'
// list.appendChild(liNode)
var item = document.getElementById('item')
// 插入节点
// insertBefore 父元素调用 传参两个 第一个是你要加的节点 第二个是参照节点(新节点要加到哪个节点前面)
list.insertBefore(liNode,item)
// 替换节点
// replaceChild 父元素调用 第一个是你新节点 第二个是要被替换的节点
list.replaceChild(liNode,item)
// 删除节点
// removeChild 父元素调用 参数是你要删除的那个节点
list.removeChild(item)
// 删除ul
document.body.removeChild(list)
}
12.综合案例
str.trim() //trim是字符串的一个方法 去除掉左右两边的空白
str.trimLeft() //trim是字符串的一个方法 去除掉左边的空白
str.trimRight() //trim是字符串的一个方法 去除掉右边的空白
//动态添加歌曲
window.onload = function () {
// 1.获取input
var inp = document.querySelector('input')
// 7. 获取ul
var ulNode = document.querySelector('ul')
// 2.绑定键盘抬起事件
inp.onkeyup = function (event) {
// 3.判断是不是按的回车
if (event.keyCode == 13) {
//4.获取input的输入内容
var content = inp.value //content拿出来是字符串格式
// 10.有些用户可能输入了一些空白
if (content.trim()) { //走到这个判断里面的 一定是有输入内容的
// 5. 创建li标签
var liNode = document.createElement('li')
// 6.添加li的内容
liNode.innerHTML = content
// 12.每次只要创建了li 我就给他添加移入移出事件
liNode.onmouseenter = function () {
this.style.backgroundColor = 'red'
}
liNode.onmouseleave = function () {
this.style.backgroundColor = ''
}
// 8.把新建的li加入dom树当中
ulNode.appendChild(liNode)
} else {
alert('请输入你喜欢的歌曲')
}
// 不管是有美欧输入正确的歌曲名字 都要清空
inp.value = ''
}
}
}
13.DOM事件
DOM级别一共可以分为4个级别:DOM0级「通常把DOM1规范形成之前的叫做DOM0级」,DOM1级,DOM2级和 DOM3级,而DOM事件分为3个级别:DOM0级事件处理,DOM2级事件处理和DOM3级事件处理。如下图所示:
13.1 dom0事件绑定和解绑
//如果给某个dom对象 绑定多次同一事件 只会执行最后一次 后面对的覆盖前面的
box.onclick = function () {
console.log('点击1')
}
box.onclick = null //通常解绑一个dom对象的事件 咱们会赋值为null,但是并不是只有null可以 只要是让他断掉与函数的连接就可以!
13.2 dom2事件绑定和解绑
//dom2绑定事件,第三个参数默认false 代表冒泡,true捕获
box.addEventListener('click', function () {
console.log('dom2方式 点击1')
})
解绑事件 //解绑的时候传递的参数必须和绑定的参数一摸一样(留意第二个参数 回调函数)
function fn() {
console.log('dom2方式 点击4')
}
box.addEventListener('click', fn)
btn.onclick = function () {
box.removeEventListener('click', fn)
}
14.事件流
1)捕获事件流(网景) 最终很少用几乎不用
2)冒泡事件流(ie) 最终我们所用的事件传播都是冒泡
3)标准DOM事件流 //这个是我们现用的标准事件流,里面包含三个阶段: 有捕获 再去获取目标元素 最后冒泡,这个三个阶段当中的捕获和冒泡可以由程序员自己选择。但是通常情况我们都是使用默认 (冒泡);
14.1 dom0事件流
dom0当中事件流只有冒泡 没有捕获
冒泡是一个过程 从内向外 (从自身向外)
事件流(事件传播)是客观存在的 和事件监听一毛钱关系都没有 //(同一类型就会触发,并不是非要同一个,例如鼠标点击事件和鼠标按下事件)
14.2 dom2事件流
one.addEventListener('click', function () {
console.log('我是老大')
}, false)
/*
冒泡 由内向外依次传递
捕获 从外向内依次传递
标准事件流 三个阶段 捕获 目标 冒泡(用的多)
*/
14.3 阻止冒泡
function fn(e) {
// 阻止冒泡
console.log('我是老二')
// e.stopPropagation();
}
two.addEventListener('click', fn)
15.事件委派
事件委派: 是依衬于事件冒泡的 如果没有冒泡 就不能用事件委派,也叫事件委托 事件代理
15.1事件委派场景一:
// 每一个子元素都在做相同的事情
//案例:移入li 让li变色
window.onload = function () {
// 给这些子元素最近的那个父元素添加事件
var ulNode = document.querySelector('ul')
ulNode.onmouseover = function (e) {
// 事件流(事件传播)是客观存在的 和事件监听一毛钱关系都没有
// 移入li的时候 会冒泡到ul身上 触发ul的事件监听
// 需要找到具体那一个子元素 让他变色
// e.target 代表的是触发事件的最里面(内部)的那个元素
// e.target有可能拿到的是ul 也有可能拿到的是li
if (e.target.nodeName === 'LI') {
e.target.style.backgroundColor = 'aqua'
}
}
ulNode.onmouseout = function (e) {
if (e.target.nodeName === 'LI') {
e.target.style.backgroundColor = 'green'
}
}
}
15.2事件委派场景二:
//之前老的做的事情一样 然后会增加新的 想让新的也具备老的的功能
window.onload=function(){
// 事件委派的玩法
var btn = document.querySelector('button')
var ulNode = document.querySelector('ul')
btn.onclick=function(){
var liNode = document.createElement('li')
liNode.innerHTML='我是新的li'
ulNode.appendChild(liNode)
}
// 事件委派玩法 必须用over out
ulNode.onmouseover=function(e){
// console.log(e.target)
if(e.target.nodeName ==='LI'){
e.target.style.backgroundColor = 'pink'
}else if(e.target.nodeName ==='SPAN'){
e.target.parentNode.style.backgroundColor = 'pink'
}
}
ulNode.onmouseout=function(e){
if(e.target.nodeName ==='LI'){
e.target.style.backgroundColor = ''
}
}
}
16.相亲墙案例
window.onload = function () {
var inps = document.querySelectorAll('input')
var btn = document.querySelector('button')
var tbody = document.querySelector('tbody') //dom上是由tbody标签的
// 添加
btn.onclick = function () {
// 获取用户输入的姓名和特点
var name = inps[0].value
var trait = inps[1].value
// 判断用户输入的内容是不是正确的
if (name.trim() && trait.trim()) {
// 创建tr结构
var trNode = document.createElement('tr')
// 创建姓名的td
var tdNode = document.createElement('td')
tdNode.innerHTML = name
trNode.appendChild(tdNode)
// 创建特点的td
var tdNode = document.createElement('td')
tdNode.innerHTML = trait
trNode.appendChild(tdNode)
// 创建删除的td
var tdNode = document.createElement('td')
tdNode.innerHTML = '<a href="javascript:;">删除</a>'
trNode.appendChild(tdNode)
// 把咱们自己创建的tr放到tbody中 (树上)
tbody.appendChild(trNode)
} else {
alert('请输入你的姓名和特点')
}
inps[0].value = ''
inps[1].value = ''
}
// 删除
tbody.onclick = function (e) {
e = e || window.event
if (e.target.nodeName === 'A') {
// 找到这个a对应的那个tr 删除tr
console.log(e.target.parentNode.parentNode)
tbody.removeChild(e.target.parentNode.parentNode)
}
}
}
17.三种鼠标位置
clientX clientY 参照视口 来获取你鼠标的位置 常用
offsetX offsetY 参照自身元素的左上角 来获取你鼠标的位置
pageX pageY 参照页面的左上角 来获取你的鼠标位置
17.1鼠标跟随案例
window.onload = function () {
/*鼠标移动 给谁绑定?
body?html?一般不给这2个特殊的绑定事件,那么基于事件冒泡特性 我们可以给document绑定
*/
var img = document.querySelector('img') //获取img
document.onmousemove = function (e) { //事件绑定
// console.log(e.clientX)
//让图片始终跟着图片
e = e || window.event //兼容性处理
img.style.left = e.clientX + 'px' //设置水平方向定位
img.style.top = e.clientY + 'px' //设置垂直方向定位
}
}
18.定时器
18.1延时定时器
1.语法:setTimeout(回调函数,毫秒值)
分析:其实就是一个函数调用的表达式,不过参数是回调函数整体和毫秒,内置封装了,那么表达式的值就是定时器的id。从2开始往后排
执行过程:等到某个时间 去执行回调函数当中的代码块 一次!!!
返回值:每个定时器都会返回一个东西 这个东西就是定时器的id
#因为咱们之后可能在任意位置去清除定时器 所以一定要把定时器返回的id做为全局变量保存
// 或者在全局有个var id=null;然后定时器里的函数 id 不带var ,那么返回的id就操作了全局变量的id了
2.清除定时器
clearTimeout(id)
18.2循环定时器
语法:
setInterval(回调函数,毫秒值)
执行过程:
每隔一段时间(你赋予的) 都会去执行一次回调函数当中的代码块 无法确定执行多少次
类似死循环 但是和死循环不一样
定时器每个都会返回一个唯一的id 按照顺序依次排列
// 清除循环定时器
clearInterval(id)
18.3定时器有时候不准的问题(了解)
因为想要执行异步代码 必须执行完所有的同步代码
但是同步代码当中有可能执行了5s 那定时器的1s早就过了
18.4万年历练习
//万年历案例练习
/* 分析题意:实时年月日 时间(可见最小变换就是秒) 循环定时器 每间隔1s 就获取一次时间
*/
var h1Node = document.querySelector('h1') //获取元素节点
//封装一个实时时间函数
function getNowDateAndTime() {
var date = new Date()
var year = date.getFullYear()
var month = date.getMonth() + 1//月份默认0-11的
var day = date.getDate()
// var time = date.toLocaleDateString()2022/4/26
var time = date.toLocaleTimeString()
return '现在是' + year + '年' + month + '月' + day + '号 ' + time
}
//添加定时器
setInterval(function () {
var time = getNowDateAndTime()// 每间隔1s 就获取一次时间
h1Node.innerHTML = time //看着是秒变了 其实每一次都是整体变掉
}, 1000)
18.5阅读协议案例
var btn = document.querySelector('button')
num = 5
setInterval(function () {
if (num <= 1) { //不加判断 就一直减下去了
// btn.style.disabled = false //这里是改的属性 不要加style的
btn.disabled = false
btn.innerHTML = '确认'
} else {
num--
btn.innerHTML = '确认(' + num + ')'
}
}, 1000)
}
19.同步与异步
/js的代码有同步代码和异步代码
异步代码:定时器当中的回调函数 事件回调//不是所有的回调函数都是异步的 像数组方法当中的回调函数就不是异步的
程序 就是一个文件 静静的躺在你的硬盘(c盘 d盘)当中 静态的
进程 程序执行叫做进程 进程是动态的
进程 车间
线程 线程是进程的基本执行单位 工人
一个进程所有的任务都在线程当中去执行的 进程想要执行任务 必须的有线程
js是单线程(只有一个工人)
同步代码一定优先于异步代码执行 异步代码想要执行 必须等我所有的同步执行完才行
/*
执行过程:进程先执行第一行同步代码,碰到异步代码就放入管理模块(管理模块里也会分定时器管理模块 事件回调管理模块)中不执行,
继续执行后面的同步代码,直到同步代码执行完,有消息返回后,系统通知进程将异步代码拿出来放入 call queue 相应时间后执行 */
/*
执行过程:查资料发现,代码执行会有一个执行栈call stack,所有代码都在里面,从一开始执行,同步就执行,如果是事件回调就放模块管理 里面,模块管理 里面也会细分,如事件回调 定时回调函数等等,(如果是点击事件,点击后才会放入执行队列里面,call queue,定时回掉函数时间到了就放进去,按顺序)线程执行完所有同步代码后,会返回任务队列去执行队列里拿出来放入执行线程后面执行 。
事件循环(event loop)主线程重复的获得任务 执行任务 再获取任务,再执行
*/
20.元素的大小与位置
一共是有12个 讲六个 剩下六个是一样的
20.1元素的大小
clientWidth //盒子的宽+盒子的padding
offsetWidth //盒子的宽+盒子的padding+盒子的边框
scrollWidth
1. 内容(three)小于盒子(two) 拿的是盒子(two)的clientWidth
2. 内容(three)大于盒子(two) 拿的是内容的offsetWidth+内容一侧的外边距+盒子一侧的内边距
20.2元素的位置
clientLeft //拿的是盒子的左边框
clientTop //拿的是盒子的上边框
offsetLeft //拿的是盒子的偏移量(left) 不是一样要定位才行 参照点(视口 开启相对定位的父元素都可以)
//只要是定位的移动 就看定位移动的值就行;
scrollLeft //只有scrollLeft 可读可写
//内容往左侧滚动的距离 而不是滚动条滚动的距离!!!! 设置在有内容的元素上,才能溢出滚动
//不设置点击滚动的话,他打开会默认计算滚动位置了 一直是0
// two.scrollLeft = 70 //scrollLeft 设置的时候注意不要加px
21.浏览器的默认行为
//例如点击a标签会刷新页面,这就是默认行为
window.onload = function () {
var aNode = document.querySelector('a')
aNode.onclick = function (e) {
// 阻止默认行为 需要用到事件对象
e.preventDefault()
}
}
22.案例练习
1.导航跟随案例
var viewH = document.documentElement.clientHeight//获取视口高度 clientHeight就是获取盒子的高和上下padding
var nav = document.querySelector('.nav') //获取div dom元素
//获取 滚动距离 是body页面的滚动距离
//绑定页面滚动事件
window.onscroll = function () {
// 有些浏览器认为页面滚动的距离是html的 有些认为是body的
// 兼容去拿滚动距离
var disT = document.documentElement.scrollTop || document.body.scrollTop
if (disT > viewH) {
nav.style.position = 'fixed' //写的样式是字符串 不要忘记加引号
//nav.style.position = 'absolute'//绝对定位默认参照根元素 可这里不行? 固定定位时相对页面整体内容定位的,而绝对定位默认是视口
//那这里视口已经和页面整体内容不一样了
nav.style.left = 0
nav.style.top = 0
} else nav.style.position = 'static';
}
2.盒子来回移动
var box = document.querySelector('#box')//获取元素对象
var dis = 3
setInterval(function () {
var eleX = box.offsetLeft //获取起始位置的偏移量
var lastX = eleX + dis //获取结束位置的偏移量
//加入判断 不然盒子一直向右走
if (lastX > document.documentElement.clientWidth - box.offsetWidth) { //判断盒子结束位置距离是否大于视口宽度减去盒子本身宽度
lastX = document.documentElement.clientWidth - box.offsetWidth //到还有一个盒子宽的距离停下来
dis = -3 //往回走
}
// else {
// dis = 3 // 这样写的话会一直左右一步来回走;因为大于就相等,那么小于等于就往前走,又大了又退 就一直循环了
// }
else if (lastX < 0) {//要有个明确的判断,锁定左边临界值
lastX = 0 //走的距离 可能不能刚好走完这么完美 可能最后一超了,还是当小的时候 就给他lastX初始到0比较好
dis = 3 //往右走
}
box.style.left = lastX + 'px'
}, 16)
3.系统滚动条的控制
/*
overflow: scroll; overflow: hidden;
body单独scroll document的 了解
html单独scroll document的 了解
body scroll html hidden 开启的滚动条是body自己的 了解
body hidden html scroll 开启的滚动条是document的 了解
body scroll html scroll body的滚动条开启了 document的滚动条也开启了 了解
*/
# body hidden html hidden 关闭了系统滚动条 熟记!!!
html,body{
height:100%;//更有说服力,只有内容超出了才会被隐藏或滚动条,若不设置,body和html的高度是由内容撑开的,body内容永远不会溢出了。
overflow:hidden;
}
4.拖拽完整版
// 事件冒泡
// 事件委派
// 一
// 1.拖拽元素很快 鼠标出来了
// 计算机计算的速度跟不上你移动的速度
// 2.出来之后移动鼠标 元素不跟鼠标动
// 你给box添加的移动事件
// 解决:不给box绑定移动了 给document绑定移动
// 3.出来之后 抬起鼠标(document身上抬起的) 再移入元素 跟着我又动了
// 没有触发box的抬起事件 所以没有解绑box的移动事件
// 解决:不给box绑定抬起了 给document绑定抬起事件
// 二
// 点击元素 crtr+a 选中文本 拖拽文本 抬起元素会立马跑过来
// 这是因为浏览器有默认行为
window.onload = function () {
// 元素最终的位置 = 元素的起始位置 + 鼠标前后的距离差
var box = document.querySelector('div')
var imgNode = document.querySelector('img')
// 绑定按下事件
box.onmousedown = function (e) {
e = e || window.event
// 需要box自身偏移的位置
var eleX = box.offsetLeft
var eleY = box.offsetTop
// 需要鼠标按下的这个位置
var startX = e.clientX
var startY = e.clientY
// 移动事件得写在按下时间里面 因为是在按下得时候去移动的
document.onmousemove = function (e) {
e = e || window.event
// 要鼠标移动之后的位置
var endX = e.clientX
var endY = e.clientY
// 求鼠标移动前后的距离差
var disX = endX - startX
var disY = endY - startY
// 元素最终位置
var lastX = eleX + disX
var lastY = eleY + disY
// 边界值判断 在把这个值设置到left top之前
// 水平距离边界值
if (lastX > document.documentElement.clientWidth - box.offsetWidth - 50) { //右边界
lastX = document.documentElement.clientWidth - box.offsetWidth
} else if (lastX < 50) { //左边界
lastX = 0
}
// 垂直距离的边界值
if (lastY > document.documentElement.clientHeight - box.offsetHeight - 50) { //下边界
lastY = document.documentElement.clientHeight - box.offsetHeight
} else if (lastY < 50) { //上边界
lastY = 0
}
// 元素动起来
box.style.left = lastX + 'px'
box.style.top = lastY + 'px'
// 碰撞效果
var boxL = lastX + box.offsetWidth
// getBoundingClientRect() 会返回这个dom对象在视口的位置 值是一个对象
// console.log(imgNode.getBoundingClientRect(),'imgNode.getBoundingClientRect()')
var imgL = imgNode.getBoundingClientRect().left
var boxT = lastY + box.offsetHeight
var imgT = imgNode.getBoundingClientRect().top
var boxR = lastX
var imgR = imgNode.getBoundingClientRect().left + imgNode.offsetWidth
var boxB = lastY
var imgB = imgNode.getBoundingClientRect().top + imgNode.offsetHeight
if (boxL < imgL || boxT < imgT || boxR > imgR || boxB > imgB) { //碰不到
imgNode.src = './img/1.jpg'
} else { //碰到
imgNode.src = './img/2.jpg'
}
}
// 绑定抬起事件
document.onmouseup = function () {
// 抬起的时候 不能再让他移动了 解绑移动事件
// 最好把抬起事件也解绑掉
document.onmousemove = document.onmouseup = null
}
// 清除浏览器的默认行为
e.preventDefault()
}
}
#可以将拖拽设为模板复用
5.滚轮事件
<div id="box"></div>
<!-- 滚动滚轮 改变某个元素得高度 -->
<script>
window.onload=function(){
var box =document.querySelector('#box')
// onmousewheel滚轮事件
// 学习滚轮事件 要知道究竟是往上滚 还是往下滚
box.onmousewheel=function(e){
// console.log('滚轮滚动了')
// 往上滚还是往下滚看e.wheelDelta大于0还是小于0
if(e.wheelDelta>0){ //往上滚
box.style.height = box.offsetHeight -10+'px'
}else if(e.wheelDelta<0){ //往下滚
box.style.height = box.offsetHeight +10+'px'
}
}
}
6.自定义滚动条+带内容+滚轮事件
//绝对定位是相对于浏览器窗口而言的或者说内容?,会随着滚动条移动而移动
//固定定位是相对于屏幕内网页窗口而言或者说视口?,滚动条移动他不动
window.onload = function () {
// 元素最终的位置 = 元素的起始位置 + 鼠标前后的距离差
var box = document.querySelector('#scrollin')
var content = document.querySelector('#content')
// 模拟内容
for (var i = 0; i < 400; i++) {
content.innerHTML += i + '</br>'
}
// 自定义滚动条的万能比例:
// 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块的滚动距离 / 内容的滚动距离
// 滑块的高度不能写死了 得根据内容发生变化 内容多 滑块小 内容少滑块大
// 求比例
var scale = document.documentElement.clientHeight / content.offsetHeight
var boxHeight = document.documentElement.clientHeight * scale
box.style.height = boxHeight + 'px'
// 滚轮逻辑
// 给document添加滚轮事件
document.onmousewheel = function (e) {
e = e || window.event
if (e.wheelDelta > 0) { //往上滚
// 滑块动
// 最新得滑块得位置
var scrollinDis = box.offsetTop - 10
// 上边界判断
if (scrollinDis < 0) {
scrollinDis = 0
}
box.style.top = scrollinDis + 'px'
// 内容也得动
// 自定义滚动条的万能比例:
// 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块的滚动距离 / 内容的滚动距离
content.style.top = -scrollinDis / scale + 'px' //注意内容是负值
} else if (e.wheelDelta < 0) { //往下滚
// 滑块动
var scrollinDis = box.offsetTop + 10
// 下边界判断
if (scrollinDis > document.documentElement.clientHeight - box.offsetHeight) {
scrollinDis = document.documentElement.clientHeight - box.offsetHeight
}
box.style.top = scrollinDis + 'px'
// 内容也得动
content.style.top = -scrollinDis / scale + 'px' //注意内容是负值
}
}
// 绑定按下事件
box.onmousedown = function (e) {
e = e || window.event
// 需要box自身偏移的位置
var eleY = box.offsetTop
// 需要鼠标按下的这个位置
var startY = e.clientY
// 移动事件得写在按下时间里面 因为是在按下得时候去移动的
document.onmousemove = function (e) {
e = e || window.event
// 要鼠标移动之后的位置
var endY = e.clientY
// 求鼠标移动前后的距离差
var disY = endY - startY
// 元素最终位置
var lastY = eleY + disY
// 边界值判断 在把这个值设置到left top之前
if (lastY > document.documentElement.clientHeight - box.offsetHeight) { //下边界
lastY = document.documentElement.clientHeight - box.offsetHeight
} else if (lastY < 0) { //上边界
lastY = 0
}
// 自定义滚动条的万能比例:
// 滑块的高度 / 滑槽的高度 = 滑槽的高度 / 内容的高度 = 滑块的滚动距离 / 内容的滚动距离
// 内容滚动距离 别忘给content定位 别忘是负值!!!!
content.style.top = -lastY / scale + 'px'
// 元素动起来
box.style.top = lastY + 'px'
}
// 绑定抬起事件
document.onmouseup = function () {
// 抬起的时候 不能再让他移动了 解绑移动事件
// 最好把抬起事件也解绑掉
document.onmousemove = document.onmouseup = null
}
// 清除浏览器的默认行为
e.preventDefault()
}
}
7.轮播图完整版
1.轮播图-点击按钮动起来(封装版)
2.轮播图-无缝轮播
3.轮播图-小圆点变色
4.轮播图-小圆点点击
5.轮播图-定时器叠加
6.轮播图-定时器自动轮播
// transition
// 1. 没有办法去跟踪到中间状态的变化
// 2. 过渡他只能应用在有具体数据的属性上
window.onload = function(){
var wrap = document.querySelector('.wrap')
var boxs = document.querySelectorAll('.wrap>div')
var list = document.querySelector('.list')
var liNodes = document.querySelectorAll('.dots li')
var timeAll = 600 //点一次移动一张图片的时间 总时间
var stepTime = 20 //每走一步需要的时间
var id = null
var isMove = false //这个变量去控制你的轮播图有没有动
var autoLoopId = null
// 移入最外面的wrap这个div 让箭头显示出来
wrap.onmouseover=function(){
boxs[0].style.opacity = '1'
boxs[1].style.opacity = '1'
// 移入 清除轮播图自动轮播得定时器
clearInterval(autoLoopId)
}
// 移出最外面的wrap这个div 让箭头隐藏出来
wrap.onmouseout=function(){
boxs[0].style.opacity = '0'
boxs[1].style.opacity = '0'
autoLoop()
}
// 点击右边按钮的逻辑
boxs[1].onclick = function(){
move(true)
}
function autoLoop(){
// 自动轮播
autoLoopId = setInterval(function(){
move(true)
},2000)
}
// 页面一打开就得轮播 默认让他执行一次
autoLoop()
// 小圆点点击
for(var i =0;i<liNodes.length;i++){
liNodes[i].index =i
liNodes[i].onclick=function(){
// this.index+1*-600 图片下标等于小圆点下标+1 图片下标*-600 就是要去得那个位置
// 可以拿到小圆点下标 反推图片下标 推出可以拿到ul最终得位置
move((this.index+1)*-600)
}
// 点击左边按钮的逻辑
boxs[0].onclick = function(){
move(false)
}
function move(flag){
// 第一次ismove是false 不会return
// 第二次ismove是true 不会往下走了 因为碰到了return
if(isMove){
return
}
isMove = true
if(typeof flag =='boolean'){ //说明是点的左右按钮
if(flag){ //为真证明点的是右边按钮
var disX = -600 //移动的距离差
}else{ //为假证明点的是左边按钮
var disX = 600 //移动的距离差
}
}else{ //点的小圆点
// 求距离差
var disX = flag - list.offsetLeft //最终距离 - ul得初始距离
}
var startX = list.offsetLeft //ul初始位置
var lastX = startX + disX //最终距离
// list.style.left = lastX +'px'
// 这样直接设置的话叫做瞬变轮播图
// 咱们不做这样的 慢慢的让你到下一张 到了下一张停下来
// 计算每步走的距离
var stepDis = disX/(timeAll/stepTime) // 路程/总步数 总步数==所有时间/每步所需要的时间
id = setInterval(function(){
// ul的起始位置
var startX = list.offsetLeft
// 每次都会累加走
var left = startX+stepDis
if(left==lastX){ //判断走到位置了 不要往后走了 停下来 清定时器
clearInterval(id)
//
if(left==-3600){
left = -600
}else if(left == 0){
left=-3000
}
isMove = false
}
list.style.left = left +'px'
},stepTime)
// 小圆点变色的逻辑
for(var i =0;i<liNodes.length;i++){
liNodes[i].className = ''
}
// 要找对应的小圆点下标
// 得通过图片得下标 图片下标-1就是小圆点下标
// 图片下标 ==> 就是你最终移动得那个距离 (-2400 -1800) c除以-600(每个图片宽度600)
// index 小圆点下标
var index = lastX/-600 -1
if(index>4){
index = 0
}else if(index<0){
index = 4
}
liNodes[index].className = 'check'
}
}
\