提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、DOM节点
1.DOM节点
// DOM 的节点我们一般分为常用的三大类 元素节点/ 文本节点/ 属性节点
1、元素节点
// 我们通过 getElementBy... 获取到的都是元素节点
2、属性节点
//我们通过getAttribute 获取的就是元素的属性节点
3、文本节点
// 我们通过 innerText 获取到的就是元素的文本节点
2.获取节点的方式
// childNodes 属性 vs children
childNodes 所有节点
children 所有元素
// firstChild 和 firstElementChild
firstChild 第一个节点
firstElementChild 第一个元素节点
// lastChild 和 lastElementChild
lastChild 最后一个节点
lastElementChild 最后一个元素节点
// previousSibling 和 previousElementSibling
previousSibling 上一个兄弟节点
previousElementSibling 上一个兄弟元素节点
// nextSibling 和 nextElementSibling
previousSibling 下一个兄弟节点
previousElementSibling 下一个兄弟元素节点
// parentNode 和 parentElement 父节点
// getAttribute 属性节点重点
box.getAttribute("index") 获取box里面的index属性节点
box.getAttributes 获取box里面所有的属性节点
box.getAttributes[0] 获取box里面所有的第一个属性节点
3.节点操作
创建节点:createElement
var odiv = document.createElement("div")
odiv.className="aaa"
odiv.innerHTML="我是新创建的节点"
插入节点:appendChild
box.appendChild(odiv) 直接在box子节点下最后面插入odiv节点
box.insertBefore(odiv,child) 在child节点前插入odiv节点
替换节点:replaceChild(新节点,老节点)
var odiv2=document.createElement("div")
odiv2.innerHTML="222"
box.replaceChild(odiv2,child)
克隆节点 :cloneNode(true) 默认false 不克隆后代;true 克隆后代
var oCloneBox=box.cloneNode(true)
console.log(oCloneBox)
oCloneBox.id="box2"
document.body.appendChild(oCloneBox)
<body>
<div id="box">
<div id="child">1111</div>
</div>
<script>
var odiv = document.createElement("div")
odiv.innerHTML = "我是新创建的节点"
//插入节点
box.appendChild(odiv)
</script>
</body>
<body>
<ul id="list"></ul>
<script>
var arr=[111,2222,3333,4444]
for (var i=0;i<arr.length;i++){
var oli=document.createElement("li") //创建节点
oli.innerHTML=arr[i] // 节点赋值
var obutton=document.createElement("button") //创建按钮
obutton.innerHTML="删除" // 节点赋值
obutton.onclick=handler // 绑定事件
list.appendChild(oli) //插入节点
oli.appendChild(obutton) //插入节点
}
function handler(){
this.parentNode.remove() //获取父节点,移除所有子节点包含自己
}
</script>
4.节点属性
可以通过 .nodeType 查找节点属性值(如1代表元素节点 2属性节点 3文本节点)
<body>
<div id="box">
<div>111</div>
</div>
<script>
var obox = document.querySelector(".box")
console.log(obox.childNodes)
for(var i=0;i<obox.childNodes.length;i++){
// console.log(obox.childNodes[i].nodeType)
if(obox.childNodes[i].nodeType===1){
console.log(obox.childNodes[i])
}
}
</script>
</body>
二、获取元素尺寸和元素偏移量
1.获取元素尺寸
offsetWidth 和 offsetheight
offsetwidth:获取的是元素 内容+padding+border的宽度
offsetheight:获取的是元素 内容+padding+border的高度
clientWidth 和 clientheight
clientwidth:获取的是元素 内容+padding的宽度
clientheight:获取的是元素 内容+padding的高度
//注意
1.单位 数字
2.box-sizing 没有影响计算方式
3.display:none 拿不到值节点前插入odiv节点
2.元素偏移量
offsetLeft 和 offsetTop
参考点:是定位父级;如果父级元素都没有定位,偏移量相当于body
clientLeft 和 clientTop就是左边框或上边框的值
可视窗口的尺寸
window.innerwidth 和Window.innerHeight 包含滚动条的宽度
document.documentElement.clientWidth 不包含滚动条的宽度
3.懒加载
renderHTML(arr1)
function renderHTML(arr){
//list.innerHTML +=arr.map(function(item){
// return`<li> </li>`}).join("")
for(var i=0;i<arr.length;i++){
var oli =document.createElement("li")
oli.innerHTML=`<img src="${arr[i].url} alt=""> <h3>${arr[i].name}</h3>`
list.appendChild(oli)
}
}
inLoading=false
window.onscroll=function(){
var listHeight=list.offsetHeight
var listTop=list.offsetTop
var scrollTop=document.documentElement.scrollTop||document.body.scrollTop
var windowHeight=document.documentElement.clientHeight
if(isLoading)return
if((listHeight+listTop)-Math.round(windowHeight+scrollTop)<50){
console.log("到底了")
isloading=true
setTimeout(function(){
renderHTML(arr2)
isLoading=false},1000)
}
}
三、DOM事件
1.初识事件
事件
一个事件由什么东西组成
1、触发谁的事件:事件源
2、触发什么事件:事件类型
3、触发以后做什么:事件处理函数
如:
var oDiv=document.queryselector("div")
oDiv.οnclick=function(){}
// oDiv 就是这个事件的事件源
// onclick 就是这个事件的类型
// function(){} 这个事件的处理函数
*每当我们点击div的时候,就会执行事件函数内部的代码
*每点击一次,就会执行一次事件处理函数(如果有多个事件函数,后面的会覆盖前面的)
//dom2 绑定多个事件处理函数 按照顺序执行(兼容性 低版本的浏览器不支持 如IE:6/7/8)
box2.addEventListener("click",function(){ })
低版本:box2.attachEvent("onclick",function(){ })
2.事件解绑
代码1如下:
<body>
<button id="btn">抽奖</button>
<script>
btn.onclick=function(){
console.log("谢谢惠顾")
this.disabled="disabled"}
</script>
</body>
//这个是在前端直接禁用,可以直接删除"disabled"代码重新点击"抽奖"
代码2如下:
<body>
<button id="btn">抽奖</button>
<script>
btn.onclick=function(){
console.log("谢谢惠顾")
this.onclick=null}
</script>
</body>
// dom节点.onclick=null 赋值空
代码3如下:
<body>
<button id="btn">抽奖</button>
<script>
function handler(){
console.log("谢谢惠顾")
this.removeEventListener("click",handler)
}
btn.addEventListener("click",handler)
</script>
</body>
//btn.removeEventListener("click",handler)移除掉函数
3.事件类型
常用事件类型
//鼠标事件 click单击鼠标
dbclick 双击鼠标
contextmenu 右键单击
mousedown 鼠标按下
mousemove 鼠标移动
mouseup 鼠标抬起
//移入移出 mouseover mouseout (放在子元素上也会触发)
//移入移除 mouseenter mouseleave (放在子元素上不会触发)
//键盘事件 onkeydown 按下键盘
onkeyup 抬起键盘
如:
<body>
<input type="text" id="username">
<script>
//window,document,输入框 input
uername.onkeydown = function(){
console.log("按下键盘")
}
</script>
</body>
//浏览器事件 load 页面全部加载完毕
scroll 浏览器滚动的时候触发
//表单事件 change 表单内容改变事件(获取焦点、失去焦点的对比里面的内容不一样才会触发)
input 表单内容输入事件 (内容不一样)
submit 表单提交事件
reset 表单重置事件
focus 获取焦点 // blur 失去焦点
//触摸事件 touchstart 开始触摸
touchmove 触摸移动的时候
touchend 结束触摸
4.事件对象
事件对象:你触发一个点击事件的时候,你点在那个位置了,坐标是多少
你触发一个键盘事件的时候,你按的是哪个按钮
代码如下:
<body>
<input type="text" id="username">
<div id="box"></div>
<script>
box.ononkeyup=function(evt){
console.log(evt)
}
//打印形参,里面有个keyCode值代表键盘上的键位,13代表回车键
username.onkeyup = function(evt){
console.log(evt.keyCode)
if(evt.keyCode===13){
console.log("创建节点")
}
}
</script>
</body>
5.事件对象--鼠标事件
鼠标对象事件
<body>
<div id="box"></div>
<script>
box.onclick = function (evt){
console.log(evt.clientX,evt.clientY)
}
// clientX clientY 距离浏览器可视窗口的左上角的坐标
// pageX pageY 距离文档页面左上角的坐标
// offsetX offsetY 距离触发元素的左上角的坐标值
</script>
</body>
6.案例--鼠标跟随
代码如下:
<style>
*{margin:0;padding: 0}
#box{width: 100px;height: 100px;background-color: yellow}
body{width: 2000px;height: 2000px}
#box p{width: 300px;
height: 300px;
background-color:red ;
position: absolute;
top:100px;
left: 100px;
display: none;
/* pointer-events: none; 穿透,鼠标会跟着p标签
}
</style>
</head>
<body>
<div id="box">
kerwin的头像
<p>
kerwin的介绍
</p>
</div>
<script>
box.onmouseover = function (){
this.firstElementChild.style.display="block"
}
box.onmouseout = function (){
this.firstElementChild.style.display="none"
}
box.onmousemove = function (evt){
console.log(evt.offsetX,evt.offsetY )
this.firstElementChild.style.left = evt.offsetX+10+"px"
this.firstElementChild.style.top = evt.offsetY+10+"px"
}
//clientX clientY 距离浏览器可视窗口的左上角的坐标
</script>
</body>
7.案例--鼠标拖拽
代码如下:
head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{margin:0;padding: 0}
#box{width: 100px;
height: 100px;
background-color: yellow;
position: absolute;
left:100px;
top:100px;
}
body{width: 2000px;height: 2000px}
</style>
</head>
<body>
<div id="box">
</div>
<script>
box.onmousedown =function (){
document.onmousemove =function (evt){
//.log("move")
var x=evt.clientX-box.offsetWidth/2
var y=evt.clientY-box.offsetHeight/2
if(y<=0) y=0
if(x<=0) x=0
var a=document.documentElement.clientWidth-box.offsetWidth
var b=document.documentElement.clientHeight-box.offsetHeight
if(x>=a) x=a
if(y>=b) y=b
box.style.left=x+"px"
box.style.top=y+"px"
}
}
box.onmouseup = function (){
console.log("up")
document.onmousemove=null
}
</script>
</body>
8.DOM事件流
子标签的事件会触发父标签的事件(事件会往上传递)
标准事件流:
捕获:window--document--html--body--outer--center--inner
目标:inner
冒泡:inner--cente--outer--body--html--document--window
点击inner上的事件,会往上触发center。。。等事件(默认情况,只在冒泡的时候触发)
9.阻止事件传播
evt.stopPropagation()阻止事件传播(兼容版本 IE版本:evt.cancelBubble=true 实现阻止)
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul id="list"></ul>
<script>
var arr=[111,2222,3333,4444]
for (var i=0;i<arr.length;i++){
var oli=document.createElement("li")
oli.innerHTML=arr[i]
var obutton=document.createElement("button")
obutton.innerHTML="删除"
obutton.onclick=handler
oli.appendChild(obutton)
oli.onclick=function (){
location.href="http://www.baidu.com"
}
list.appendChild(oli)
}
function handler(evt){
this.parentNode.remove()
evt.stopPropagation()
}
</script>
</body>
</html>
10.阻止默认行为
代码如下:return false 和 evt.preventDefault()
dom1:
myform.onsubmit =function(){
console.log("submit","校验表单内容")
reture false //阻止表单提交
}
dom2:
document.addEventListener("contextmenu" ,function (evt){
evt.preventDefault()
})
11.案例--自定义右键菜单
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{margin:0;padding:0 }
li{list-style: none}
#box{width: 50px;height: 100px;background-color: #76818c;
border:1px solid black;
display: none;
position: absolute}
ul li:hover{background-color: #3ca5f6}
</style>
</head>
<body>
<ul id="box">
<li>111</li>
<li>222</li>
<li>333</li>
</ul>
<script>
document.addEventListener("contextmenu" ,function (evt){
console.log("右键")
evt.preventDefault()
box.style.display="block"
var x=evt.clientX
var y=evt.clientY
var a=document.documentElement.clientWidth-box.offsetWidth
var b=document.documentElement.clientHeight-box.offsetHeight
if(x>=a) x=a
if(y>=b) y=b
box.style.left=x+"px"
box.style.top=y+"px"
})
document.onmouseup=function (){
box.style.display="none"
}
</script>
</body>
</html>
12.事件委托
事件委托
//就是把我要做的事情委托给别人来做
//因为我们的冒泡机制,点击子元素的时候,也会同步触发父元素的相同事件
//所以我们就可以把子元素的事情委托给父元素来做
target
// target 这个属性就是事件对象里面的属性,表示你点击的目标
//当你触发点击事件的时候,你点击在哪个元素上,target就是哪个元素
// 这个target也不兼容,在IE下使用 srcElement
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ou1=document.querySelector("ul")
ou1.addEventListener("click",function(e){
//console.log("我是ul的点击事件,我被触发了")
e=e||e.srcElement
var target=e.target||e.srcElement
console.log(target)
})
</script>
<body>
//减少多个函数的绑定的性能损耗
//动态添加li,也会有事件处理(指定元素“BUTTON”才会触发)
list.onclick = function(evt){
//console.log(evt.target.nodeName)
if(evt.target.nodeName==="BUTTON"){
evt.target.parentNode.remove()
}
}
上个例子自定义右键菜单,也可以用target来实现 li 里面的函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{margin:0;padding:0 }
li{list-style: none}
#box{width: 50px;height: 100px;background-color: #76818c;
border:1px solid black;
display: none;
position: absolute}
ul li:hover{background-color: #3ca5f6}
</style>
</head>
<body>
<ul id="box">
<li class="aaa">111</li>
<li class="bbb">222</li>
<li class="ccc">333</li>
</ul>
<script>
document.addEventListener("contextmenu" ,function (evt){
// console.log("右键")
evt.preventDefault()
box.style.display="block"
var x=evt.clientX
var y=evt.clientY
var a=document.documentElement.clientWidth-box.offsetWidth
var b=document.documentElement.clientHeight-box.offsetHeight
if(x>=a) x=a
if(y>=b) y=b
box.style.left=x+"px"
box.style.top=y+"px"
})
document.onmouseup=function (){
box.style.display="none"
}
box.addEventListener("click",function (evt){
// console.log(evt.target)
target=evt.target||evt.srcElement
if(target.className==="aaa"){
console.log("1")
}
if(target.className==="bbb"){
console.log("2")
}
if(target.className==="ccc"){
console.log("3")
}
})
</script>
</body>
</html>
四、正则表达式
/abc/ 表示必须包含abc连在一起的
1、基本元字符
1 \d 一位数字(0-9)( / \d\d / 包含2位数字)
如:var reg= / \d /
console.log(reg.test("abc")) // 返回 false
console.log(reg.test("123")) // 返回 true (123为一个数字)
2 \D 包含一位非数字 ( / \D\D / 必须包含2位非数字)
如:var reg= / \D /
console.log(reg.test("123abc")) // 返回 true
console.log(reg.test("123")) // 返回 false
3 \s 包含一位空格 ( 空格 缩进 换行)
如:var reg= / \s /
console.log(reg.test("12 3abc")) // 返回 true
console.log(reg.test("12\n3")) // 返回 true (\n换行符)
console.log(reg.test("123abc")) // 返回 false
4 \S 包含一位非空格 ( 非空白)
如:var reg= / \S /
console.log(reg.test("12 bc")) // 返回 true
console.log(reg.test(" \n\n ")) // 返回 false (\n换行符)
console.log(reg.test(" ")) // 返回 false
5 \w 包含一位字母 数字 下划线( / \w\w / 包含2位字母 数字下划线)
如:var reg= / \w /
console.log(reg.test("1—")) // 返回 true
console.log(reg.test("12aab ")) // 返回 true
console.log(reg.test("&*")) // 返回 false
6 \W 包含一位非字母 数字 下划线
如:var reg= / \w /
console.log(reg.test("1—")) // 返回 false
console.log(reg.test("12aab ")) // 返回 false
console.log(reg.test("&*")) // 返回 true
7 . 任意内容 (\n换行不算)
如:var reg= / \w /
console.log(reg.test("1\n—")) // 返回 true
console.log(reg.test("\n")) // 返回 false
console.log(reg.test("&*")) // 返回 true
8 . \ 转义字符 //1.2 2.3 通过 \ 把 . 转义成普通字符
如:var reg= / \d \.\d/
console.log(reg.test("1.2")) // 返回 true
console.log(reg.test("1a2)) // 返回 false
2、边界符
1 ^ 第一位
如:var reg= /^ \d / (第一位必须是数字)
console.log(reg.test("abc123")) // 返回 false
console.log(reg.test("123abc")) // 返回 true (第一位为数字)
2 $ 最后一位
如:var reg= / \d$ / (最后一位必须是数字)
console.log(reg.test("123abc")) // 返回 false
console.log(reg.test("abc123")) // 返回 true (最后一位为数字)
3、限定符
1 * 0~多次
如:var reg= /\d* /
console.log(reg.test("abc123")) // 返回 true
console.log(reg.test("123abc")) // 返回 true
2 + 1~多次
如:var reg= / \d+ / (包含至少1位数字)
console.log(reg.test("abc")) // 返回 false
console.log(reg.test("abc1")) // 返回 true
3 ? 0~1次
如:var reg= / \d?/
console.log(reg.test("abc")) // 返回 true
console.log(reg.test("abc1")) // 返回 true
4 {n} 指定次数 ( {n,} 表示大于等于n次 {n,5}表示大于等于n 小于等于5)
/abc{2}/ 表示必须包含abcc( {}只匹配最近的一位字符)
如:var reg= / \d{3}/ (出现3次数字)
console.log(reg.test("abc")) // 返回 false
console.log(reg.test("ab12")) // 返回 false
console.log(reg.test("abc123")) // 返回 true
4、特殊字符
1 () 把字符括起来表示一个整体
如:var reg= /(abc){2}/ (表示包含abcabc)
console.log(reg.test("abc123")) // 返回 false
console.log(reg.test("abcabc123")) // 返回 true
2 | 或
如:var reg= / a|b / (包含a或b)
console.log(reg.test("ac")) // 返回 true
console.log(reg.test("cb1")) // 返回 true
如:var reg= / abc|def|xyz/ (表示abc、def、xyz整体中的一个)
如:var reg= / (abc|def)/ (表示abc或加上d、e、f中的任意)
console.log(reg.test("ab")) // 返回 false
onsole.log(reg.test("abc")) // 返回 true
console.log(reg.test("abcef")) // 返回 true
3 [ ] 代表1个
如:var reg= / [abcdef]/ (表示abcdef中的任意1位)
onsole.log(reg.test("xyz")) // 返回 false
console.log(reg.test("axyz")) // 返回 true
如:var reg= /[abcdef]{3,5}/ (出现3~5次任意字符)
console.log(reg.test("abc")) // 返回 true
console.log(reg.test("ab12")) // 返回 false
[a-zA-Z0-9_] 等价 \w
[0-9] 等价 \d
[^abc] 取反,表示有1个不在abc里面的任意字符
如:var reg= /[^abc]/
console.log(reg.test("a")) // 返回 false
console.log(reg.test("abz")) // 返回 true (z在abc里面)
5、捕获 exec
如:var reg= /\d{3}/ (表示捕获3个数字)
console.log(reg.exec("abc123aaa")) // 返回 123
console.log(reg.test("abcabc")) // 返回 null
如:var datestr="time is 2029-01-01 12:20:20"
var reg= /\d{4}-\d{1,2}-\d{1,2}/ (表示捕获时间2029-01-01)
var newdatestr=reg.exec(datestr)
// console.log(newdatestr[0]) // 返回 2029-01-01
console.log(newdatestr[0].split("-").join("/")) // 返回 2029/01/01 (split分割)
6、标识符 g i
g 全局表示符 i 不分字母大小写
如:var datestr="time is from2029-01-01 12:20:20 to 2029-11-11 12:20:20"
var reg= /\d{4}-\d{1,2}-\d{1,2}/ g
var newdatestr1=reg.exec(datestr) // 只能捕获时间2029-01-01
console.log(newdatestr1[0]) // 返回 2029-01-01
var newdatestr2=reg.exec(datestr) //捕获下个时间2029-11-11
console.log(newdatestr2[0]) // 返回 2029-11-11)
7、贪婪
如:var reg= /\d{1,4}/ (贪婪)
console.log(reg.exec("abc12345aaa")) // 返回 1234
如:var reg= /\d{1,4}?/ (?非贪婪)
console.log(reg.exec("abc12345aaa")) // 返回 1
8、正则与字符串方法
// 正则.test(字符串)
// 正则.exec(字符串)
// 字符串.replace替换 search查找一个字符 match匹配拿到一个字符
//replace
如:var reg= "adefaea"
var newreg=reg.replace("a","*")
console.log(newreg) // 返回 *defaea
var newreg=reg.replace(/a/g,"*")
console.log(newreg) // 返回 *def*e*
//search
如:var reg= "adefaea"
var newreg=reg.search("d")
console.log(newreg) // 返回 1
var newreg=reg.search(/a/g)
console.log(newreg) // // 返回 0
//match 捕获内容
如:var reg= "adefaea"
var newreg=reg.match("ad")
console.log(newreg) // 返回 ad
如:var datestr="time is from2029-01-01 12:20:20 to 2029-11-11 12:20:20"
var newdatestr=datestr.match(/\d{4}-\d{1,2}-\d{1,2}/ g)
console.log(newdatestr) // 返回 ['2029-01-01','2029-11-11']
案例
<body>
<form>
<input type="text">
</label>
<p>
<span>弱</span>
<span>中</span>
<span>强</span>
</p>
</form>
<script>
var ospan=document.querySelector("span")
var oinput=document.querySelector("input")
var reg1 = /\d/
var reg2 = /[a-z]/i
var reg3 = /[~!@#$%^&*()_+?":><]/
oinput.oninput=function (evt){
console.log(this.value)
//console.log(evt.target.value)
var level = 0
if(reg1.test(this.value)) level++
if(reg2.test(this.value)) level++
if(reg3.test(this.value)) level++
//console.log(level)
for (var i=0;i<ospan.length;i++){
if(i<level){
ospan[i].classList.add("active")
}
}
}
</script>
</body>
五、this指向
1.this 关键字(谁调用我,this就指向谁)
// 全局
//console.log(this) // window
function test(){
console.log(this)}
window.test() // window
// 对象
<script>
var obj = {
name:"kerwin",
test:function (){
console.log("111",this) //this指向obj
}
}
obj.test()
</script>
setInterval(function (){
console.log(111,this)
},2000) //this指向window
// 事件绑定的this
box.onclick=function (){
console.log(this)
} //this 指向box节点
2.改变this指向
// call或apply 执行函数,并改变this执行为函数的第一个参数
//call支持多个参数;apply两个参数,第二个参数是一个数组
<script>
var obj1= {
name:"kerwin1",
test:function (){
console.log("test1",this.name)
}
}
var obj2= {
name:"kerwin2",
test:function (){
console.log("test2",this.name)
}
}
obj1.test.call(obj2) //test1 kerwin2 (this指向obj2)
// obj1.test.apply(obj2)
</script>
// bind 改变this指向为函数第一个参数,不会自动执行函数
var fun1= obj1.getName.bind(obj2)
console.log(fun1)}
fun1() // 指向obj2
// oDiv 就是这个事件的事件源
// onclick 就是这个事件的类型