js进阶-WebAPIs-DOM
一、Web APIs
1、 Web APIs与JS基础关联性
JS基础阶段:
-
我们学习的是ECMAscript标准规定的基本语法
-
要求同学们掌握Js基础语法
-
只学习基本语法,做不了常用的网页交互效果
-
目的是为了Js后面的课程打基础、做铺垫
Web APls阶段:
-
web APIs是w3c组织的标准
-
web APIs 我们主要学习DoM和BOM
-
web APIs 是我们Js 所独有的部分
-
我们主要学习页面交互功能
-
需要使用Js 基础的课程内容做基础
-
Js 基础学习ECMAscript 基础语法为后面作铺垫,web APIs是Js 的应用,大量使用Js 基础语法做交互效果
2、 DOM
2.1 简介
文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口
2.2 获取元素
因为文档页面从上往下加载,因此先得有标签,所以script要写到标签下面
2.2.1 根据ID获取
document.getElementById()
返回的是一个元素对象
<div id="time">2019-9-9</div> <script> // 1.因为我们文档页面从上往下加载,所以得先有标签,所以script写在标签下面 // 2.get 获得 element 元素 by 通过 驼峰命名法 // 3.参数 id是大小写敏感的字符串 // 4.返回的是一个元素对象 var timer = document.getElementById('time'); console.log(timer); // 5. console.dir 打印我们的元素对象,更好的查看里面的属性和方法 console.dir(timer); </script>
2.2.2 根据标签名获取
doucument.getElementsByTagName('标签名');
返回的是获取过来元素对象的集合 以伪数组的形式存储
<ul> <li>知否知否,应是等你好久1</li> <li>知否知否,应是等你好久2</li> <li>知否知否,应是等你好久3</li> <li>知否知否,应是等你好久4</li> <li>知否知否,应是等你好久5</li> </ul> <script> // 1.返回的是获取过来元素对象的集合 以伪数组的形式存储 var lis = document.getElementsByTagName('li'); console.log(lis); console.log(lis[0]); // 2.依次打印,遍历 for (var i = 0; i < lis.length; i++) { console.log(lis[i]); } // 3.如果页面中只有 1 个 li,返回的还是伪数组的形式 // 4.如果页面中没有这个元素,返回的是空伪数组 </script>
还可以根据标签名获取某个元素(父元素)内部所有指定标签名的子元素,获取的时候不包括父元素自己
父元素必须是单个指定元素
element(某个元素).getElementsByTagName('标签名')
<ul> <li>知否知否,应是等你好久1</li> <li>知否知否,应是等你好久2</li> <li>知否知否,应是等你好久3</li> <li>知否知否,应是等你好久4</li> <li>知否知否,应是等你好久5</li> </ul> <ol id="ol"> <li>生僻字1</li> <li>生僻字2</li> <li>生僻字3</li> <li>生僻字4</li> <li>生僻字5</li> </ol> <script> var a = document.getElementsByTagName('ol');//将所有的ol都找出来,形成一个伪数组 console.log(a); console.log(a[0].getElementsByTagName('li'));//在父元素中查找li,在伪数组中选取父类 </script>
也可以根据id实现
var a = document.getElementById('ol'); console.log(ol.getElementsByTagName('li'));
2.2.3 通过HTML5新增的元素
- 根据类名返回元素对象合集 :
document.getElementsByClassName('类名');
<div class="box">盒子1</div> <div class="box">盒子2</div> <div id="nav"></div> <script> var boxs = document.getElementsByClassName('box'); console.log(boxs); </script>
- 根据指定选择器返回第一个元素对象
document.querySelector('选择器')
var firstb = document.querySelector('.box') console.log(firstb); var navs = document.querySelector('#nav')//也可以用来选择id名 console.log(navs); //也可以选择标签,只能得到第一个对象
- 返回指定选择器的所有元素对象集合
document.querySelectorAll('选择器')
var allb = document.querySelectorAll('.box') console.log(allb);
2.2.4 获取特殊标签
-
获取body元素 返回body元素对象
document.body;
-
获取html元素 返回html元素对象
document.documentElement;
2.3 事件基础
-
JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。
-
简单理解: 触发— 响应机制。
-
网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。
2.3.1 事件三要素
-
事件源(谁)
-
事件类型(什么事件)
-
事件处理程序(做什么)
<script> // 点击一个按钮,弹出对话框 // 1. 事件是有三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素 //(1) 事件源 事件被触发的对象 谁 按钮 var btn = document.getElementById('btn'); //(2) 事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下 //(3) 事件处理程序 通过一个函数赋值的方式 完成 btn.onclick = function() { alert('秋香'); } </script>
2.3.2 执行事件的步骤
-
获取事件源
-
注册事件(绑定事件)
-
添加事件处理程序(采取函数赋值形式)
2.3.3 鼠标事件
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover | 鼠标经过触发 |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
2.4 操作元素
2.4.1 改变元素内容
element.innerText
——非标准 (从起始位置到终止位置的内容,不识别html标签(里面的标签会直接显示)、空格和换行)
<button>123</button> <div>某个时间</div> <p>112233</p> <script> //获取元素 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 dates = date.getDate(); var arr = ['周日', '周一', '周二', '周三', '周四', '周五', '周六']; var day = date.getDay(); return '今天是' + year + '年' + month + '月' + dates + '日 ' + arr[day]; } //元素可以不用添加事件 var p = document.querySelector('p') p.innerText = getDate();
element.innerHTML
——W3C推荐 (从起始位置到终止位置的内容,但它识别html标签,同时保留空格和换行)
var p = document.querySelector('p') p.innerHTML = '<strong>今天是</strong>' + getDate();
2.4.2 常用元素的属性操作
<button class="ldh">刘德华</button> <button class="zxy">张学友</button><br> <img src="imges/京东广告右.jpg" alt="" title="刘德华"> <script> var ldh = document.querySelector('.ldh');//注意这里不能用getElementsByClassName,他返回的是数组,不能用于添加事件 var zxy = document.querySelector('.zxy'); var img = document.querySelector('img'); zxy.onclick = function () { img.src = 'imges/京东广告左.jpg'; img.title = '张学友' } ldh.onclick = function () { img.src = 'imges/京东广告右.jpg'; img.title = '刘德华' </script>
根据时间显示问候语和图片案例:
<img src="imges/s.png" alt=""> <div>上午好</div> <script> var img = document.querySelector('img'); var div = document.querySelector('div'); var date = new Date(); var h = date.getHours(); if (h < 12) { img.src = 'imges/s.png'; div.innerHTML = '上午好'; } else if (h < 18) { img.src = 'imges/x.png'; div.innerHTML = '下午好'; } else { img.src = 'imges/w.png'; div.innerHTML = '晚上好'; } </script>
2.4.3 修改表单属性
-
利用DOM可以操作如下表单元素的属性:
type, value, checked, selected, disabled -
注:表单里面的值通过修改value值来修改的
input.value = "xxx"; input.type = "xxx"; input.checked = "xxx"; input.selected = true / false; input.disabled = true / false;//当为true时,禁用 this.disabled=true;//this指向调用者
例:密码的可见与不可见
<div> <input type="password" value=""><br> <label for=""> <img src="imges/不可见.jpg" alt=""> </label> </div> <button>登录</button> <script> var pas = document.querySelector('input'); var img = document.querySelector('img'); var flag = 0; img.onclick = function () { if (flag == 0) { pas.type = 'text'; img.src = 'imges/可见.jpg' flag = 1; } else { pas.type = 'password'; img.src = 'imges/不可见.jpg' flag = 0; } } </script>
2.4.4 样式属性操作
1)element.style— 行内样式操作
div.style.backgroundColor = 'pink'; div.style.width = '250px';
- JS里面的样式(中间有'-')采取驼峰命名法,比如 fontSize ,backgroundColor
- JS 修改 style 样式操作 ,产生的是行内样式,CSS权重比较高
例:隐藏二维码
<div> <img src="imges/chahao.jpg" alt="" width="20px" class="chahao"> <img src="imges/erweima.webp" alt="" class="erweima"> </div> <script> var del = document.querySelector('.chahao'); var div = document.querySelector('div');//注意这里,隐藏的是div,因此div也需要声明 del.onclick = function () { div.style.display = 'none';//display 使用小写即可 } </script>
循环精灵图 backgroundPosition 位置为负值
<!-- 循环精灵图 --> <style> ul li { background-image: url(imges/sprite.png); background-repeat: no-repeat; } </style> <ul> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> <script> var lis = document.querySelectorAll('li'); for (var i = 0; i < lis.length; i++) { var index = 44 * i;//索引号*两张图纵坐标的间距=精灵图的y坐标 lis[i].style.backgroundPosition = '0 -' + index + 'px'; } </script>
显示隐藏文本框内容
首先需要两个新事件,获得焦点onfocus,失去焦点onblur
<input type="text" value="输入"> <script> var btn = document.querySelector('input'); //获取焦点事件 btn.onfocus = function () {//光标在输入框内 if (btn.value === '输入') {//文本框内是原字符,才变为空 btn.value = ''; } btn.style.color = '#333' } //失去焦点事件 btn.onblur = function () { if (btn.value === '') {//文本框里没有内容时,才复原 btn.value = '输入'; } btn.style.color = '#999' } </script>
2) element.className— 类名样式操作
this.className = '新类名';
- className 会直接更改元素的类名,会覆盖原先的类名
this.className = '旧类名 新类名';
原先的类名也保留了
<style> div { width: 100px; height: 100px; color: beige; font-size: 16px; background-color: blueviolet; } /* 更改后的样式 */ .change { width: 120px; height: 120px; color: aqua; font-size: 14px; background-color: blue; } </style> <div>盒子</div> <script> var divs = document.querySelector('div'); divs.onclick = function () { divs.className = ('change');//使div当前的类名改为change } </script>
.dui { display: inline-block; color: green; } .cuo { color: red; } <div> <input type="password" value=""> <p class="dui">!密码长度为6~16个字符</p> </div> <script> var pwd = document.querySelector('input'); var text = document.querySelector('p'); pwd.onblur = function () { if (pwd.value.length < 6) {//判断输入密码长度 text.innerHTML = '× 密码过短 应不小于6个字符'//要注意这里的对象名不是标签名,都写错好几次了!!! text.className = 'dui cuo' } else if (pwd.value.length > 16) { text.innerHTML = '× 密码过长 应不大于16字符' text.className = 'dui cuo' } else { text.innerHTML = '√' text.className = 'dui' } } </script>
2.4.5 排他思想
-
所有元素全部清除样式
-
给当前的元素设置样式
<button>按钮1</button> <button>按钮2</button> <button>按钮3</button> <button>按钮4</button> <button>按钮5</button> <button>按钮6</button> <script> var btn = document.getElementsByTagName('button'); for (var i = 0; i < btn.length; i++) { btn[i].onclick = function () { for (var i = 0; i < btn.length; i++) {//先将所有颜色都变为默认 btn[i].style.backgroundColor = '';//这里是在for循环内,用this来指代不了 } this.style.backgroundColor = 'pink';//this指向btn[i] } //这里我最开始用的是失焦事件,也可以实现,但本节重点讲解排他算法 /* btn[i].onblur = function () { this.style.backgroundColor = '';//颜色变为默认 } */ } </script>
例:点击更换背景
body { background: url() no-repeat; background-size: 100%; } <ul class="pifu"> <li><img src="imges/壁纸1.webp" alt="" height="60px"></li> <li><img src="imges/壁纸2.webp" alt="" height="60px"></li> <li><img src="imges/壁纸3.webp" alt="" height="60px"></li> <li><img src="imges/壁纸4.webp" alt="" height="60px"></li> </ul> <script> var btn = document.querySelector('.pifu').querySelectorAll('img');//将类名为pifu的ul里的img全部选取出来 for (var i = 0; i < btn.length; i++) { btn[i].onclick = function () { document.body.style.backgroundImage = 'url(' + this.src + ')'; //this.src指鼠标点击的图片的路径 } } </script>
2.4.6 表格隔行变色
鼠标事件:
- 鼠标经过onmouseover
- 鼠标离开onmouseout
<style> table { width: 800px; margin: 100px auto; border-collapse: collapse; /*边框合并*/ font-size: 14px; text-align: center; } thead { background-color: rgb(137, 183, 255); } tr { height: 30px; } tbody td { border-bottom: 1px solid #d7d7d7; } </style> </head> <body> <table> <thead> <tr> <th>代码</th> <th>名称</th> <th>最新公布净值</th> <th>累计净值</th> <th>前单位净值</th> <th>净值增长率</th> </tr> </thead> <tbody> <tr> <td>003526</td> <td>农银金穗3个月定期开放债券</td> <td>1.075</td> <td>1.079</td> <td>1.074</td> <td>+0.047%</td> </tr> <tr> <td>003526</td> <td>农银金穗3个月定期开放债券</td> <td>1.075</td> <td>1.079</td> <td>1.074</td> <td>+0.047%</td> </tr> <tr> <td>003526</td> <td>农银金穗3个月定期开放债券</td> <td>1.075</td> <td>1.079</td> <td>1.074</td> <td>+0.047%</td> </tr> <tr> <td>003526</td> <td>农银金穗3个月定期开放债券</td> <td>1.075</td> <td>1.079</td> <td>1.074</td> <td>+0.047%</td> </tr> </tbody> </table> <script> var tbs = document.querySelector('tbody').querySelectorAll('tr'); for (var i = 0; i < tbs.length; i++) { tbs[i].onmouseover = function () { this.style.backgroundColor = 'pink'; } tbs[i].onmouseout = function () { this.style.backgroundColor = ''; } } </script>
2.4.7 全选和取消
<style> table { width: 200px; margin: 100px auto; text-align: center; border-collapse: collapse; } tr { height: 35px; background-color: rgba(234, 234, 234); } th { background-color: rgb(137, 183, 255); border: 1px solid rgb(215, 215, 215); } td { border: 1px solid rgb(192, 191, 191); font-size: 14px; } </style> </head> <body> <table> <thead> <tr> <th><input type="checkbox" id="cbAll"></th> <th>商品</th> <th>价格</th> </tr> </thead> <tbody> <tr> <td><input type="checkbox"></td> <td>桃子</td> <td>12元/斤</td> </tr> <tr> <td><input type="checkbox"></td> <td>油泼面</td> <td>10元</td> </tr> <tr> <td><input type="checkbox"></td> <td>唇膏</td> <td>9.9元</td> </tr> </tbody> </table> <script> var cball = document.querySelector('#cbAll'); var cb = document.querySelector('tbody').querySelectorAll('input'); //经过行变色,前提是tb不设置背景颜色 var trs = document.querySelector('tbody').querySelectorAll('tr'); for (var i = 0; i < trs.length; i++) { trs[i].onmouseover = function () { this.style.backgroundColor = 'white'; } trs[i].onmouseout = function () { this.style.backgroundColor = ''; } } //一键全选,取消 cball.onclick = function () { for (i = 0; i < cb.length; i++) { cb[i].checked = this.checked; //将总复选框的值赋值给下面各个复选框,即下面复选框的状态与总复选框状态一致 } } //单个全选,总的自动勾选 for (i = 0; i < cb.length; i++) { cb[i].onclick = function () { var flag = true;//控制是否被选中 //每次都要循环检查单个复选框是否全部选中 for (i = 0; i < cb.length; i++) { if (!cb[i].checked) { flag = false;//存在单个复选框没有被选中,flag就变为false break;//提高执行效率 } } cball.checked = flag;//结束循环后,判断单个复选框是否全部被选中 } } </script>
2.4.8 自定义属性
1)获取自定义的属性值
-
获取内置属性值(元素本身自带的属性):
element.属性
;
(通常是内置属性使用)
console.log(div.id)
-
获取自定义的属性:
element.getAttribute('属性')
;
(主要获得 自己添加的自定义的属性可使用)
console.log(div.getAttribute('id'));
2)设置属性值
-
设置内置属性值:
element.属性 = '值'
;
div.id='text';
-
主要设置自定义的属性:
element.setAttribute('属性',值 / '其他')
;
div.setAttribute('index',1);
div.setAttribute('class','footer');
3)移除属性
element.removeAttribute('属性');
例:tab栏切换
<style> * { margin: 0; padding: 0; } .tab { width: 700px; height: 35px; background-color: rgb(240, 240, 240); border-bottom: 2px solid rgb(220, 63, 63); line-height: 35px; margin: 100px auto; margin-bottom: 0; } .tab ul li { list-style: none; text-align: center; padding: 0 15px; float: left; } .tab_con { width: 700px; margin: 100px auto; margin-top: 0; } .item { display: none; } .current { background-color: rgb(220, 63, 63); color: aliceblue; } </style> </head> <body> <div class="tab"> <ul> <li class="current">商品介绍</li> <li>规格与包装</li> <li>售后保障</li> <li>商品评价</li> <li>手机社区</li> </ul> </div> <div class="tab_con"> <div class="item" style="display:block"> 商品介绍模块内容 </div> <div class="item"> 规格与包装模块内容 </div> <div class="item"> 售后保障模块内容 </div> <div class="item"> 商品评价模块内容 </div> <div class="item"> 手机社区模块内容 </div> </div> <script> var tab = document.querySelector('.tab').querySelectorAll('li'); var item = document.querySelector('.tab_con').querySelectorAll('.item'); for (var i = 0; i < tab.length; i++) { //给5个li设置索引号 tab[i].setAttribute('index', i);//注意!注意!这里一定是tab[i] tab[i].onclick = function () { //tab样式变换 for (var i = 0; i < tab.length; i++) { tab[i].className = ''; } this.className = 'current'; //显示内容 var a = this.getAttribute('index');//得到当前点击的是哪个li for (var i = 0; i < item.length; i++) { item[i].style.display = ''; } item[a].style.display = 'block'; } } /* for (var i = 0; i < tab.length; i++) { tab[i].onclick = function () { this.className = 'current'; } //这里的失焦事件就不可以用了,俺也不明白 tab[i].onblur = function () { this.className = ''; } } */ </script>
2.4.9 H5自定义属性
设置H5自定义属性:H5规定自定义属性 data- 开头作为属性名并赋值
获取H5自定义属性:
-
兼容性获取 element.getAttribute(‘data-index’)
-
H5新增的:
element.dataset.index
或element.dataset[‘index’] IE11才开始支持
(dataset是一个集合,里面存放了所有已data开头的属性)
console.log(div.getAttribute('data-list-name')); console.log(div.dataset.listName);//当自定义属性有多个 _ 链接的单词,采用驼峰命名法 console.log(div.dataset['listName']);
2.5 节点操作
2.5.1 节点概述
节点至少有三个基本属性
-
nodeType
1 元素节点,nodeType为1
2 属性节点,nodeType为2
3 文本节点,nodeType为3(文本节点包含文字、空格、换行等) -
nodeName
-
nodeValue
2.5.2 父节点
node.parentNode
-
parentNode属性可以返回某节点的父结点,注意是最近的一个父结点
-
如果指定的节点没有父结点则返回null
<div class="box"> <span class="erweima">×</span> </div> <script> var erweima=document.querySelector('.erweima'); // var box=document.querySelector('.box') erweima.parentNode;//box 为 erweima 的父节点,因此替代上一句 </script>
2.5.3 子节点
1)parentNode.childNodes (标准)
<ul> <li></li> <li></li> <li></li> </ul> <script> var ul = document.querySelector('ul'); //var lis=ul.querySelectorAll('li'); ul.childNodes;//他的输出值里 </script>
-
返回值包含了所有的子结点,包括元素节点,文本节点等
-
如果只想要获得里面的元素节点,则需要专门处理。所以我们一般不提倡使用childNodes
2)parentNode.children (非标准)
-
它只返回子元素节点,其余节点不返回 (这个是我们重点掌握的)
-
虽然 children 是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用
<ul> <li></li> <li></li> <li></li> </ul> <script> var ul = document.querySelector('ul'); //var lis=ul.querySelectorAll('li'); console.log(ul.childNodes); console.log(ul.children);//会常用
3)获取第一个和最后一个子元素
① 返回所有的节点,包括元素节点,文本节点等
-
parentNode.firstChild
返回第一个子节点,找不到则返回null
包含所有的节点,包括元素节点,文本节点等 -
parentNode.lastChild
返回最后一个子节点,找不到则返回null
包含所有的节点,包括元素节点,文本节点等
② 仅返回子元素节点(有兼容性问题,IE9以上才支持)
-
parentNode.firstElementChild
返回第一个子节点,找不到则返回null -
parentNode.lastElementChild
返回最后一个子节点,找不到则返回null
③实际开发的写法
parentNode.children[0];
parentNode.children[最后一个的索引号];
<ul> <li></li> <li></li> <li></li> </ul> <script> var ul = document.querySelector('ul'); //返回全部元素 console.log(ul.firstChild); console.log(ul.lastChild); //仅返子元素 console.log(ul.firstElementChild); console.log(ul.lastElementChild); //实际开发 console.log(ul.children[0]); console.log(ul.children[ul.children.length-1]);//用全部子元素的个数-1
案例:下拉菜单
点击查看代码
<style> * { margin: 0; padding: 0; } ul { list-style: none; } a { text-decoration: none; } .nav { width: 300px; margin: 10px auto; } .nav .dh { width: 80px; height: 50px; text-align: center; float: left; line-height: 50px; } .nav .dh:hover { background-color: rgb(240, 240, 240); color: orange; } .nav ul { display: none; } .dh ul li { border: 1px solid rgb(253, 220, 128); padding: 0px 10px; } .dh li:hover { background-color: antiquewhite; } </style> </head> <body> <ul class="nav"> <li class="dh"><a href="">微博 ↓</a> <ul> <li>私信</li> <li>评论</li> <li>@我</li> </ul> </li> <li class="dh"><a href="">博客 ↓</a> <ul> <li>私信</li> <li>评论</li> <li>@我</li> </ul> </li> <li class="dh"><a href="">邮箱 ↓</a> <ul> <li>私信</li> <li>评论</li> <li>@我</li> </ul> </li> </ul> <script> var nav = document.querySelector('.nav'); var lis = nav.children; for (var i = 0; i < lis.length; i++) { lis[i].onmouseover = function () { this.children[1].style.display = 'block'; } lis[i].onmouseout = function () { this.children[1].style.display = ''; } } </script>
2.5.4 兄弟节点
① 返回所有的节点,包括元素节点,文本节点等
-
node.previousSibling
返回上一个兄弟节点,找不到则返回null
包含所有的节点,包括元素节点,文本节点等 -
node.nextSibling
返回下一个兄弟节点,找不到则返回null
包含所有的节点,包括元素节点,文本节点等
② 仅返回兄弟元素节点(有兼容性问题,IE9以上才支持)
-
node.previousElementSibling
返回上一个兄弟节点,找不到则返回null -
node.nextElementSibling
返回下一个兄弟节点,找不到则返回null
<body> <div>我是div</div> <span>我是span</span> <script> var div = document.querySelector('div'); // 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等 console.log(div.nextSibling); // #text console.log(div.previousSibling); // #text // 2. nextElementSibling 得到下一个兄弟元素节点 console.log(div.nextElementSibling); //<span>我是span</span> console.log(div.previousElementSibling);//null </script> </body>
2.5.5 创建节点
页面添加一个新的元素:
-
先创建节点
document.createElement('tagName')
因为这些元素原先不存在,是根据需求动态产生的,所有也称为动态创建元素节点 -
再添加节点
1. node.appendChild(child)
node父级,child子级
将一个节点添加到 指定父节点的 子节点列表 末尾(类似push)
2. node.insertBefore(child,指定元素)
将一个节点添加到 父节点的 指定子节点 前面
<ul> <li>123</li> </ul> <script> //1.创建节点 var li = document.createElement('li'); //2.添加节点 var ul = document.querySelector('ul'); ul.appendChild(li);//插入到123后面 //添加到已有子节点的前面 var lis = document.createElement('li');//创建的的节点 ul.insertBefore(lis, ul.children[0])//插入到123前面
补充:利用element.insertAdjacentHTML('position', text);
可以把字符串格式元素添加到父元素中
position : 一个 DOMString,表示插入内容相对于元素的位置,并且必须是以下字符串之一:
beforebegin
:元素自身的前面。afterbegin
:插入元素内部的第一个子节点之前。beforeend
:插入元素内部的最后一个子节点之后。afterend
:元素自身的后面。
案例:简单的留言发布
点击查看代码
<style> * { margin: 0; padding: 0; } div { width: 200px; margin: 50px 0 30px 50px } textarea { width: 150px; height: 100px; resize: none; border: 1px solid rgb(255, 107, 132); cursor: text; } ul li { list-style: none; background-color: pink; width: 200px; margin-left: 50px; margin-bottom: 10px; } </style> <body> <div class="liuyan"> <textarea name="" id="">123</textarea> <button>发布</button> </div> <ul> </ul> <script> var text = document.querySelector('textarea'); var btn = document.querySelector('button'); var ul = document.querySelector('ul') btn.onclick = function () { if (text.value == '') { alert('输入内容无效') } else { var lis = document.createElement('li'); ul.appendChild(lis); lis.innerHTML = text.value; } } </script>
2.5.6 删除节点
node.removeChild(child)
方法从 DOM 中删除一个子节点,返回 删除的节点
<body> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> var ul = document.querySelector('ul'); ul.removeChild(ul.children[0]); </script>
简单的删除发布留言:
点击查看代码
<style> * { margin: 0; padding: 0; } div { width: 200px; margin: 50px 0 30px 50px } textarea { width: 150px; height: 100px; resize: none; border: 1px solid rgb(255, 107, 132); cursor: text; } ul li { list-style: none; background-color: pink; width: 200px; margin-left: 50px; margin-bottom: 10px; } li a { float: right; text-decoration: none; } </style> <div class="liuyan"> <textarea name="" id="">123</textarea> <button>发布</button> </div> <ul> </ul> <script> var text = document.querySelector('textarea'); var btn = document.querySelector('button'); var ul = document.querySelector('ul'); btn.onclick = function () { if (text.value == '') { alert('输入内容无效') } else { var lis = document.createElement('li'); ul.appendChild(lis); lis.innerHTML = text.value + '<a href="javascript:;">删除</a>';//innerHTML可以识别标签 //javascript:;可阻止链接跳转 //删除评论 var as = document.querySelectorAll('a'); for (var i = 0; i < as.length; i++) { as[i].onclick = function () { ul.removeChild(this.parentNode); //需要删除a的父亲li,即this.parentNode,而他的父亲是ul } } } } </script>
2.5.7 复制节点
node.cloneNode()
-
node.cloneNode();
括号为空或者里面是false 浅拷贝 只复制标签 不复制里面的内容 -
node.cloneNode(true);
括号为true 深拷贝 复制标签 复制里面的内容
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> var ul = document.querySelector('ul'); //先克隆节点 var liclone = ul.children[0].cloneNode();// 浅拷贝 var liclone = ul.children[0].cloneNode(true);// 深拷贝 //再添加节点 ul.appendChild(liclone); </script> </body>
动态生成表格:
点击查看代码
<table> <thead> <tr> <th>姓名</th> <th>年龄</th> <th>性别</th> <th>操作</th> </tr> </thead> <tbody> </tbody> </table> <script> //1.准备数据,大量数据用数组 var datas = [{ name: '张三', age: 18, sex: '男' }, { name: '李四', age: 18, sex: '男' }, { name: '王五', age: 18, sex: '男' }]; //2.往tbody里面创建行 var tbody = document.querySelector('tbody'); for (var i = 0; i < datas.length; i++) { var tr = document.createElement('tr'); tbody.appendChild(tr); //3.在行里面创建单元格,单元格的个数取决于属性的个数,这里采用遍历对象的属性,对第i个对象进行遍历 for (var k in datas[i]) { var td = document.createElement('td'); tr.appendChild(td); //取值 td.innerHTML = datas[i][k];//这里的 obj[k] 得到的是属性值 } //创建'删除'的单元格 var td = document.createElement('td'); tr.appendChild(td); td.innerHTML = '<a href="javascript:;">删除</a>'; } //添加删除事件 var as = document.querySelectorAll('a'); for (var i = 0; i < as.length; i++) { as[i].onclick = function () { tbody.removeChild(this.parentNode.parentNode); //删除行tr,而他的父亲是tbody,this.parentNode指td,他的父亲是tr } }
2.5.8 三种动态创建元素的区别
-
document.write()
- 直接将内容写入页面的内容流,但是文档流执行完毕,所以会导致页面全部重绘,也就是说,如果页面文档流加载完毕,再调用这句话会导致页面重绘,原来的就没有了,仅剩下新建的元素
-
element.innerHTML
特点:
- innerHTML 是将内容写入某个DOM节点,不会导致页面重绘
- 创建多个元素效率更高(但是要采用数组拼接效率才高)
-
document.createElement()
- 特点:大量创建时,效率低一点点,但是结构更清晰
<body> <div class="innner"></div> <div class="create"></div> <script> // 2. innerHTML 创建元素 var inner = document.querySelector('.inner'); // 2.1 innerHTML 用拼接字符串方法 for (var i = 0; i <= 100; i++) { inner.innerHTML = '<a href="#">百度</a>'; } // 2.2 innerHTML 用数组形式拼接 var arr = []; for (var i = 0; i <= 100; i++) { arr.push('<a href="#">百度</a>'); } inner.innerHTML = arr.join(''); // 3. document.createElement() 创建元素 var create = document.querySelector('.create'); var a = document.createElement('a'); create.appendChild(a); </script> </body>
2.6 DOM重点核心
对于DOM操作,我们主要针对子元素的操作,主要有
-
创建:document.write、innerHTML、createElement
-
增:appendChild、insertBefore
-
删:removeChild
-
改:主要修改dom的元素属性,dom元素的内容、属性、表单的值等
- 修改元素属性:src、href、title 等
- 修改普通元素内容:innerHTML、innerText
- 修改表单元素:value、type、disabled
- 修改元素样式:style、className
-
查:主要获取查询dom的元素
- DOM提供的API方法:getElementById、getElementsByTagName (古老用法,不推荐)
- H5提供的新方法:querySelector、querySelectorAll (提倡)
- 利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling) 提倡
-
属性操作:主要针对于自定义属性
- setAttribute:设置dom的属性值
- getAttribute:得到dom的属性值
- removeAttribute:移除属性
3. 事件高级
3.1 注册事件
注册事件有两种方式:传统方式和方法监听注册方式
3.1.1 传统方式
-
利用 on 开头的事件
-
btn.onclick = function(){}
-
特点:注册事件的唯一性
-
同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
3.1.2 方法监听注册方式
-
w3c推荐方式
-
addEventListener() 它是一个方法
-
IE9之前的IE不支持此方法,可使用 attachEvent() 代替
-
同一个元素同一个事件可以注册多个监听器
-
按注册顺序依次执行
eventTarget.addEventListener()
方法将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数
eventTarget.addEventListener(type,listener[,useCapture])
该方法接收三个参数:
1.type:事件类型字符串,比如click,mouseover,注意这里不要带on 2.listener:事件处理函数,事件发生时,会调用该监听函数 3.useCapture:可选参数,是一个布尔值,默认是 false。学完 DOM 事件流后,我们再进一步学习
<body> <button>传统注册事件</button> <button>方法监听注册事件</button> <button>ie9 attachEvent</button> <script> var btns = document.querySelectorAll('button'); // 1. 传统方式注册事件 btns[0].onclick = function () { alert('hi'); } btns[0].onclick = function () { alert('hao a u'); } // 2. 事件监听注册事件 addEventListener // (1) 里面的事件类型是字符串 所以加引号 而且不带on // (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序) btns[1].addEventListener('click', function () { alert(22); }) btns[1].addEventListener('click', function () { alert(33); }) // 3. attachEvent ie9以前的版本支持 btns[2].attachEvent('onclick', function () { alert(11); }) </script> </body>
3.2 解绑事件
3.2.1 传统事件删除方式
eventTarget.onclick = null;
3.2.2 removeEventListener删除事件方式
eventTarget.removeEventListener(type,listener[,useCapture]);
该方法接收三个参数:
1. type:事件类型字符串,比如click,mouseover,注意这里不要带on 2. listener:事件处理函数,事件发生时,会调用该监听函数 3. useCapture:可选参数,是一个布尔值,默认是 false。学完 DOM 事件流后,我们再进一步学习
3.2.3 detachEvent删除事件方式(兼容)
eventTarget.detachEvent(eventNameWithOn,callback);
该方法接收两个参数:
1. eventNameWithOn:事件类型字符串,比如 onclick 、onmouseover ,这里要带 on 2. callback: 事件处理函数,当目标触发事件时回调函数被调用
- ie9以前的版本支持
<body> <div>1</div> <div>2</div> <div>3</div> <script> var divs = document.querySelectorAll('div'); divs[0].onclick = function () { alert(11); // 1. 传统方式删除事件 divs[0].onclick = null; } // 2.removeEventListener 删除事件 divs[1].addEventListener('click', fn); //里面的fn不需要调用加小括号 function fn() {//要删除de事件不能用匿名函数 alert(22); divs[1].removeEventListener('click', fn); } // 3.IE9 中的删除事件方式 divs[2].attachEvent('onclick', fn1); function fn1() { alert(33); divs[2].detachEvent('onclick', fn1); } </script> </body>
3.3 DOM事件流
事件流描述的是从页面中接收事件的顺序
比如我们给一个div注册了点击事件:
DOM事件流分为3个阶段:1.捕获阶段 2.当前目标阶段 3.冒泡阶段
事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。 事件捕获: 网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
// dom 事件流 三个阶段 // 1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。 // 2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。 // 3. 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段 document -> html -> body -> father -> son var son = document.querySelector('.son'); son.addEventListener('click', function () { alert('son'); }, true) var father = document.querySelector('.father'); father.addEventListener('click', function () { alert('father'); }, true)//点击子盒子先弹出father,再弹出son //4. 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段 son -> father ->body -> html -> document var son2 = document.querySelector('.son2'); son2.addEventListener('click', function () { alert('son2'); }, false) var father2 = document.querySelector('.father2'); father2.addEventListener('click', function () { alert('father2');//点击子盒子先弹出松2,再弹出father2 }, false)
3.4 事件对象
var div=document.querySelector('div'); div.onclick=function(event){} div.addEventListener('click',function(event){})
event就是一个事件对象,写到监听函数的小括号中 当形参来看
-
event 就是一个事件对象 写到我们侦听函数的 小括号里面 当形参来看
-
事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
-
事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的
比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标啊,
如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键 -
这个事件对象我们可以自己命名 比如 event 、 evt、 e
-
事件对象也有兼容性问题 ie678 通过
window.event
, 兼容性的写法:e = e || window.event;
3.4.1 常见的属性和方法
事件对象属性方法 | 说明 |
---|---|
e.target | 返回触发事件的对象 标准 |
e.type | 返回事件的类型 比如click mouseover 不带on |
e.srcElement | 返回触发事件的对象 非标准 ie6-8使用 |
e.preventDefault() | 该方法 阻止默认行为 标准 比如不让链接跳转 |
e.returnValue | 该属性 阻止默认行为 非标准,ie6-8使用 |
e.stopPropagation() | 该方法阻止冒泡 标准 |
e.cancelBubble | 该属性阻止冒泡,非标准,ie6-8使用 |
1) e.target和this的区别
-
e.target 是事件触发的元素。(例如点击事件,鼠标点击的哪个元素,返回的就是哪个元素)
-
this 是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素)
和this有个非常相似的属性 currentTarget,返回的也是事件的绑定元素,有兼容性问题,不常用
<ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> var ul = document.querySelector('ul'); ul.addEventListener('click', function (e) { console.log(e.target);//返回的是li console.log(this);//返回的是ul }) </script>
2)返回事件类型 (e.type)
var div = document.querySelector('div'); div.addEventListener('click', fn); function fn(e) { console.log(e.type);//返回结果为 click
3)阻止默认行为 (e.preventDefault())
让链接不跳转,或者 让提交按钮不提交
var a = document.querySelector('a'); a.addEventListener('click', function (e) { e.preventDefault(); })
return flase
也能阻止默认行为,且无兼容性问题,但后面的代码无法实现,且只限用于传统注册方式
4)阻止冒泡(e.stopPropagation())
var son2 = document.querySelector('.son2'); son2.addEventListener('click', function (e) { alert('son2'); e.stopPropagation(); }, false) var father2 = document.querySelector('.father2'); father2.addEventListener('click', function () { alert('father2'); }, false) //只弹出son2,不再弹出father2
ie 6-8写法:
window.e.cancelBubble = true;
3.4.2 事件委托
原理:
不是每个子节点单独设置监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
案例:给ul注册点击事件,然后点击里面的li的时候,当前的li可以用event.target得到,并且点击li,事件会冒泡到ul上
<ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <script> var ul = document.querySelector('ul'); ul.addEventListener('click', function (e) { for (var i = 0; i < ul.children.length; i++) { ul.children[i].style.backgroundColor = ''; } e.target.style.backgroundColor = 'pink'; }) //点击li,通过事件冒泡 传给ul,触发ul点击事件,再通过e.targr来得到点击的对象 </script>
3.5 常用的鼠标事件 2
3.5.1 禁止选中文字 和 禁止右键菜单
1)selectstart
-
主要控制鼠标选中
-
可以通过阻止默认行为来取消默认的上下文菜单
hello world! <script> document.addEventListener('selectstart', function (e) { e.preventDefault(); })
2)contextmenu
-
主要控制应该何时显示上下文菜单
-
可以通过阻止默认行为来取消默认的上下文菜单
hello world! <script> document.addEventListener('contextmenu', function (e) { e.preventDefault();//阻止默认行为 })
3.5.2 鼠标事件对象
-
event对象代表事件的状态,跟事件相关的一系列信息的集合
-
现阶段我们主要是用鼠标事件对象 MouseEvent 和键盘事件对象 KeyboardEvent。
鼠标事件对象 | 说明 |
---|---|
e.clientX | 返回鼠标相对于浏览器窗口可视区的X坐标 |
e.clientY | 返回鼠标相对于浏览器窗口可视区的Y坐标 |
e.pageX(重点) | 返回鼠标相对于文档页面的X坐标(屏幕滚动后点击的坐标不同) IE9+ 支持 |
e.pageY(重点) | 返回鼠标相对于文档页面的Y坐标(屏幕滚动后点击的坐标不同) IE9+ 支持 |
e.screenX | 返回鼠标相对于电脑屏幕的X坐标 |
e.screenY | 返回鼠标相对于电脑屏幕的Y坐标 |
<script> document.addEventListener('click', function (e) { //相对浏览器的坐标 console.log(e.clientX); console.log(e.clientY); //相对页面文档的坐标 console.log(e.pageX); console.log(e.pageY); //相对电脑屏幕的坐标 console.log(e.screenX); console.log(e.screenY); }) </script>
案例:跟随鼠标
img { position: absolute; top: 0; right: 0; } <body> <img src="imges/魔女.png" alt="" width="100" height=""> <script> var img = document.querySelector('img'); //mousemove只要鼠标移动1px就会触发事件 document.addEventListener('mousemove', function (e) { img.style.left = e.clientX + 'px'; img.style.top = e.clientY + 'px'; //想要鼠标到图的中间位置 img.style.left = e.clientX - 50 + 'px'; img.style.top = e.clientY - 40 + 'px'; })
3.6 常见的键盘事件
键盘事件 | 触发条件 |
---|---|
onkeyup | 某个键盘按键被松开时触发 |
onkeydown | 某个键盘按键被按下时触发 |
onkeypress | 某个键盘按键被按下时触发,但是它不识别功能键,比如 ctrl shift 箭头等 |
-
如果使用addEventListener 不需要加 on
-
onkeypress 和前面2个的区别是,它不识别功能键,比如左右箭头,shift 等
-
三个事件的执行顺序是: keydown – keypress — keyup
<script> //按任意按键,松开键盘触发 document.addEventListener('keyup', function () { console.log('world'); }) //按任意按键,按下键盘触发 document.addEventListener('keydown', function () { console.log('hello');//按住不松会一直触发 }) ////按下键盘触发,但不识别功能键 document.addEventListener('keypress', function () { console.log('hello');//按住不松会一直触发 }) </script>
3.6.1键盘事件对象
属性 | 说明 |
---|---|
keyCode | 返回该键值的ASCII值 |
- onkeydown和 onkeyup 不区分字母大小写(按大小写得到的ASCII码值相同),onkeypress 区分字母大小写。
//键盘事件对象 document.addEventListener('keypress', function (e) { console.log(e.keyCode); })
案例:按下s键后光标在搜索框内显示
var search = document.querySelector('input'); //此处用keyup是因为按键松开后才会触发事件,因此s不会被输入 document.addEventListener('keyup', function (e) { if (e.keyCode == 83) { search.focus();//focus()方法:获得焦点 } })
案例:放大单号
点击查看代码
<style> div { width: 168px; border: 1px solid rgba(0, 0, 0, .4); position: relative; box-shadow: 0px 2px 10px rgba(0, 0, 0, .4); margin-bottom: 10px; font-size: 19px; display: none; } div::before { content: ''; border-top: 10px solid white; border-right: 10px solid transparent; border-bottom: 10px solid transparent; border-left: 10px solid transparent; width: 0; height: 0; position: absolute; top: 24px; left: 84px; margin-left: -5px; border-style: solid dashed dashed; border-color: #fff transparent transparent; } input { position: absolute; top: 50px; } </style> <body> <div></div> <input type="text"> <script> //输入单号,显示放大 //检测是否输入,添加键盘事件 //将表单的值赋给div //失去焦点,div隐藏,获得焦点,div显示 var big = document.querySelector('div'); var input = document.querySelector('input'); input.addEventListener('keyup', function () { if (input.value !== '') { big.style.display = 'block'; big.innerHTML = this.value; } else { big.style.display = ''; big.innerHTML = this.value; } input.addEventListener('blur', function () { big.style.display = ''; big.innerHTML = this.value; }) input.addEventListener('focus', function () { if (input.value !== '') { big.style.display = 'block'; big.innerHTML = this.value; } }) }) </script> </body>
- keydown和keypress在文本框里面的特点:他们两个触发的时候,文字还没有落入文本框中
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~