问题
1.dom对象的innerText和innerHTML有什么区别?
- innerText:
- 当使用innerText读取值时,如果有HTML标签,它会过滤掉HTML标签,并且按照由浅入深的顺序将所有的文本拼接起来。
- 当使用innerText写入值时,结果会删除dom对象的所有子节点,插入包含的相应文本值的文本节点。如果有HTML标签,它会对HTML语法字符(小于号、大于号、引号及和号等)进行编码,使HTML标签以正常的文本形式出现在dom对象中。
举例:
<body>
<div id="content">
<p>This is a <strong>test</strong> paragraph</p>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
</body>
<script>
var oDiv = document.getElementById("content");
console.log(oDiv.innerText);
oDiv.innerText = "<h2>Hello & <strong>hunger</strong></h2>";
- innerHTML
- 当使用innerHTML读取值时,返回dom对象的所有子节点(包括元素、注释和文本节点)对应的HTML标记。
- 当使用innerHTML写入值时,会根据写入的值创建新的DOM树,然后用这个DOM树完全替换原先所有的子节点。
举例:
<body>
<div id="content">
<p>This is a <strong>test</strong> paragraph</p>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
</body>
<script>
var oDiv = document.getElementById("content");
console.log(oDiv.innerHTML);
oDiv.innerHTML = "<h2>Hello & <strong>hunger</strong></h2>";
那么总而言之:innerHTML是一种插入HTML字符的方法,所以它会根据标签生成DOM树,而innerText是一种插入文本的方法,所以它会过滤掉标签。
2.elem.children和elem.childNodes的区别?
- elem.children
每个节点都会有一个childNodes属性,其中保存着一个NodeList对象。而NodeList是一个类数组,用于保存节点中所有的子节点(共12中,Element元素节点只是其中一种,具体哪12种可以参考深入理解DOM节点类型第一篇——12种DOM节点类型概述)。这组节点是有序的,可以通过位置来访问。
举例:
<body>
<ul id="test">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
<script>
var oUl = document.getElementById("test");
console.log(oUl.children.length);//返回7,包括3个元素节点和4个空白字符的文本节点
</script>
- 而elem.children只会返回节点的元素子节点,除此之外,与elem.childNodes没什么区别。
举例:
<body>
<ul id="test">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
<script>
var oUl = document.getElementById("test");
console.log(oUl.children.length);//返回3
</script>
3.查询元素有几种常见的方法?
- querySelector 方法接受一个CSS选择器作为参数,返回匹配该选择器的元素节点。
如果有多个节点满足匹配条件,则返回第一个匹配的节点。
如果没有发现匹配的节点,则返回null。
该方法在HTML文档上和HTML元素上都能调用。
querySelectorAll 方法与querySelector用法类似。
区别是返回一个静态的NodeList对象(NodeList 本质上是一个动态的 Node 集合,只是规范中对 querySelectorAll 有明确要求,规定其必须返回一个静态的 NodeList 对象),包含所有匹配给定的选择器的节点。
该方法在HTML文档上和HTML元素上都能调用。getElementById 方法返回匹配指定的id属性的元素节点。
如果没有发现匹配的节点,则返回null。
该方法只能在HTML文档上调用,不能在HTML元素上调用。getElementsByTagName 方法接受一个元素的标签名为参数,返回一个实时的NodeList对象,包含所有匹配的子节点。
该方法在HTML文档上和HTML元素上都能调用。
特殊的是,在HTML文档中,也就是使用document.getElementsByTagName时,会返回一个HTMLCollection对象(与NodeList很像),这是一个“动态”的合集,可以实时反映 HTML文档的变化。getElementsByClassName方法类似getElementsByTagName,只不过它接受的参数为元素的class属性值组成的字符串。
如果参数是一个空格分隔的字符串,元素的class必须符合所有的字符串之中的class才能匹配。
刚开始接触HTMLCollection和NodeList时,对它们之间关系挺莫名其妙的,后来查阅了下资料才稍微有些明白。
具体可以参考这个回答:NodeList 和 HTMLCollection之间的关系?
简单来说就是由于历史原因,DOM规范分为2个部分:Core(最基础的XML解析说明)和HTML(HTML的特有API解析说明)。而NodeList是属于Core的,HTMLCollection 是属于HTML的。
它们返回的都是实时的Node合集,并且可以Node[取索引]来返回子节点。
不同的是NodeList是node节点集合(即包含元素节点,文档节点和注释节点等12种节点类型),而HTMLCollection只包含元素节点集合,所以在HTML文档中,getByElement系列都是HTMLCollection集合。
而有的书上说这些查询元素的方法都是NodeList集合,有的说是HTMLCollection合集,看起来很矛盾,其实是讨论的使用环境不一样罢了 。
另外动态集合虽然很实用,但是在循环它们的时候要特别小心,不要因为忽略了实时变化而造成死循环。
参考:深入理解javascript中的动态集合——NodeList、HTMLCollection和NamedNodeMap
4.如何创建一个元素?如何给元素设置属性?
- document.createElement()方法可以创建新的元素节点,这个方法只接受一个参数,就是创建元素的标签名。
- document.createTextNode()方法可以用来创建新的文本节点,这个方法方法值接受一个参数,就是要插入节点的文本。
- setAttribute()用来给元素设置属性,这个方法接收2个参数,需要设置的属性名和属性值。
举例:
<body>
<div></div>
</body>
<script>
var oDiv = document.getElementsByTagName("div")[0];
var oImg = document.createElement("img");
var txt = document.createTextNode("my images")
oImg.setAttribute("alt","A cup of coffee");
oImg.setAttribute("src","images/coffee.jpg");
oDiv.appendChild(oImg);
oDiv.appendChild(txt);
</script>
5.元素的添加、删除。
- 元素的添加:
- appendChild()方法,让指定元素成为某个现有元素的最后一个子元素。
用语法表示:parent.appendChild(child)
;
举例:
<body>
<ul id="test">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
<script>
var oUl = document.getElementById("test");
var oLi = document.createElement("li");
oUl.appendChild(oLi);
</script>
- insertBefore()方法;让指定的元素插入到某个现有元素的前面。调用此方法,必须告诉它三件事:
1.新元素:你想插入的元素(newElement)
2.目标元素:你想把这个新元素插入到哪个元素(targetElement)之前。
3.父元素:目标元素的父元素(parentElement)
下面是该方法的调用语法:parentElment.insertBefore(newElement,targetElement)
举例:
<body>
<ul id="test">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
<script>
var oUl = document.getElementById("test");
var oLi = document.createElement("li");
oUl.insertBefore(oLi,oUl.firstChild);
</script>
- 元素的删除:
removeChild()方法:删除某个元素,不过要注意的是,该方法不是在待删除的元素上调用,而是在其父元素上调用。
用语法表示就是:parent,removerChild(child).
举例:
<body>
<ul id="test">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
<script>
var oUl = document.getElementById("test");
var oLi = document.querySelectorAll("li")[0];
oUl.removeChild(oLi);
</script>
6.DOM0 事件和DOM2级在事件监听使用方式上有什么区别?
- DOM0级事件就是将一个函数赋值给一个事件处理程序属性。
这些属性通常都是小写,例如onclick,来看一个例子:
<body>
<input id="myBtn" type="button" value="点击我"/>
</body>
<script>
var oBtn = document.getElementById("myBtn");
oBtn.onclick = function(){
console.log(this.id);
}
</script>
使用DOM0 级方法指定的事件处理程序被认为是元素的方法,因此,这个时候的事件处理程序是在元素的作用域中运行,换句话说,程序中的this引用当前元素,所以,上述例子点击按钮后显示的是元素的ID。
另外如果要删除DOM0 级事件处理程序,只要将事件处理程序设置为null即可。
- DOM2 级 定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removerEventListerner()。
所有DOM节点都包含这两个方法,并且都接受3个参数:
1.要处理的事件名
2.作为事件处理程序的函数
3.一个布尔值,布尔值如果是true,表示在捕获阶段调用事件处理程序,如果是flase,表示在冒泡阶段调用事件处理程序。
看例子:
<body>
<input id="myBtn" type="button" value="点击我"/>
</body>
<script>
var oBtn = document.getElementById("myBtn");
oBtn.addEventListener("click",function(){
console.log(this.id);
},false);
oBtn.addEventListener("click",function(){
console.log("Hello world")
},false);
</script>
与DOM0 级的区别在于,使用DOM2 级方法可以添加多个事件处理程序。
另外,通过addEventListener()添加的事件只能通过removeEventListener()来删除,删除时传入的参数与添加时相同,这也就意味着添加的匿名函数是无法删除的。
7.attachEvent与addEventListener的区别?
1.接受的参数:
attachEvent接受2个参数:事件名称,事件处理函数,只支持事件冒泡。
addEventListener接受3个参数:事件名称,事件处理函数,布尔值
2.事件名称:
attachEvent事件名称前面要加“on”,如“onclick”,
addEventListener不需要,如“click”。
3.作用域:
attachEvent会在全局作用域中运行,即this = window。
addEventListener是在元素作用域中运行,this指的是当前元素。
4.事件处理程序的顺序:
addEventListener是按照添加顺序执行。
attachEvent是按照添加顺序相反执行。
5.删除方法:
attachEvent使用detachEvent删除添加事件。
addEventListener使用removeEventListener删除添加事件。
6.兼容:
IE8以及IE8以下只支持attachEvent,
IE9开始支持addEventListener。
8.解释IE事件冒泡和DOM2事件传播机制?
- IE事件冒泡:指的是IE的事件流,事件开始时由最具体的元素(文档嵌套层次最深的那个节点)接受,然后逐渐向上传播到较为不具体的节点(文档)
- DOM2的事件传播机制:指的是DOM2级事件的事件流,包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标收到事件。最后一个是冒泡阶段,事件作出相应。
9.如何阻止事件冒泡?如何阻止默认事件?
- stopPropagation()方法可以阻止事件冒泡,如果bubbles(表明事件是否冒泡)为ture,则可以使用这个方法。
举例:
<body>
<div id="test">
<input id="myBtn" type="button" value="点击我"/>
</div>
</body>
<script>
var oDiv = document.getElementById("test");
var oBtn = document.getElementById("myBtn");
oDiv.addEventListener("click",function(){
console.log(this.id+"我被冒泡了");
},false);
oBtn.addEventListener("click",function(ev){
console.log(this.id);
ev.stopPropagation();
},false);
</script>
- preventDefault()方法可以阻止默认事件,如果cancelable(表明是否可取消事件的默认行为)为ture,则可以使用这个方法。
举例:
<body>
<div id="test">
<a id="myLink" href="http://www.baidu.com">点击我</a>
</div>
</body>
<script>
var link = document.getElementById("myLink");
link.addEventListener("click",function(ev){
ev.preventDefault();//取消a链接点击转跳到指定的URL的默认行为。
},false);
</script>
代码
1.有如下代码,要求当点击每一个元素li时控制台展示该元素的文本内容。不考虑兼容
<ul class="ct">
<li>这里是</li>
<li>饥人谷</li>
<li>前端6班</li>
</ul>
<script>
//todo ...
</script>
解答代码:
方法一, 循环子元素 :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>任务1</title>
</head>
<body>
<ul class="ct">
<li>这里是</li>
<li>饥人谷</li>
<li>任务6班</li>
</ul>
<script>
var oUl = document.getElementsByClassName("ct");
var aLi = oUl[0].getElementsByTagName("li");
for(var i=0,len=aLi.length; i<len; i++){
aLi[i].addEventListener("click",function(){
console.log(this.innerText);
},false);
}
</script>
</body>
</html>
代码1-方法1效果预览
方法二,事件代理:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>任务1</title>
</head>
<body>
<ul class="ct">
<li>这里是</li>
<li>饥人谷</li>
<li>任务6班</li>
</ul>
<script>
var oUl = document.getElementsByClassName("ct")[0];
oUl.addEventListener("click",function(ev){
console.log(ev.target.innerText)
})
</script>
</body>
</html>
2.补全代码,要求:
1.当点击按钮开头添加时在<li>这里是</li>
元素前添加一个新元素,内容为用户输入的非空字符串;当点击结尾添加时在<li>前端6班</li>
后添加用户输入的非空字符串.
2.当点击每一个元素li时,控制台展示该元素的文本内容。
<ul class="ct">
<li>这里是</li>
<li>饥人谷</li>
<li>前端6班</li>
</ul>
<input class="ipt-add-content" placeholder="添加内容"/>
<button id="btn-add-start">开头添加</button>
<button id="btn-add-end">结尾添加</button>
<script>
//todo ...
</script>
解决代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>任务2</title>
</head>
<body>
<ul class="ct">
<li>这里是</li>
<li>饥人谷</li>
<li>前端6班</li>
</ul>
<input class="ipt-add-content" placeholder="添加内容"/>
<button id="btn-add-start">开头添加</button>
<button id="btn-add-end">结尾添加</button>
<script>
var oUl = document.getElementsByClassName("ct")[0];
var oLi = document.getElementsByTagName("li");
var startBtn = document.getElementById("btn-add-start");
var endBtn = document.getElementById("btn-add-end");
var addContent = document.getElementsByClassName("ipt-add-content")[0];
startBtn.addEventListener("click",function(){
if(!addContent.value){
alert("请输入内容");
}
else {
var newLi = document.createElement("li");//注意逻辑顺序,是点击之后再创建一个新的li元素
newLi.innerText = addContent.value;
oUl.insertBefore(newLi,oLi[0]);
}
},false)
endBtn.addEventListener("click",function(){
if(!addContent.value){
alert("请输入内容")
}
else{
var newLi = document.createElement("li");
newLi.innerText = addContent.value;
oUl.appendChild(newLi);
}
},false)
oUl.addEventListener("click",function(ev){
console.log(ev.target.innerText);
},false)
</script>
</body>
</html>
3.补全代码,要求:当鼠标放置在li
元素上,会在img-preview里展示当前li
元素的date-img对应的图片。
<ul class="ct">
<li data-img="1.png">鼠标放置查看图片1</li>
<li data-img="2.png">鼠标放置查看图片2</li>
<li data-img="3.png">鼠标放置查看图片3</li>
</ul>
<div class="img-preview"></div>
<script>
//todo ...
</script>
解决代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>任务2</title>
</head>
<body>
<ul class="ct">
<li data-img="1.jpg">鼠标放置查看图片1</li>
<li data-img="2.jpg">鼠标放置查看图片2</li>
<li data-img="3.jpg">鼠标放置查看图片3</li>
</ul>
<div class="img-preview"></div>
<script>
var oDiv = document.querySelector(".img-preview");
newImg = document.createElement("img");
oDiv.appendChild(newImg);
//方法一:循环子元素,设置事件程序
var oLi = document.getElementsByTagName("li");
for(var i=0,len=oLi.length; i<len; i++){
oLi[i].onmouseover = function(){
var source = this.getAttribute("data-img");
newImg.setAttribute("src",source);
}
}
//方法2:对父元素进行事件监听
// var oUl = document.querySelector(".ct");
// oUl.addEventListener("mouseover",function(ev){
// var source = ev.target.getAttribute("data-img");
// newImg.setAttribute("src",source);
// },false);
</script>
</body>
</html>
代码3-方法1效果预览
代码3-方法2效果预览
4.实现如下图Tab切换的功能
解决代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>任务2</title>
<style type="text/css">
body,ul,li,p{
margin:0;
padding:0;
}
.clearfix:after{
content:'';
display:block;
clear:both;
}
.tab-switch *{
box-sizing:border-box;
}
.tab-switch{
width:600px;
margin:auto;
margin-top:40px;
border:1px solid #ccc;
}
.tab li{
list-style-type:none;
float:left;
width:200px;
height:40px;
line-height:40px;
text-align:center;
cursor:pointer;
border-right:1px solid #ccc;
border-bottom: 1px solid #ccc;
}
.tab li:last-child{
border-right:none;
}
.tab .active {
background-color:#eee;
}
.tab-switch div{
display:none;
height:300px;
padding:20px;
}
.tab-switch .content{
display:block;
}
</style>
</head>
<body>
<div class="tab-switch">
<ul class="tab clearfix">
<li class="active">tab1</li>
<li>tab2</li>
<li>tab3</li>
</ul>
<div class="content">内容1</div>
<div>内容2</div>
<div>内容3</div>
</div>
<script>
var oDiv = document.querySelector(".tab-switch");
aLi = oDiv.getElementsByTagName("li");
aDiv = oDiv.getElementsByTagName("div");
for(var i=0,len=aLi.length; i<len; i++){
aLi[i].index = i;//创建一个index属性来表示div的序列号。
aLi[i].addEventListener("click",function(){
for(var i=0,len=aLi.length; i<len; i++){
aLi[i].className= "";
aDiv[i].style.display = "none";
}
this.className = "active";
aDiv[this.index].style.display="block";
},false);
}
</script>
</body>
</html>
5.实现下图的模态框功能
方法1,直接修改显示效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>任务5</title>
<style type="text/css">
#modal-1{
display:none;
}
a{
text-decoration: none;
color: #333;
}
.cover{
position:fixed;
top:0px;
left:0px;
right:0px;
bottom:0px;
background-color: #000;
opacity:0.4;
z-index:99;
}
.modal-ct{
position:fixed;
top:50%;
left:50%;
transform: translate(-50%,-50%);
width:400px;
border-radius: 3px;
background-color:#fff;
z-index:100;
}
.header {
position:relative;
height:36px;
line-height:36px;
border-bottom: 1px solid #ccc;
}
h3{
margin: 0;
padding-left: 10px;
font-size: 16px;
}
.close{
position:absolute;
right:10px;
top: 10px;
line-height:1;
}
.content{
padding:10px;
}
.footer{
padding:10px;
border-top:1px solid #eee;
}
.footer:after{
content:'';
display:block;
clear:both;
}
.btn{
float:right;
margin-left:10px;
}
</style>
</head>
<body>
<button class="btn-modal">点我!</button>
<div id="modal-1" class="modal-dialog">
<div class="cover"></div>
<div class="modal-ct">
<div class="header">
<h3>我是标题3</h3>
<a class="close" href="#">X</a>
</div>
<div class="content">
<p>我是内容1</p>
<p>我是内容2</p>
</div>
<div class="footer">
<a class="btn btn-confirm" href="#">确定</a>
<a class="btn btn-cancel" href="#">取消</a>
</div>
</div>
</div>
<script>
var btn = document.querySelector(".btn-modal"),
modal = document.querySelector("#modal-1"),
modalCt= document.querySelector("#modal-1 .modal-ct");
btn.addEventListener("click",function(ev){
ev.stopPropagation();
showModal(modal);
});
modalCt.addEventListener("click",function(ev){
ev.stopPropagation();
if(hasClass(ev.target,"close") || hasClass(ev.target,"btn-cancel")){
hideModal(modal);
}
});
document.body.addEventListener("click",function(){
hideModal(modal);
})
function showModal(modal){
modal.style.display = "block";
}
function hideModal(modal) {
modal.style.display = "none";
}
function hasClass(ele, cls){
return ele.className.match(new RegExp('\\b'+cls+'\\b'));
}
</script>
</body>
</html>
代码5-方法1效果预览
方法2,通过添加和删除类名来改变显示效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>任务5-2</title>
<style type="text/css">
a{
text-decoration: none;
color: #333;
}
.cover{
position:fixed;
top:0px;
left:0px;
right:0px;
bottom:0px;
background-color: #000;
opacity:0.4;
z-index:99;
display:none;
}
.modal-ct{
position:fixed;
top:50%;
left:50%;
transform: translate(-50%,-50%);
width:400px;
border-radius: 3px;
background-color:#fff;
z-index:100;
display:none;
}
.header {
position:relative;
height:36px;
line-height:36px;
border-bottom: 1px solid #ccc;
}
h3{
margin: 0;
padding-left: 10px;
font-size: 16px;
}
.close{
position:absolute;
right:10px;
top: 10px;
line-height:1;
}
.content{
padding:10px;
}
.footer{
padding:10px;
border-top:1px solid #eee;
}
.footer:after{
content:'';
display:block;
clear:both;
}
.btn{
float:right;
margin-left:10px;
}
.active{
display:block;
}
</style>
</head>
<body>
<button class="btn-modal">点我!</button>
<div id="modal-1" class="modal-dialog ">
<div class="cover"></div>
<div class="modal-ct">
<div class="header">
<h3>我是标题3</h3>
<a class="close" href="#">X</a>
</div>
<div class="content">
<p>我是内容1</p>
<p>我是内容2</p>
</div>
<div class="footer">
<a class="btn btn-confirm" href="#">确定</a>
<a class="btn btn-cancel" href="#">取消</a>
</div>
</div>
</div>
<script>
var oBtn = document.querySelector(".btn-modal"),
oCover = document.querySelector(".cover"),
oModalCt= document.querySelector("#modal-1 .modal-ct");
oBtn.addEventListener("click",function(ev){
ev.stopPropagation();
addClass(oCover,"active");
addClass(oModalCt,"active");
});
oModalCt.addEventListener("click",function(ev){
ev.stopPropagation();
if(hasClass(ev.target,"close") || hasClass(ev.target,"btn-cancel")){
removeClass(oCover,"active");
removeClass(oModalCt,"active");
}
});
document.body.addEventListener("click",function(ev){
removeClass(oCover,"active");
removeClass(oModalCt,"active");
});
function hasClass(ele, cls){
var reg = new RegExp('\\b'+cls+'\\b','g');
return reg.test(ele.className);
};
function addClass(ele, cls){
if(!hasClass(ele,cls)){
ele.className += " "+cls
}
};
function removeClass(ele,cls){
if(hasClass(ele,cls)){
ele.className = ele.className.replace(cls,"")
}
};
</script>
</body>
</html>
本文版权归本人和饥人谷所有,转载请注明来源。