js 的组成
- ECMA Script
- Bom
- Dom
Dom 文档对象模型
文档树
获取元素
根据id获取元素
对象是有类型的,getElementById这个方法只能通过document来调用
<script>
var div_first = document.getElementById("first");
console.log(div_first);
</script>
根据标签名获取元素
var divs=document.getElementsByTagName("div");//伪数组
获取的是动态集合
获取子代元素
<div id="first">
<div id="first_inner"></div>
<div></div>
</div>
<script>
var div_first = document.getElementById("first");
var div_first_inner = div_first.getElementsByTagName("div")[0];
console.log(div_first_inner);
</script>
获取元素的其他方式
getElementsByName
- 在IE, OP浏览器会查id
var arr=document.getElementsByClassName("dd");
console.log(arr)
getElementsByClassName的问题
- ie9之后才支持
根据选择器获取元素
ie8之后才支持
querySelector
id是# 类是.
只能获取一个元素
<div id="first" class="dd">
<div id="first_inner"></div>
<div class="dd"></div>
</div>
<script>
var div= document.querySelector("#first>.dd")
console.log(div);
</script>
querySelectorAll
返回的是元素的数组
<div id="first" class="dd">
<div id="first_inner"></div>
<div class="dd"></div>
</div>
<script>
var div= document.querySelectorAll("#first")[0];
console.log(div);
</script>
注册事件
事件名称 | 事件的作用 |
---|---|
onclick | 点击事件 |
点击事件
<input type="button" value="确定" id="btn">
<script>
var btn=document.getElementById("btn");
btn.onclick=function () {
console.log("点击")
}
</script>
<script>
var btn=document.getElementById('btn');
btn.addEventListener('click',function () {
console.log('======');
})
btn.addEventListener('click',function () {
console.log('111======');
})
</script>
老版本的ie支持的点击事件
btn.attachEvent('onclicl',function () {
console.log('111======');
});
获取焦点事件和失去焦点事件
<script>
var text = document.getElementById('text');
text.onfocus = function () {
//获取焦点的事件
if (this.value === "请输入搜索关键字") {
this.value='';
}
this.className='black';
}
text.onblur=function () {
//失去焦点
if (this.value === '') {
this.value='请输入搜索关键字';
}
this.className='grey';
}
</script>
addEventListener
- 可重复注册不会被覆盖
- 浏览器兼容问题,ie9以后才兼容
点击事件的兼容性写法
/**
* 注册事件的兼容性写法
* @param element
* @param eventName
*/
function addEventListener(element, eventName,fn) {
if (element.addEventListener) {
element.addEventListener(eventName,fn);
}else if (element.attachEvent) {
element.attachEvent('on'+eventName,fn);
}else {
element['on'+eventName]=fn;
}
}
移除事件
var btn=document.getElementById('btn');
btn.onclick=function () {
console.log('===77===');
btn.onclick=null;
}
- 如果通过addEventListener注册事件有想要移除事件,就不能用匿名函数
var btn=document.getElementById('btn');
var fn=function(){
console.log("===8888===")
btn.removeEventListener('click',fn);
}
btn.addEventListener('click',fn);
- ie老版本 移除事件的方法
var btn = document.getElementById('btn');
function btnClick() {
console.log('111======');
btn.detachEvent('onclick', btnClick)
}
btn.attachEvent('onclick', btnClick);
移除事件的兼容性写法
/**
* 移除事件的兼容性写法
* @param element
* @param eventName
*/
function removeEventListener(element, eventName, fn) {
if (element.removeEventListener) {
element.removeEventListener(eventName,fn);
}else if (element.detachEvent) {
element.detachEvent('on'+eventName,fn);
}else {
element['on'+eventName]=null ;
}
}
事件冒泡
事件由里向外传递
事件的三个阶段
事件发生的阶段 | eventPhase 值 |
---|---|
事件捕获 | 1 |
执行当前点击的元素(目标阶段) | 2 |
事件冒泡 | 3 |
元素.onclick 是无法进行事件捕获的
事件委托
<script src="../utils/JSUtils.js"></script>
<script>
my$('ul').addEventListener('click',function (e) {
//e.target 是真正触发事件的元素对象
//e 事件参数,也是事件对象
for (let i = 0; i < my$('ul').children.length; i++) {
my$('ul').children[i].removeAttribute('class');
}
e.target.setAttribute('class','highlight');
console.dir(e.target.innerText);
})
</script>
事件对象
eventPhase | 事件发生的阶段(数值) | |
target | 获取真正触发事件的对象(通常指标签对象) | 老版本ie不兼容 |
currentTarget | 注册事件的对象 | |
type | 事件的类型 | |
clientX,clientY | 相对于浏览器可视界面的横纵坐标 | |
pageX,pageY | 相对于文档的横纵坐标 | ie9之前不兼容 |
如何阻止事件冒泡
标准dom方法
e.stopPropagation()
老版本ie阻止事件冒泡的方法,谷歌现也支持
e.cancelBubble=true;
t.addEventListener('click',function (e) {
console.log(e.eventPhase)
console.dir(e.target);
console.log(e.type)
console.dir(e.currentTarget);
console.log("thir");
//e.stopPropagation();//阻止事件冒泡
e.cancelBubble=true;
});
target 兼容写法
var target=e.target||e.srcElement;
获取浏览器滚动的距离
document.body.scrollLeft | 横向滚动的距离 |
document.body.scrollTop | 纵向滚定的距离 |
获取页面滚动距离的兼容问题
/**
* 获取浏览器的滑动距离
* @returns {{scrollLeft: number, scrollTop: number}}
*/
function getScroll() {
return {
scrollLeft: document.body.scrollLeft || document.documentElement.scrollLeft,
scrollTop: document.body.scrollTop || document.documentElement.scrollTop
}
}
获取鼠标在页面上的位置的兼容问题
/**
* 获取鼠标在页面位置
* @param e 鼠标的时间对象
* @returns {{pageY: (*|number), pageX: (*|number)}}
*/
function getMousePosition(e) {
return{
pageX:e.pageX||e.clientX+getScroll().scrollLeft,
pageY:e.pageY||e.clientY+getScroll().scrollTop
};
}
取消默认行为的执行
return false; | |
e.preventDefault(); | |
e.returnValue=false; | ie老版本的方法,谷歌也支持 |
<a id="a" href="http://www.baidu.com">666</a>
<script>
my$("a").onclick=function () {
console.log("====???");
return false;
}
</script>
<a id="a" href="http://www.baidu.com">666</a>
<script>
my$("a").onclick = function (e) {
console.log("====???");
e = e || window.event;
e.preventDefault();
}
</script>
<a id="a" href="http://www.baidu.com">666</a>
<script>
my$("a").onclick = function (e) {
console.log("====???");
e = e || window.event;
// e.preventDefault();
e.returnValue=false;//ie老版本的方法,谷歌也支持
}
</script>
键盘事件
onkeydown | 键盘按下 |
onkeyup | 键盘按下松开 |
keyCode | 键盘的ascll码a=65,48-57是数字 |
key | 键值 |
<input type="text" id="text">
<script>
my$('text').onkeydown=function (e) {
console.log("onkeydown",e.keyCode,e.key);
if ((e.keyCode<48||e.keyCode>57)&&e.keyCode!==8){
e.preventDefault();
//e.cancelBubble=true;
}
}
my$('text').onkeyup=function (e) {
console.log("onkeyup",e.keyCode,e.key);
}
</script>
属性操作
自定义属性
获取自定义属性
<div id="555" persionid="dd"></div>
<script>
var div=document.getElementById("555");
console.log(div.persionid);//获取不到的
console.log(div.getAttribute("persionid"));
</script>
设置自定义属性
setAttribute 不仅可以设置自定义属性,也可以设置已有属性
<script>
div.tag='777';//设置不了
div.setAttribute('tag','666');
</script>
删除属性
li.removeAttribute('class')
非表单元素的属性
获取标签的某个属性值
标签.属性名
<a href="www.baidu.com" title="百度" id="link">点击跳转</a>
<img src="../file/5d089c5a851d1-家长订阅.png" alt="图片加载失败" id="img">
<script>
var link=document.getElementById('link');
var img=document.getElementById('img')
console.log(link.id);
console.log(link.href);
console.log(link.title);
</script>
获取class属性
className
<button id="btn">影藏</button>
<div id="tag" class="show"></div>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
let div = document.getElementById("tag");
console.log(div.className)
if (div.className == "show") {
btn.innerText = "显示"
div.className = "hidden";
} else {
btn.innerText = "影藏"
div.className = "show"
}
}
</script>
表单元素
表单元素的属性
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
var text = document.getElementById('text');
if (!text.disabled){
btn.innerText='启用';
}else {
btn.innerText='禁用';
}
text.disabled = !text.disabled;
console.log(text.disabled)
console.log(text.type)
}
</script>
如何取消a标签的默认跳转效果
onclick事件里拦截 retrun false
arr_a[i].onclick=function () {
p.innerText=arr[i].name;
console.log(arr[i].name);
show.src=arr[i].pic;
return false;//取消a的默认行为
}
innerText 与innerHTML,textContent 的区别
innerText | 如果内容中有标签会把标签过滤掉,去掉空格换行 | 旧版的火狐,ie9以下只支持 |
innerHTML | 如果内容中有标签会把标签获取到,原封不动获取(包括空格换行) | 效率较低,因为要解析标签 |
textContent | 如果内容中有标签会把标签过滤掉,去掉空格换行 |
兼容处理
/**
* 获取标签内容的兼容方法
* @param element
*/
function getInnerText(element) {
if (typeof element.innerText === 'string') {
return element.innerText;
} else {
return element.textContent;
}
}
样式操作
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
<script>
var ul = document.getElementById("ul");
var arr = ul.children;//获得所有的子元素
for (let i = 0; i < arr.length; i++) {
if (i%2==0){
//奇数行
arr[i].style.backgroundColor='#f00';
}else {
arr[i].style.backgroundColor='#0f0';
}
}
</script>
设置样式要.style设置
节点操作
##节点与元素的区别
- 个人认为元素相当于html的标签
- 节点的含义就比较广泛,包含了元素
节点的类型 | nodeName | nodeType | nodeValue |
---|---|---|---|
元素节点 | 1 | null | |
属性节点 | |||
文本节点 | #text | 3 | 空格,换行,字符 |
注释节点 | #comment | 8 | 注释的内容 |
- 换行+空白 属于文本节点
父子节点
获取所有的子节点
作用 | ||
---|---|---|
childNodes | 获取所有的子节点包括:元素节点,文本节点,注释节点 | NodeList |
children | 获取所有的子元素 | HTMLCollection |
hasChildNodes | 判断某个元素是否含有子节点(包含文本节点) | |
firstElementChild | 获得第一个元素节点 | ie9以上,有兼容问题 |
<script>
//获取子节点
console.log(div.firstChild);
console.log(div.firstElementChild)
console.log(div.hasChildNodes());
console.log(typeof div.childNodes);//子节点
console.dir(div.childNodes);
console.log(typeof div.children);//子元素
console.dir(div.children);
</script>
获得第一个元素节点的兼容性写法
/**
* 获取第一个子元素的兼容性代码
* @param element
* @returns {ChildNode | *|Element}
*/
function getFirstElement(element) {
if (element.firstElementChild){
return element.firstElementChild;
}else {
var arr=element.childNodes;
for (let i = 0; i <arr .length; i++) {
if (arr[i].nodeType===1){
return arr[i];
}
}
}
}
组织a标签跳转的几种写法
<li class="current"><a href="javascript:void 0;">AA</a></li>
<li><a href="javascript:void(0);">BB</a></li>
<li><a href="javascript:undefined;">CC</a></li>
兄弟节点
方法 | |
---|---|
nextSibling | 获取下一个兄弟节点 |
nextElementSibling | 获取下一个兄弟元素 |
previousSibling | 获取上一个兄弟节点 |
previousElementSibling | 获取上一个兄弟元素 |
/**
* 获取上一个兄弟元素
* @param element
* @returns {Node | (() => (Node | null)) | ActiveX.IXMLDOMNode|null}
*/
function getPreviousElementSibling(element) {
let el=element;
while (el=el.previousSibling){
if (el.nodeType===1){
return el;
}
}
return null;
}
/**
* 获取下一个兄弟元素
* @param element
* @returns {ChildNode | (() => (Node | null)) | ActiveX.IXMLDOMNode | Node|null}
*/
function getNextElementSibling(element) {
let el=element;
while (el=el.nextSibling){
if (el.nodeType===1){
return el;
}
}
return null;
}
动态创建元素
方式 | 特点 |
---|---|
document.write | 会把整个页面覆盖掉 |
innerHTML | |
createElement | 在内存中创建一个dom对象(推荐 ) |
通常innerHTML的性能比createElement要高
- 如果使用innerHTML里的子元素注册了事件,又把
innerHTML=’’,就会导致元素清空,但事件依然绑定,引发内存泄漏 - removeChild 清空元素并且清除掉元素的事件
document.write innerHTML
<script>
var div=document.getElementById("tag");
//document.getElementById("tag").innerHTML="666";
//document.write("Name<p>hcy</p>");
var xhr=new XMLHttpRequest();
xhr.open('get','./photo.php');
xhr.send();
xhr.responseType='json';
xhr.onreadystatechange=function () {
if (this.readyState!=4){
return;
}
var array=this.response;
console.log(array);
var html=[];
html.push('<ul>');
for (let i = 0; i < array.length; i++) {
html.push("<li class=\"myli\">");
html.push(array[i].name);
html.push('</li>');
}
html.push('</ul>');
div.innerHTML=html.join('');
}
</script>
createElement
<script>
//在内存中创建一个dom对象
var p=document.createElement("p");
p.innerText=666;
var div=document.getElementById("tag");
div.appendChild(p);
</script>
动态移除元素
removeChild | 必须要直接父级的标签删除子标签,不能隔代删除 |
insertBefore | 把元素插入到页面的指定位置 |
replaceChild | 把当前元素的标签替换 |
<script>
//在内存中创建一个dom对象
var p=document.createElement("p");
p.innerText=999;
var div=document.getElementById("tag");
//div.appendChild(p);
div.insertBefore(p,div.children[0]);
</script>
<script>
//在内存中创建一个dom对象
var p=document.createElement("p");
p.innerText=999;
var div=document.getElementById("tag");
//div.appendChild(p);
div.replaceChild(p,div.children[0]);
</script>