前端点滴(JS基础)(六)----倾尽所有
HTML DOM 操作
1. 属性节点的操作
(1)查询元素的属性
属性不能单独存在,一定属于一个标签。所有,操作属性,前提必须找到标签。
语法 | 描述 | 特点 | 支持 |
---|---|---|---|
元素节点.attributes | 获取元素的所有属性 | - | 所有浏览器 |
元素节点.getAttribute(属性名) | 获取指定属性的值 | 标准的获取已经存在的属性值的方法 | 所有浏览器 |
元素节点.属性名 | 获取指定属性的值 | 获取不存在的属性值时比较好用,能够获取类似于readOnly、checked等属性 | 所有浏览器 |
实例:
<script>
var input = document.getElementById('input');
/* 元素节点.attributes */
console.log(input.attributes);
// NamedNodeMap {0: type, 1: id, 2: readonly, type: type, id: id, readonly: readonly, length: 3}
console.log(input.attributes.length); // 3
/* 元素节点.getAttribute(属性名) */
console.log(input.getAttribute('type')); //=> text
console.log(input.getAttribute('readOnly')); //=> null
/* 元素节点.属性名 */
console.log(input.type); //=> text
console.log(input.readOnly); //=> true
</script>
(2)添加/修改元素的属性
语法 | 描述 | 特点 | 支持 |
---|---|---|---|
元素节点.setAttribute(属性名,属性值) | 设置(添加/修改)元素的所有属性 | 属性不存在表示添加,属性存在表示修改 | 所有浏览器 |
元素节点.属性名 = 值 | 设置(添加/修改)元素的所有属性 | 属性不存在表示添加,属性存在表示修改 | 所有浏览器 |
实例:
/* 设置元素属性 */
input.setAttribute("value","yaodao");
input.value = "yaodao"
/* 修改元素属性 */
input.setAttribute("name","text2");
input.name = "text2"
效果:
(设置前):
(设置后):
(3)删除元素的属性
/* 删除元素属性 */
input.removeAttribute("value")
(4)判断元素是否有哪个属性
语法:标签节点.hasAttribute("属性名")
注意: 返回Boolean类型的值。
/* 判断是否存在元素属性 */
console.log(input.hasAttribute("value")); //=> false
console.log(input.hasAttribute("name")); //=> true
总结
元素节点的增删改查:
- 增:document.creatElement(“标签名”); document.creatTextNode(“文本”); 父节点.appendChild(子节点); 父节点.insertBefore(新节点,参照节点)
- 删:父节点.removeChild(子节点);
- 改:父节点.replaceChild(新节点,参照节点)
- 查:document.getElementById(“元素id”); document.getElementsByTagName(“标签名”); document.getElementsByClassName(“类名”);document.getElementsByName(“元素的name属性”);document.querySelector(“css选择器”);document.querySelectorAll(“css选择器”)
属性节点的增删改查:
- 增:元素节点.setAttribute(“属性名”,“属性值”); 元素节点.属性名 = “属性值”;
- 删:元素节点.removeAttribute(“属性名”);
- 改:元素节点.setAttribute(“属性名”,“属性值”); 元素节点.属性名 = “属性值”;
- 查:元素节点.attributes; 元素节点.getAttribute(“属性名”); 元素节点.属性名;
2. DOM 对象的通用属性
innerHTML
- 获取/设置元素里的html内容
innerText
- 获取/设置元素里面的文本内容
nodeName
- nodeName 是只读的
元素节点的 nodeName 与标签名相同
属性节点的 nodeName 与属性名相同
文本节点的 nodeName 始终是 #text
文档节点的 nodeName 始终是 #document
nodeValue
- 元素节点的 nodeValue 是 undefined 或 null
- 文本节点的 nodeValue 是文本本身
- 属性节点的 nodeValue 是属性值
nodeType
调用nodeType属性会得到一个数字,这个数字表示节点的类型
- 元素 1
- 属性 2
- 文本 3
- 注释 8
- 文档 9
实例:
<script type="text/javascript">
var p = document.getElementById('p');
//innerHTML,innerText
/* 获取元素里的html内容 */
console.log(p.innerHTML); //=> 123<span>456</span>
/* 获取元素里的文本内容 */
console.log(p.innerText); //=> 123456
/* 设置元素中的html内容 */
p.innerHTML = '<a href="#">按钮</a>';
/* 设置元素里的文本内容 */
p.innerText = '这是innerText后的文本';
// nodeName
/* 获取元素节点的nodeName */
console.log(p.nodeName); //=> p
/* 获取属性节点的nodeName */
console.log(p.getAttributeNode("id").nodeName); //=> id
// nodeValue
/* 获取元素节点的nodeValue */
console.log(p.nodeValue); //=> undefined
console.log(p.getAttributeNode("id").nodeValue); //=> p
// nodeType
/* 获取元素节点的nodeType */
console.log(p.nodeType); //=> 1
/* 获取属性节点的nodeType */
console.log(p.getAttributeNode("id").nodeType); //=> 2
/* 获取文本节点的nodeType */
console.log(p.childNodes[0].nodeType); //=> 3
/* 获取文档的nodeType */
console.log(document.nodeType); //=> 9
</script>
3. 设置/获取元素的css样式
(1)设置样式
语法: elementNode.style.css样式 = 值
css样式的写法:
①、一个单词的直接写即可。比如color height …
②、样式名称带中横线的,去掉中横线,后面单词首字母大写。比如fontSize lineHeight backgroundColor
实例:
(2)获取样式
使用 " elementNode.style.样式名称
" 的方式只能获取行内样式和js已经设置过的样式。
要想获取全部的样式,则必须使用下面的方法:
- 在IE中支持
elementNode.currentStyle.样式名称
- 火狐支持
getComputedStyle(elementNode).样式
为了兼容各个浏览器,所以需要自己封装一个函数,用于获取完整的css样式:
function getStyle(el,style){
// IE 支持类型
if(el.currentStyle){
return el.currentStyle[style]
}else{
// 火狐支持类型
return getComputedStyle(el)[style]
}
}
console.log(getStyle(p,'fontSize'))
调用 getStyle() 获取完整的样式。
注意: 样式名有需要地使用驼峰命名法,并且以字符串的方式参入参数。
4. DOM获取元素的位置
静态元素位置属性:
- offsetLeft 元素在网页中水平坐标值
- offsetTop 元素在网页中垂直坐标值
- offsetWidth 元素在页面中占据的宽度
- offsetHeight 元素在页面中占据的高度
注意: 当前offsetWidth = width+padding+border。
注意: 当前offsetLeft = margin-left。
注意: 当前offsetTop = margin-top。
动态元素位置属性:
- scrollLeft 滚动条在容器中水平滚动的距离,多用于浏览器的滚动条
- scrollTop 滚动条在容器中垂直滚动的距离,多用于浏览器的滚动条
间歇滚动实现案例:
// <ul id="Dong"> 关键是css中设置 overflow:hidden;
var Dong = document.getElementById("Dong");
Dong.innerHTML += Dong.innerHTML;
var iLiHeight = 45; //设置滚动行高
Dong.scrollTop = 0; //初始化
var tim;
function moving() {
Dong.scrollTop++;
tim = setInterval(scrollUp, 30);
}
function scrollUp() {
if (Dong.scrollTop % iLiHeight ==0) {
clearInterval(tim);
setTimeout(moving, 3000)
}
else {
Dong.scrollTop++;
if (Dong.scrollTop >= Dong.scrollHeight/2) {
Dong.scrollTop =0;
}
}
}
setTimeout(moving,3000);
})
5. 事件和事件对象
(1)什么是事件
浏览网页时,当我们做出点击鼠标、按键盘、移动鼠标等行为时,这些行为会被浏览器内置的JavaScript引擎所捕获,并执行对应的某些操作(函数)。那么你的行为(动作)+ JavaScript引擎捕获 + 执行对应的操作 = 事件
。
所以,一个完整的事件应该包括:
- 用户行为;
- 浏览器捕获你的行为;
- 执行对应的操作(函数)
常见行为有:鼠标点击、鼠标的移动、鼠标的移入和移出、键盘控制等等。
事件的作用是:通过事件,我们(浏览网页的人)就可以和浏览器进行一些交互了。
(2)事件绑定的多种方式
声明: 如果同时存在标签事件,DOM方法绑定的事件。优先执行DOM方式绑定的事件。
1、on() 绑定事件
语法:elementNode.on('不带on的常用事件名',function(){})
实例:
document.getElementById('btn').on('click', function () {
alert(123);
});
2、事件名绑定事件
语法:elementNode.带有on的常用事件名 = function(){}
实例:
document.getElementById('btn').onclick = function () {
alert(123);
};
3、事件监听绑定事件
事件监听的方法有两种:
- addEventListener——兼容:firefox、chrome、IE、safari、opera;不兼容IE7、IE8
- attachEvent——兼容:IE7、IE8;不兼容firefox、chrome、IE9、IE10、IE11、safari、opera
addEventListener() 语法: elementNode.addEventListener(event, function, useCapture)
注意: useCapture (可选)布尔值,指定事件是否在捕获或冒泡阶段执行。【true:事件句柄在捕获阶段执行; false:默认,事件句柄在冒泡阶段执行】,需要了解事件发生过程:事件捕获----处于目标----事件冒泡
attachEvent() 语法: elementNode.attachEvent(event, function)
共性与区别:
相同点:
都是dom对象的方法,可以实现一种事件绑定多个事件处理函数。
不同点:
-
attachEvent是IE有的方法,它不遵循W3C标准,而其他的主流浏览器如FF等遵循W3C标准的浏览器都使用addEventListener,所以实际开发中需分开处理。
-
多次绑定后执行的顺序是不一样的,attachEvent是后绑定先执行(覆盖),addEventListener是先绑定先执行(不会覆盖)。
-
存在兼容问题,绑定事件名方法不同,addEventListener() 方法的event参数不用带on ,attachEvent() 方法中的event 参数需要带on。
同样为了兼容各个浏览器,所以需要自己封装一个函数,用于监听事件:
var btn = document.getElementById('btn');
function listenFn(el,type,fn){
if(window.addEventListener){
return el.addEventListener(type,fn);
}else{
return el.attachEvent('on'+type,fn)
}
};
function fn(){
alert(123);
};
function fn2(){
alert(456);
};
// ...
listenFn(btn,'click',fn);
listenFn(btn,'click',fn2);
// ... 还可以绑定多个事件
效果:
事件监听的第三个参数说明:
addEventListener第三个参数涉及到的事件捕获与冒泡。
<style>
#div1{
width: 200px;
height: 200px;
background-color: red;
}
#div2{
width: 100px;
height: 100px;
background-color: green;
}
</style>
<div id="div1" >
<div id="div2">
<button id="btn">按钮</button>
</div>
</div>
<script type="text/javascript">
window.onload=function(){
document.getElementById("btn").addEventListener("click",function () {
// body...
alert("hello");
});
document.getElementById("div2").addEventListener("click",function(){
alert("div2");
},true);
document.getElementById("div1").addEventListener("click",function(){
alert("div1");
});
}
</script>
效果:
说明:
- 默认情况下addEventListener() 的第三个参数为false/不填,表示元素触发事件在冒泡阶段 事件流:btn事件 -> div2事件 -> div1事件。
当处于目标div2 时元素触发事件,事件就会逐层向上冒泡 div1事件 -> div2事件;当处于目标btn 时元素触发事件,事件同样会逐层向上冒泡div1事件 -> div2事件 -> btn事件。
- 非默认情况下addEventListener() 的第三个参数为true,表示元素触发事件在捕获阶段 事件流:div1事件 -> div2事件 -> btn事件。
当处于目标div2 时元素触发事件,事件会根据捕获阶段的事件流,先触发div2事件,再经过冒泡阶段触发div1事件。当处于目标btn 时,由于div2 addEventListener() 的第三个参数为true,在捕获阶段触发。所以先触发div2事件,再触发btn事件,最后触发div1事件。
- 不过要注意一点:不要因为捕获而忽略冒泡。
4、标签中绑定事件
直接在标签中添加事件,例如:
<input type="button" value="按钮" id="btn" onclick="fn2()">
function fn2(){
alert(456);
}
5、实例说明
<input type="text" id="username" value="请输入用户名" />
<script>
//找到username,绑定获取焦点事件
document.getElementById('username').onfocus = function () {
document.getElementById('username').value = '';
};
//优化
document.getElementById('username').onfocus = function () {
this.value = '';
};
</script>
在事件处理函数中,this表示绑定事件的那个元素
HTML代码:
<!- 要求:页面中有很多个td,点击td的时候,让td的背景颜色发生变化 ->
<table>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</table>
css代码:
<style>
table,td{
border:solid 1px #ccc;
border-collapse: collapse; /*合并边框*/
}
td{
width:150px;
height:50px;
}
table{
margin:10px auto; /*让表格左右居中对齐*/
}
</style>
JS代码:
<script>
//点击页面中的td,点击之后,让被点击的td背景颜色改变成随机颜色
//先找到所有的td
var tds = document.getElementsByTagName('td'); // 返回数组
//循环,为每个td都绑定一个单击事件
for(var i=0; i<tds.length; i++){
tds[i].onclick = function () {
//this 表示绑定事件的那个td
var r = Math.floor(Math.random()*256);
var g = Math.floor(Math.random()*256);
var b = Math.floor(Math.random()*256);
this.style.backgroundColor = 'rgb('+r+', '+g+', '+b+')';
//全变红色
/*if(this.style.backgroundColor != 'red'){
this.style.backgroundColor = 'red';
}else{
this.style.backgroundColor = 'white';
}*/
};
}
</script>
效果:
(3)常用的事件名
- 页面事件:
- onload :当页面载入完毕(页面中的标签和外部资源)后触发
- 焦点事件:
- onfocus :当获取焦点时触发
- onblur :当失去焦点时触发
- 鼠标事件:
- onmouseover :当鼠标悬浮时触发
- onmouseout :当鼠标离开时触发
- 键盘事件:
- onkeypress :当键盘按下时触发(如果按住某个键不松开,会一直触发press事件)
- onkeydown :当键盘按下时触发
- onkeyup :当键盘弹起时触发
- 其他事件:
- onchange :内容改变时会触发,常用于select>option。
- onsubmit :表单提交时触发,这个事件要给form绑定而不是给提交按钮绑定
- onresize : 页面窗口改变大小时会触发
- onscroll :滚动条滚动时触发
(4)什么是事件对象
事件对象也是一个对象,它提供了一些属性,这些属性描述了当前事件的特点;
不同的事件中,事件对象也有所差异,比如单击事件中,事件对象会提供pageX和pageY属性,表示点击的点距离页面的距离,比如键盘事件中,事件对象会提供keyCode属性,表示按的是什么键。
总之,事件对象中提供了一些属性,这些属性可以很好的描述当前的事件的特点。
(5)获取事件对象
IE 浏览器:window.event;
主流浏览器:传递给事件函数的参数。
同样的为了兼容各个浏览器,兼容各个浏览器的获取事件对象的方法:
document.getElementsByTagName('input')[0].onclick = function(a){
if(window.event){
e = window.event;
}else{
e = a;
}
// 简写
var e = window.event||a;
}
(6)事件对象的常用属性
下面列举一些事件对象中的常用属性:
- target:返回触发此事件的元素(事件的目标节点)。
- currentTarget:返回其事件监听器触发该事件的元素。
- keyCode:表示键盘上的键对应的数值。
- altKey:表示是否按了alt键,按了结果为true,没按结果为false(组合按键的时候,才会有作用)
- shiftKey:表示是否按了shift键,按了结果为true,没按结果为false(组合按键的时候,才会有作用)
- ctrlKey:表示是否按了ctrl键,按了结果为true,没按结果为false(组合按键的时候,才会有作用)
- pageX: 鼠标距离页面左边的距离
- pageY: 鼠标距离页面上面的距离
- screenX: 鼠标距离屏幕左边的距离
- screenY: 鼠标距离屏幕上面的距离
实例:
(7)事件对象的方法
stopPropagation() 阻止冒泡事件的发生。
1. 什么是冒泡事件?
上述小例子中,点击元素的子元素,会透过子元素触发元素本身的事件,这就是冒泡事件。
首先,要清楚什么是事件流?
事件流:
当一个HTML元素产生一个事件时,该事件会在元素节点与根节点之间的路径传播,路径所经过的节点都会收到该事件,这个传播的过程叫做DOM事件流。
元素触发事件时,事件的传播过程称为事件流,过程分为捕获和冒泡两种:
冒泡事件: 微软提出的 事件由子元素传递到父元素的过程,叫做冒泡
捕获事件: 网景提出的 事件由父元素到子元素传递的过程,叫做事件捕获
有些时候要的就是这个效果,可以不做任何处理;有些时候不希望有冒泡事件发生,那么可以通过事件对象的方法来阻止冒泡的发生。
2. 阻止冒泡事件的发生
阻止冒泡事件的发生有:
- 标准浏览器使用 evt.stopPropagation(); //evt指的是事件对象
- IE内核浏览器使用 window.event.cancelBubble = true;
可以封装一个兼容各个浏览器的阻止冒泡的方法:
<script>
/*************** 阻止冒泡函数 *************/
function zuzhi(evt){
if(window.event){
window.event.cancelBubble = true;
}else{
evt.stopPropagation(); //evt指的是事件对象
}
}
//分别给两个div绑定单击事件
document.getElementById('d1').onclick = function () {
alert(11111);
};
document.getElementById('d2').onclick = function (evt) {
alert(22222);
//阻止冒泡发生
zuzhi(evt); // 此处会阻止11111的弹出
};
</script>
preventDefault() 阻止标签的默认行为。
默认行为就是html标签的一些默认行为,比如点击a标签会跳转,比如点击了submit按钮表单会提交。这些都属于标签的默认行为。
有些时候,点击了a标签或者submit按钮后不希望执行标签的默认行为,这时候就需要阻止默认行为。
阻止默认行为:
标准浏览器:evt.preventDefault();
IE内核浏览器:window.event.returnValue = false;
兼容各个浏览器的阻止标签默认行为的方法:
<body>
<a href="13冒泡事件.html">跳转</a>
<form name="f1" action="07全选.html" method="post">
用户名:<input type="text" name="username"><br>
密 码:<input type="password" name="pwd"><br>
<input type="submit" id="sub" value="提交">
</form>
<script>
/********* 阻止标签的默认行为 *********/
//形参evt标签标准浏览器的事件对象
function zuzhi(evt){
if(window.event){
//IE浏览器
window.event.returnValue = false;
}else{
//非IE浏览器
evt.preventDefault();
}
}
document.getElementById('sub').onclick = function (evt) {
//检测用户名是否为空
if(document.f1.username.value == ''){
alert('用户名不能为空');
//阻止表单提交
zuzhi(evt);
//return false; //return false也可以阻止表单提交
}
};
</script>
注意: return false 同样可以阻止默认行为。
综合案例----可编辑表格
HTML:
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>唐僧</td>
</tr>
<tr>
<td>2</td>
<td>悟空</td>
</tr>
<tr>
<td>3</td>
<td>八戒</td>
</tr>
<tr>
<td>4</td>
<td>沙僧</td>
</tr>
<tr>
<td>5</td>
<td>白龙马</td>
</tr>
<tr>
<td>6</td>
<td>金箍棒</td>
</tr>
</tbody>
</table>
css:
<style>
*{
margin:0;
padding:0;
border:0 none;
}
table,th,td{
border:solid 1px #1b272e;
border-collapse: collapse; /*合并边框*/
}
table{
width:400px;
margin:10px auto; /*左右居中对齐*/
}
th,td{
width:50%;
padding:3px;
}
</style>
js:
/* 要求:隔行换色,姓名可修改,且点击姓名后自动变成 value为原有值的 input 并且宽高与 td 一致,绑定回车与esc键盘事件 */
//兼容各个浏览器的获取完整css样式的写法
function getStyle(node, styleName){
if(node.currentStyle){
//说明是IE
return node.currentStyle[styleName];
}else{
return getComputedStyle(node)[styleName];
}
}
// 隔行换色
// 找到所有的 tr 进行遍历,如果遍历的 i 能够整除2,就改变颜色。
var trs = document.querySelectorAll('tbody tr');
for(var i = 0;i<trs.length;i++){
if(i%2 == 0){
trs[i].style.backgroundColor = '#d4d4d4';
}
}
//获取姓名td
var tds = document.querySelectorAll('tbody td:nth-child(2n)');
//循环遍历给每个姓名td绑定单击事件
for(var i = 0;i<tds.length;i++){
tds[i].onclick = function(){
//将每一个td赋值给变量td进行操作,避免改变原有数据
var td = this; //this表示点击事件的对象td[i]
var text = td.innerText;
td.innerHTML = '';
//创建input框
var input = document.createElement('input');
//设置样式
input.style.width = getStyle(td,"width");
input.style.height = getStyle(td,"height");
input.style.backgroundColor = getStyle(td,"backgroundColor");
input.style.fontSize = getStyle(td,"fontSize");
input.style.outline= "none";
//将保存的td文本赋值给input.value
input.value = text;
//在td中加入设置好的input框
td.appendChild(input);
//获取焦点
input.focus();
//绑定键盘事件,enter成功设置,esc取消设置(恢复原形)。
input.onkeyup = function (evt) {
var e = window.event||evt;
var keyCode = e.keyCode;
if(keyCode == 13){ //表示按了回车,表示确定
td.innerHTML = ''; //先清空td中的input
td.innerHTML = this.value;
}
if(keyCode == 27){ //按ESC键表示取消
td.innerHTML = ''; //先清空td中的input
td.innerHTML = text;
}
};
}
}
效果: