前端之勇闯DOM关
一、DOM简介
1.1什么是DOM
文档对象类型(Document Object Model,简称DOM),是W3C组织推荐的处理课扩展标记语言(HTML或者XML)的标准编程接口
W3C已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式
1.2DOM树
- 文档:一个页面就是一个文档,DOM中使用document 表示
- 元素:页面中的所有标签都是元素,DOM中使用element表示
- 节点:网页中所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示
DOM把以上所有内容看作是对象
二、获取元素
2.1如何获取页面元素
- 根据ID获取
- 根据标签名获取
- 通过HTML5新增的方法获取
- 特殊元素获取
2.2根据ID获取
使用getElementById()方法可以获取带有ID的对象
花花 var namer = document.getElementById('name'); console.log(namer);//花花 console.dir(namer);//div#name
- 因为我们文档页面从上往下加载,所以先得有标签,所以我们scrip写到标签的下面
- 参数:id是大小写敏感的字符串
- 返回的是一个元素对象
-
console.dir打印我们返回的元素对象,更好地查看里面的属性和方法
2.3根据标签名获取
使用getElementByTagName()方法可以返回带有知道标签名的对象的集合
- 1110
- 111
- 111
- 111
- 111
可以看见,是采用伪数组的形式存储的
所以也可以用数组的方法输出
console.log(lis[0]);
想要依次打印里面的元素可以采用遍历的方式
for (var i = 0; i
注意:
1.因为得到的是一个对象的集合,所以我们想要操作里面的元素就需要遍历
2.得到元素对象是动态的
3.如果页面只有一个li,返回的还是伪数组形式
4.如果页面中没有这个元素,返回的是空的伪数组的形式
获取某个元素(父元素) 内部所有指定标签的子元素
element.getElementsByTagName('标签名');
注意:父元素必须是单个对象(必须指明是哪一个元素对象),获取的时候不包括自己
例如:
var ul = document.getElementsByTagName('ul'); console.log(ol.getElementsByTagName('ol'));
此时将伪数组作为父元素,报错啦
要指定一个确定的元素
var ul = document.getElementsByTagName('ul'); console.log(ul[0].getElementsByTagName('ul'));
此时可以把ul里面所有li获取出来
但是这个方法还是有点麻烦,可以直接给ul一个id,根据id获取ul里面所有的li
2.4通过HTML5新增的方法获取
(1)根据类名返回元素对象集合
document.getElementsByClassName('类名');//根据类型名返回元素对象集合
例如
盒子1 盒子2
- 首页
- 产品
运行结果:
(2)根据指定选择器返回第一个元素对象
document.querySelector('选择器');//根据指定选择器返回第一个元素对象
例如:
var firstBox = document.querySelector('.box'); console.log(firstBox); var nav = document.querySelector('#nav'); console.log(nav); var firstli = document.querySelector('li'); console.log(firstli);
运行结果:
切记里面的选择器要加符号,.box #nav.....
(3)根据指定选择器返回所有对象
document.querySelectorAll('选择器');//根据指定选择器返回所有元素对象
例如:
var allBox = document.querySelectorAll('.box'); console.log(allBox);
运行结果:
2.5获取特殊元素(body,HTML)
(1)获取body元素
document.body//返回body元素对象
实际应用:
var bodyEle = document.body; console.log(bodyEle);
(2)获取html元素
document.documentElement//返回heml元素对象
实际应用:
var htmlEle = document.documentElement; console.log(htmlEle);
三、事件基础
3.1事件概述
JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为
简单理解:触发---响应机制
事件三要素:事件源,事件类型,事件处理程序
唐伯虎 //(1)事件源 事件:被触发的对象 谁:按钮 var btn = document.getElementById('btn'); //(2)事件类型 如何触发 什么事件 比如鼠标点击(onclick),还是鼠标经过,还是鼠标按下 //(3)事件处理程序 通过一个函数赋值的方式完成 btn.onclick = function () { alert('点秋香'); }
3.2执行事件的步骤
1.获取事件源
2.注册事件(绑定事件)
3.添加事件处理程序(采取函数赋值形式)
案例:点击123,输出我被选中了
123 //1.获取事件源 var xzl = document.querySelector('div'); //2.绑定事件 //div.onclick //3.添加事件处理程序 xzl.onclick = function () { alert('我被选中了'); }
3.3常见的鼠标事件
鼠标事件 触发条件 onclick 鼠标点击左键触发 onmouseover 鼠标经过触发 onmouseout 鼠标离开触发 onfocus 获得鼠标焦点触发 onblur 失去鼠标焦点触发 onmousemove 鼠标移动触发 onmouseup 鼠标弹起触发 onmousedown 鼠标按下触发 四、操作元素
4.1改变元素内容
element.innerText
从起始位置到终止位置的内容,但它除去html标签,同时空格和换行也会去掉
element.innerHTML
从起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行
案例:点击按钮,div的文字发生变化
显示时间 时间
1
var btn = document.querySelector('button'); var div = document.querySelector('div'); btn.onclick = function () { div.innerText = getDate(); } function getDate() { var date = new Date(); var year = date.getFullYear(); var month = date.getMonth() + 1; var day = date.getDate(); return year + '年' + month + '月' + day + '日'; }我们元素可以不用添加事件
var p = document.querySelector('p'); p.inner.Text = getDate();
这样的事件,刷新网页后会自动跳出所需内容
element.innerText和element.innerHTML区别
1.inner.Text不识别html标签 非标准 去除换行与空格
2.inner.HTML识别html标签 W3C标准 保留空格和换行
3.这两个属性是可读写的,可以获取元素里面的内容
4.2常用元素的属性操作
1.innerText、innerHTML 改变元素内容
2.src、href
3.id、alt、title
例如使用src
1 2
var but1 = document.getElementById('.1'); var but2 = document.getElementById('2'); var imgs = document.querySelector('img'); but2.onclick = function () { imgs.src = '10.png'; } but1.onclick = function () { imgs.src = 'https://blog.csdn.net/2401_88226934/article/details/9.png'; }
案例:分时显示不同图片,显示不同的问候语
上午好
var date = new Date(); var hour = date.getHours(); var img = document.querySelector('img'); var div = document.querySelector('div'); if (hour
4.3表达原始的属性操作
利用DOM可以操作如下表单元素的属性:
type,value,checked,selected,disabled
(1)value(表单里面的文字内容是通过value来修改的)
按钮 var btn = document.querySelector('button'); var input = document.querySelector('input'); btn.onclick = function () { input.value = '被点击了'; }
(2)disabled(让某个表单被禁用,不能再点击)
btn.disabled = true;
(3)type
input.type = '';
案例:仿京东显示密码
点击按钮将密码框切换为文本框,并可以查看密码明文
css部分
.box { position: relative; width: 400px; border-bottom: 1px solid #ccc; margin: 100px auto; } .box input { width: 370px; height: 30px; border: 0; outline: none; } .box img { top: 5px; left: 365px; position: absolute; width: 24px; }
HTML部分
JavaScript部分
var input = document.querySelector('input'); var img = document.querySelector('img'); var flag = 0; img.onclick = function () { if (flag == 0) { input.type = 'text'; img.src = 'display.png'; flag = 1; } else { input.type = 'password'; img.src = 'https://blog.csdn.net/2401_88226934/article/details/yincang.png'; flag = 0; } }
4.4样式属性操作
我们可以通过JS修改元素的大小、颜色、位置等样式
(1)行内样式操作
element.style
案例:点击盒子,改变背景以及宽度
css:
div { width: 200px; height: 200px; background-color: pink; }
HTML:
JavaScript:
var div = document.querySelector('div'); div.onclick = function () { this.style.backgroundColor = 'purple'; this.style.width = '250px'; }
注意:
1.JS里面的样式采取驼峰命名法,例如:fontSize、backgroundColor
2.JS修改style样式操作,产生的是行内样式,css权重比较高
案例:关闭二维码
css:
.box { position: relative; width: 200px; height: 200px; margin: 100px auto; } .box .ma { width: 180px; } .box p { position: absolute; top: -20px; left: -15px; width: 5px; }
HTML:
JS:
var fork = document.querySelector('p'); var box = document.querySelector('.box'); fork.onclick = function () { box.style.display = 'none'; }
案例:循环精灵图背景
可以用for循环设置一组元素的精灵图背景
css:
.box { width: 305px; height: 170px; margin: 200px auto; } .box li { float: left; list-style: none; width: 24px; height: 24px; margin: 15px; background: url(sprite.png); } .box li:hover { border: 1px solid red; }
HTML:
JavaScript:
var lis = document.querySelectorAll('li'); for (var i = 0; i
案例:显示隐藏文本内容
当鼠标点击文本框时,里面文字默认隐藏,当鼠标离开文本框时,文字显示
css:
input { color: #999; }
HTML:
JavaScript:
var text = document.querySelector('input'); text.onfocus = function () { if (this.value == '手机') { this.value = ''; } this.style.color = 'black'; } text.onblur = function () { if (this.value == '') { his.value = '手机'; } his.style.color = '#999'; }
(2)类名样式操作
element.ClassName
案例:使用className更改元素样式
css:
div { height: 50px; width: 50px; background-color: pink; } .change { background-color: purple; color: #fff; font-size: 25px; margin-top: 100px; }
HTML:
文本
JavaScript:
var div = document.querySelector('div'); div.onclick = function () { this.className = 'change'; }
注意:
1.如果样式修改较多,可以采取操作类名的方式更改元素样式
2.class因为是个保留字,隐藏使用className来操作元素类名属性
3.className会直接更改元素类名,会覆盖原先的类名
4.如果想要保留原先类名,可以用多类名选择器
this.className = 'first change';
案例:密码框格式提示错误信息
用户如果离开密码框。里面输入个数不是6-16,则提示错误信息,否则提示输入正确信息
css:
.register { margin: 200px 500px; } .ipt { height: 20px; } .message { display: inline-block; color: #999; font-size: 12px; padding-left: 20px; background: url(mess.png) no-repeat left center; } .wrong { color: red; background: url(wrong.png) no-repeat left center; } .right { color: green; background: url(right.png) no-repeat left center; }
HTML:
请输入6~16位密码
JavaScript:
var ipt = document.querySelector('input'); var p = document.querySelector('p'); ipt.onblur = function () { if (this.value.length 16) { p.className = 'message wrong'; p.innerHTML = '您输入的位数不正确,要求6~16位'; } else { p.className = 'message right'; p.innerHTML = '您输入的位数正确'; } }
4.5排他思想
案例:点击按钮变色,上一个按钮恢复原来颜色
HTML:
按钮1 按钮2 按钮3 按钮4 按钮5 按钮6
JavaScript:
var btns = document.querySelectorAll('button'); for (var i = 0; i
如果有一组元素,我们想要某一个元素实现某个样式,需要用到循环的排他思想算法
案例:百度换肤
css:
* { margin: 0; padding: 0; } body { background: url(https://blog.csdn.net/2401_88226934/article/details/3.png) no-repeat center top; } .baidu { overflow: hidden; margin: 100px auto; background-color: #fff width: 410px; padding-top: 3px; display: flex; justify-content: center; } .baidu li { list-style: none; } .baidu img { width: 100px; }
HTML:
JavaScript:
var imgs = document.querySelector('.baidu').querySelectorAll('img'); var body = document.querySelector('body'); for (var i = 0; i
案例:表格隔行变色
css:
table { border-collapse: collapse; border: 1px solid skyblue; margin: 100px auto; } th, td { border: 1px solid skyblue; } th { background-color: #4196c1; color: #fff; } .bg { background-color: #0ad5eb; }
HTML:
表头1 表头2 1 2 3 4 JavaScript:
var trs = document.querySelector('tbody').querySelectorAll('tr'); for (var i = 0; i
案例:表单全选取消全选
css:
table { border-collapse: collapse; border: 1px solid skyblue; margin: 100px auto; } th, td { border: 1px solid skyblue; } th { background-color: #4196c1; color: #fff; }
HTML:
表头1 表头2 1 2 3 4 JavaScript:
var j_cbAll = document.querySelector('#j_cbAll'); var j_tbs = document.querySelector('#j_tb').getElementsByTagName('input'); j_cbAll.onclick = function () { console.log(this.checked); for (var i = 0; i
4.6自定义属性的操作
(1)获取属性值
1.element.属性
var div = document.querySelector('div'); console.log(div.id);
2.element.getAttribute('属性')
console.log(div.getAttribute('id'));
区别:
1.element.属性 获取内置属性值(元素本来自带的属性)
2.element.getAttribute('属性') 主要获取自定义属性(我们程序员自定义的属性)
(2)设置属性值
1.element.属性 = '值' 设置内置属性值
div.id = 'test'; div.className = 'navs';
2.element.setAttribute('属性','值') 主要针对于自定义属性
div.setAttribute('id','test'); div.setAttribute('class','footer');
class特殊,这里写的就是class,不是className
(3) 移除属性
element.removeAttribute('属性')
div.removeAttribute('id');
案例:tab栏切换
css:
* { margin: 0; padding: 0; } ul { display: inline-block; } li { font-size: 20px; list-style: none; display: inline-block; padding: 5px; line-height: 20px; } .tab_list { width: 510px; background-color: #efecec; } .current { background-color: #ba7272; color: #fff; }
HTML:
- 商品介绍
- 规格与包装
- 售后与保障
- 商品评价
- 手机社区
JavaScript:
var tab_list = document.querySelector('.tab_list'); var lis = tab_list.querySelectorAll('li'); for (var i = 0; i
4.7H5自定义属性
自定义属性的目的:为了保存并使用数据,有些数据可以保存到页面中而不用保存到数据库中、
自定义属性通过getAttribute('属性')获取
有些自定义属性不容易判断是元素的内置属性还是自定义属性
(1)设置H5自定义属性
H5规定自定义属性data-开头作为属性名并且赋值
例如:
或者用JS设置:
element.setAttribute('data-index');
(2)获取H5自定义属性
1.兼容获取 element.getAttribute('data-index');
2.H5新增element.dataset.index 或者 element.dataset['index'] ie11才开始支持
dataset是一个集合,里面存放了所有以data开头的自定义属性
如果自定义属性比较长,使用getAttribute比较方便,使用dataset的话使用驼峰命名法,例如:
console.log(div.getAttribute('data-list-name'); console.log(div.dataset.listName);
五、节点操作
5.1节点概述
上面DOM树提过节点的概念,也就是页面所有内容全是节点
一般来讲,节点至少有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性
- 元素节点 nodeType值为1------------>我们主要操作的节点类型
- 属性节点 nodeType值为2
- 文本节点 nodeType值为3 (文本节点包含文字、空格、换行等)
5.2节点层级
(1)父节点
parentNode 得到的是离元素最近的节点(亲爸爸),如果找不到父元素返回null
在下面有父子关系的盒子中,要得到父元素:
x
原来的方法:
var erweima = document.querySelector('.erweima'); var box = document.querySelector('.box');
使用 父节点:
var erweima = document.querySelector('.erweima'); console.log(erweima.parentNode);
(2)子节点
1.childNodes
childNodes得到的所有子节点包含元素节点、文本节点等等
在下面有父子关系的盒子中,要得到子元素:
x x x x
原来的方法:
var box = document.querySelector('.box'); var erweima = box.querySelector('.erweima');
使用子节点:
var box = document.querySelector('.box'); console.log(box.childNodes);
如果只想获得里面的元素节点,则需专门处理:
var box = document.querySelector('.box'); for (var i = 0; i
2.parentNode .children
parentNode .children 非标准 获得所有的子元素节点
console.log(box.children);
3.parentNode.firstChild
parentNode.firstChild 获得子元素第一个节点,不管是文本节点还是元素节点
console.log(box.firstChild);
4.parentNode.lastChild
parentNode.larstChild 获得子元素最后一个节点,不管是文本节点还是元素节点
console.log(box.lastChild);
5.parentNode.firstElementChild
parentNode.firstElementChild 返回第一个子元素节点
console.log(box.firstElementChild);
6.parentNode.lastElementChild
parentNode.lastElementChild 返回最后一个子元素节点
console.log(box.lastElementChild);
注意:5和6有兼容性问题,IE9以上才支持
7.获得子元素第一个和最后一个节点的写法(开发中)
此方法无兼容性问题
console.log(box.children[0]); console.log(box.children[box.children.length - 1]);
案例:下拉菜单
css:
* { margin: 0; padding: 0; } a { display: inline-block; width: 69px; color: #000; text-decoration: none; } .nav { display: inline-block; width: 210px; text-align: center; } .nav ul { display: inline-block; } .nav>li { width: 65px; position: relative; } .under { display: none; position: absolute; top: 100%; left: 0; } .under li { width: 68px; border-collapse: collapse; border: 1px solid orange; } li { display: inline-block; list-style: none; } .nav>li a:hover { background-color: #ec040475; } .under li:hover { background-color: #f18e16ba; }
HTML:
- 微博
- 私信
- 评论
- @我
- 微博
- 私信
- 评论
- @我
- 微博
- 私信
- 评论
- @我
JavaScript:
var nav = document.querySelector('.nav'); var lis = nav.children; for (var i = 0; i
(3)兄弟节点
1.node.nextSibling
node.nextSibling返回当前元素的下一个兄弟节点,找不到则返回null,包含所有节点,元素节点、文本节点等
例如在:
1 2
使用 node.nextSibling,输出#text
var div = document.querySelector('div'); console.log(div.nextSibling);//#text
2.node.previousSibling
node.previousSibling返回当前元素的上一个兄弟节点,找不到则返回null,包含所有节点,元素节点、文本节点等
例如在:
1 2
使用 node.previousSibling,输出#text
var span = document.querySelector('span'); console.log(div.previousSibling);//#text
3.node.nextElementSibling
node.nextElementSibling返回当前元素的下一个兄弟节点,找不到则返回null
var div = document.querySelector('div'); console.log(div.nextElementSibling);
4.node.previousElementSibling
node.previousElementSibling返回当前元素的上一个兄弟节点,找不到则返回null
var span = document.querySelector('span'); console.log(div.previousElementSibling);
注意:3和4有兼容性问题,只有IE9以上才支持
可以自己封装一个兼容性函数
function getNextElementSibling(element) { var el = element; while (el = el.nextSibling) { if (el.nodeType == 1) { return el; } } return null; }
5.3创建节点
document.createElement('tagName');
因为原先不存在,根据需求生成的,又叫动态创建元素节点
5.4添加节点
node.appendChild(child);
(1)node.appendChild()
node.appendChild()将一个节点添加到指定父节点的末尾,类似于CSS里面after伪元素,又称为追加元素,类似于数组中的push
在一个ul里面添加li
var li=document.createElement('li'); var ul=document.querySelector('ul'); ul.appendChild(li);
(2) nodeinsertBefore()
nodeinsertBefore(child,指定元素)
var lili = document.createElement('li'); ul.insertBefore(lili,ul.children[0]);
案例:简单版发布留言案例
css:
li { color: plum; background-color: rgb(250, 217, 222); margin-bottom: 10px; } textarea { margin-top: 20px; margin-left: 40px; resize: none; border: 1px solid pink; border-radius: 5px; }
HTML:
发布
JavaScript:
var btn = document.querySelector('button'); var text = document.querySelector('textarea'); var ul = document.querySelector('ul'); btn.onclick = function () { if (text.value == '') { alert('您没有输入内容'); return false; } else { var li = document.createElement('li'); li.innerHTML = text.value; ul.insertBefore(li, ul.children[0]); } }
5.5删除节点
node.removeChild(child)方法从DOM中删除一个子节点,返回删除的节点
例如:
ul.removeChild(ul.children[0]);
案例:删除留言节点
css:
li { color: plum; background-color: rgb(250, 217, 222); margin-bottom: 10px; } li a { float: right; } textarea { margin-top: 20px; margin-left: 40px; resize: none; border: 1px solid pink; border-radius: 5px; }
HTML:
发布
JavaScript:
var btn = document.querySelector('button'); var text = document.querySelector('textarea'); var ul = document.querySelector('ul'); btn.onclick = function () { if (text.value == '') { alert('您没有输入内容'); return false; } else { var li = document.createElement('li'); li.innerHTML = text.value + "删除"; ul.insertBefore(li, ul.children[0]); var as = document.querySelectorAll('a'); for (var i = 0; i
5.6复制节点(克隆节点)
node.cloneNode()
1.如果括号参数为空或者是false,则是浅拷贝,只克隆节点本身,不克隆里面的子节点
2.如果括号参数为true,则是深拷贝,只克隆里面的内容
案例:动态生成表格
css:
thead { background: #bababa; } th { border: 1px solid rgb(150, 149, 149); padding-left: 20px; padding-right: 20px; } td { border: 1px solid rgb(150, 149, 149); text-align: center; }
HTML:
姓名 科目 成绩 操作 JavaScript:
var datas = [{ name: '魏璎珞', subject: 'JavaScript', score: 100 }, { name: '宏利', subject: 'JavaScript', score: 90 }, { name: '尹翼川', subject: 'JavaScript', score: 60 }] var tbody = document.querySelector('tbody'); for (var i = 0; i
5.7三种动态创建元素的区别
(1)document.write()
document.write直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
(2)document.innerHTML
document.innerHTML将内容写入某个DOM节点,不会导致页面全部重绘
innerHTML创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
(3)document.createElement()
createElement创建多个元素效率稍微低一点,但是结构更清晰
- 微博