JavaScript核心 BOM 和DOM
一、区分什么是BOM 什么是DOM
window对象
window对象既是通过 JavaScript 访问浏览器窗口的一个接口,又是 ECMAScript 规定的 Global 对象。这意味着在网页中定义的任何一个对象、变量和函数,都以 window 作为其 Global 对象,因此有权访问parseInt()等方法。
窗口位置:screenLeft 和 screenTop
IE、 Safari、 Opera 和 Chrome 都提供了
screenLeft 和 screenTop 属性,分别用于表示窗口相对于屏幕左边和上边的位置。 Firefox 则在screenX 和 screenY 属性中提供相同的窗口位置信息, Safari 和 Chrome 也同时支持这两个属性。
Opera虽然也支持 screenX 和 screenY 属性,但与 screenLeft 和 screenTop 属性并不对应,因此建议大家不要在 Opera 中使用它们。使用下列代码可以跨浏览器取得窗口左边和上边的位置。
var leftPos = (typeof window.screenLeft == "number") ? window.screenLeft : window.screenX; var topPos = (typeof window.screenTop == "number") ? window.screenTop : window.screenY;
窗口大小 :innerWidth、 innerHeight、 outerWidth 和 outerHeight
跨浏览器确定一个窗口的大小不是一件简单的事。 IE9+、 Firefox、 Safari、 Opera 和 Chrome 均为此提 供了 4 个属性: innerWidth、 innerHeight、 outerWidth 和 outerHeight。在 IE9+、 Safari 和 Firefox 中, outerWidth 和 outerHeight 返回浏览器窗口本身的尺寸(无论是从最外层的 window 对象还是从 某个框架访问)。在 Opera 中,这两个属性的值表示页面视图容器①的大小。而 innerWidth 和 innerHeight 则表示该容器中页面视图区的大小(减去边框宽度)。在 Chrome 中, outerWidth、 outerHeight 与 innerWidth、 innerHeight 返回相同的值,即视口( viewport)大小而非浏览器窗口大小。 IE8 及更早版本没有提供取得当前浏览器窗口尺寸的属性;不过,它通过 DOM 提供了页面可见区域 的相关信息。 在 IE、 Firefox、 Safari、 Opera 和 Chrome 中, document.documentElement.clientWidth 和 document.documentElement.clientHeight 中保存了页面视口的信息。在 IE6 中,这些属性必须在 标准模式下才有效;如果是混杂模式,就必须通过 document.body.clientWidth 和 document.body. clientHeight 取得相同信息。而对于混杂模式下的 Chrome,则无论通过 document.documentElement 还是 document.body 中的 clientWidth 和 clientHeight 属性,都可以取得视口的大小。 虽然最终无法确定浏览器窗口本身的大小,但却可以取得页面视口的大小,如下所示。
/* //窗口内部宽高,不含工具栏,地址栏等内容,包含滚动条 console.log(window.innerWidth,window.innerHeight);//5 // 当前窗口宽高包含工具等. console.log(window.outerWidth,window.outerHeight);//5 // 窗口当前的位置,只能获取,不能设置 console.log(window.screenLeft,window.screenTop);//5
导航和打开窗口 :window.open()
使用 window.open()方法既可以导航到一个特定的 URL,也可以打开一个新的浏览器窗口。
这个方法可以接收 4 个参数:要加载的 URL、窗口目标、一个特性字符串以及一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。通常只须传递第一个参数,最后一个参数只在不打开新窗口的情况下使用。
window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");
location一般是修改地址栏或者获取地址栏中的内容(针对地址栏操作)
跳转历史
客户端(浏览器)信息
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> /* * window对象既是通过 JavaScript 访问浏览器窗口的一个接口,又是 ECMAScript 规定的 Global 对象。这意味着 在网页中定义的任何一个对象、变量和函数,都以 window 作为其 Global 对象,因此有权访问parseInt()等方法。*/ // window.document;(DOM) document自身称为DOM // window是权限最高的对象,他可以找到我们要操作的所有子目标 var a=window.open("http://www.163.com","网易","width=400,height=400");//3 // a.close(); a.alert("确定"); window.close();//3 /* //窗口内部宽高,不含工具栏,地址栏等内容,包含滚动条 console.log(window.innerWidth,window.innerHeight);//5 // 当前窗口宽高包含工具等. console.log(window.outerWidth,window.outerHeight);//5 // 窗口当前的位置,只能获取,不能设置 console.log(window.screenLeft,window.screenTop);//5 /!* var id=setTimeout(function () { location.reload();//3秒后重载页面,给PHP等服务端工程师使用 clearTimeout(id); },3000);*!/ // location.href="http://www.163.com"; //跳转页面 3 // location.assign("http://www.163.com"); //跳转页面 5 // location.replace("http://www.163.com"); //跳转页面 5 // document.addEventListener("click",clickHandler); function clickHandler(e) { location.href="a.html";//跳转页面,有历史记录,属性设置 // location.assign("http://www.163.com");//跳转页面,有历史记录,方法设置 // location.replace("http://www.163.com");//跳转页面,没有历史记录 } console.log(location.hash);//获取地址栏中#后面内容 5 console.log(location.search);//获取地址栏中?后面的内容 1 console.log(location.hostname);//域名 console.log(location.pathname);//目录 console.log(location.port);//端口号 console.log(location.protocol);//协议 // 相当于设备屏幕宽高 console.log(screen.availWidth,screen.availHeight);//不带屏幕下面的系统部件 console.log(screen.width,screen.height);//包含系统部件 console.log(navigator.userAgent);//3 console.log(navigator.appName);//5 console.log(navigator.appVersion);//5 console.log(navigator.platform);//5 class Box{ constructor(){ } static get getInstance(){ if(!Box._instance){ Object.defineProperty(Box,"_instance",{enumerable:false,value:new Box()}); } return Box._instance; } }*/ </script> </body> </html>
DOM(Document Object Model)
节点属性 nodeName nodeValue nodeType
<body><div id="div0"></div> <ul id="a"> <li></li> <li class="abc"></li> <li class="abc"></li> <li class="abc def"></li> </ul> <ul id="b"> <li abc="r"></li> <li class="abc"></li> <li class="abc"></li> <li></li> </ul> <!--以get方式 将input输入内容提交到地址栏中?后面--> <form action="#" method="get"> <!--input的name属性主要用于表单。对应的值,一般单选和多选必须设置value值--> <input type="radio" name="ab" value="a"> <input type="radio" name="ab" value="b"> <input type="radio" name="ab" value="c"> <input type="radio" name="ab" value="d"> <input type="text" name="user"> <input type="password" name="pass"> <input type="submit"> </form> <script> var div0=document.getElementById("div0"); var div1=div0.cloneNode(false);//浅复制 document.body.appendChild(div1); /* * 4 * 节点 是树形结构,不能交叉,因此整个DOM就是一个节点数 * nodeName 如果是标签,nodeName就是标签名 * nodeType 可以用来判断当前是不是文档节点了,文档节点是9 * nodeValue 如果是注释,nodeValue就是注释的内容 * */ console.log(document.body.nodeName); console.log(document.body.firstChild.nodeName); //body的第一个子节点 包括换行符和元素。注释是#comment , 换行是 #text,标签就显示标签名DIV console.log(document.body.nodeType); // 元素 1,属性 2,文本 3,注释 8, 文档 9 console.log(document.body.firstChild.nodeType); console.log(document.nodeType); console.log(document.nodeValue); console.log(document.body.nodeValue); console.log(document.body.firstChild.nodeValue); document.body.innerHTML+=document.body.firstChild.nodeValue; var div0=document.getElementById("div0"); console.log(div0.nodeName) </script>
获取Dom元素
document.getElementById("div0");//根据id名获取DOM元素,唯一一个 var lis=document.getElementsByTagName("li");//根据标签名获取所有的列表 lis=document.getElementsByClassName("abc");//根据标签中class名获取元素列表 console.log(lis); //HTMLCollection HTML标签元素列表类型,是类数组,但是不能使用数组的方法 var radio=document.getElementsByName("ab"); //根据表单元素的name获取节点列表NodeList console.log(radio); //NodeList(4) [input, input, input, input] radio.forEach(function (t) { console.log(t); }); // NodeList 节点列表 具有forEach的遍历方法 // 根据CSS选择器选择元素,使用简单 但是效率没有上述方法高 // document.querySelector(); 找到第一个 // document.querySelectorAll(); 找到全部的 返回列表 var li1=document.querySelectorAll("#b .abc");//NodeList console.log(li1); var li2=document.querySelector("[abc=r]"); //属性选择器中属性值等于什么 console.log(li2); //document全文档查找 var ul0=document.getElementById("a"); //从ul0这个父级元素的子元素中查找className是abc的元素 var li3=ul0.getElementsByClassName("abc");
节点遍历 --->子节点 子孙节点 父节点 。。。
<body> <div> <ul> <li></li> <li></li> <li></li> <li></li> </ul> </div> <script> //在列表中找第0元素返回 var div=document.getElementsByTagName("div")[0]; console.log(div.childNodes);//所有子节点,包含换行和元素,注释;NodeList console.log(div.children);//获取所有子元素,只获取标签;HTMLCollection console.log(div.parentNode);//获取父节点 console.log(div.parentElement);//获取父元素 console.log(div.firstChild);//获取第一个子节点 console.log(div.firstElementChild);//获取第一个子元素 console.log(div.lastChild);//获取最后一个子节点 console.log(div.lastElementChild);//获取最后一个子元素 console.log(div.previousSibling);//获取上一个兄弟节点 console.log(div.previousElementSibling);//获取上一个兄弟元素 console.log(div.nextSibling);//获取下一个兄弟节点 console.log(div.nextElementSibling);//获取下一个兄弟元素 for(var i=0;i<div.firstElementChild.children.length;i++){ div.firstElementChild.children[i].innerHTML=i+1; } </script> </body>
节点的增 删 改 查 复制
<body> <button></button> <div id="a"> <ul id="b"> <li></li> <li></li> <li></li> <li></li> </ul> </div> <script> /* 创建节点 添加节点*/ var bn=document.querySelector("button"); var text=document.createTextNode("按钮");//创建文本节点;一般用于节点内有其他元素 bn.appendChild(text); bn.addEventListener("click",clickHandler); function clickHandler(e) { // document.body.innerHTML+="<div></div>"; //因为会被覆盖,因此不可以创建多次 var div=document.createElement("div");//根据标签名创建元素 document.body.appendChild(div);//把div插入在body的尾部 } var div=document.createElement("div"); console.log(div); console.log(div.__proto__); //div 继承了所有的属性,多次向body中添加标签会降低效率, // 因此最好全部创建完之后放在一个容器div中,一次添加到body中 var ul=document.createElement("ul"); //创建一个ul容器 for(var i=0;i<10;i++){ var li=document.createElement("li"); //创建li ul.appendChild(li); //先将li一个个放到ul容器中 } document.body.appendChild(ul); //最后一次将ul 添加到body中 // 如果所有的标签直接在body下 没有容器时,这时需要一个临时包袱 var elem=document.createDocumentFragment();//文档碎片 相当于一个包袱 先将创建的标签扔到包袱里,最后把包袱加入到body中。包袱用完之后(包袱加到body中)就扔掉了 for(var j=0;j<20;j++){ var divs=document.createElement("div"); elem.appendChild(divs); } document.body.appendChild(elem); // 父容器.appendChild(子元素) // 父容器.insertBefore(子元素,要插入在谁的前面) document.body.insertBefore(elem,ul); document.body.insertBefore(elem,document.body.firstElementChild);//插入在最前面 var div1=document.createElement("div"); div1.textContent="内容";//给标签添加文本内容;节点内没有其他元素,可以直接使用 console.log(div1.textContent); /* * 删除 * remove() 自己删自己 * removeChild() 删除子元素 * */ // ul.remove(); // var li1=ul.firstElementChild; // ul.removeChild(li1);//删除第一个子元素 /* 删除所有子元素 var len=ul.children.length; for(var s=0;s<len;s++){ ul.lastElementChild.remove(); } 注意(易错):删除过程中 ul.children.length 长度在变化,要将放在外面 for(var s=0;s<ul.children.length;s++){ ul.lastElementChild.remove(); } */ /* * 复制 * 1.复制当前元素及当前元素的子元素 ,DOM元素深复制 cloneNode(true) * 2.仅复制当前元素及元素的属性,DOM元素浅复制 cloneNode(false); * * */ // var div2=document.getElementById("a"); // document.body.appendChild(div2);//如果重新插入已有的元素,相当于移位 // document.body.appendChild(div2.cloneNode(true));//深复制 // document.body.appendChild(div2.cloneNode(false));//深复制 // console.log(div2); /* 新元素 取代旧元素 * 父容器.replaceChild(新元素,旧元素); * */ // var p=document.createElement("p"); // document.body.replaceChild(p,div2);//替换节点 // var img=document.createElement("img"); /*var img=new Image(); img.src=""; function createElem(type,parent,style) { // 可以将创建节点 写成一个函数,多次调用 } createElem("div",document.body,{"100px",height:"100px",backgroundColor:"red"})*/ </script> </body>
DOM属性
<body> <!-- HTML 标签属性命名:不区分大小,所以全部用小写,单词与单词之间使用横杆连接,标签属性可以看为一个公开属性--> <div id="div0" class="divStyle" title="abc" xietian="abc" main-data="abc" ></div> <button>按钮</button> <button>按钮</button> <button>按钮</button> <button>按钮</button> <button>按钮</button> <button>按钮</button> <button>按钮</button> <script> console.log(document.body); console.log(document.title); console.log(document.URL);//url地址 console.log(document.domain);//域名 /* 跑马灯title*/ /*str="你有一封信邮件,请前往邮箱查收"; var num=0; var str1=""; //console.log(str.substr(0,11)) setInterval(animation,500); function animation() { str1=str.substring(num,num+11); if(num+11>str.length-1) { var s=num+11-(str.length-1); str1+=str.substring(0,s); } num++; if(num>str.length-1) num=0; document.title=str1; console.log(str1); }*/ // 第二种写法 /*str="你有一封信邮件,请前往邮箱查收 "; var num=0; setInterval(animation,100); function animation() { var str1=""; var s=num; while (str1.length<11){ str1+=str[s]; s++; if(s>str.length-1){ s=0; } } num++; if(num>str.length-1)num=0; document.title=str1; }*/ /* * DOM 元素有两个属性 标签属性 对象属性 * * 部分系统的标签属性和对象属性完全相同,如: * id name type checked title src href style * * 注意: * class属性在对象属性中是className * */ /*var div=document.createElement("div"); div.a=10; //DOM 对象属性,给div创建一个属性a="10" console.log(div.a); document.body.appendChild(div); var div0=document.getElementById("div0"); console.log(div0.className); //divStyle console.log(div0.title); //abc var bns=document.getElementsByTagName("button"); for(var i=0;i<bns.length;i++){ // bns[i].addEventListener("click",clickHandler); bns[i].n=i; //给每一个bns 都添加一个属性n=i } function clickHandler(e) { this.textContent=this.textContent+this.n; }*/ /* * 标签属性 * 通过js设置获取标签属性 * 设置属性setAttribute或者获取属性getAttribute,属性值都会转化为字符类型 * */ // console.log(document.querySelector("[main-data]")); // console.log(div0.main-data); //获取标签属性 // console.log(div0.getAttribute("main-data")); // console.log(div0.getAttribute("xietian")); //设置标签属性 属性名 属性值 // div0.setAttribute("xietian",100); // div0.setAttribute("boolean",false); // 删除属性 // div0.removeAttribute("boolean"); /* * DOM style样式 * 取消原有css中-,将-后面的字母变大写就可以 * 这种方法是增加行内样式的方法<div style="background-color: red"></div> * */ // div0.style.backgroundColor="red"; //注意程序是从上往下加载,最后加载<style></style>, // console.log(div0.style.width) //在这里直接获取div0的width 是获取不到的,可以用下面方法 // console.log(getComputedStyle(div0).width);//除IE外所有浏览器使用这种方法获取计算后样式 // console.log(div0.currentStyle.width);//IE获取计算后样式 // var width; // try { // width=getComputedStyle(div0).width; // }catch (error){ // width=div0.currentStyle.width; // } // console.log(width); </script> </body>
DOM的宽高和位置
补充:margin padding border
div{ width: 100px; height: 100px; margin: 20px; //外边距 padding: 30px; //内边距 overflow: scroll; background: pink; border: 4px solid black; //边框 }
偏移量 ---> offsetWidth offsetHeight
偏移量( offset dimension),包括元素在屏幕上占用的所有可见的空间。元素的可见大小由其高度、宽度决定,包括所有内边距、滚动条和边框大小(注意,不包括外边距)。
DOM元素的大小和位置 ---> ele.getBoundingClientRect()
right = left + width
bottom = top + height
客户区大小 ---> clientHeight clientWidth
元素的客户区大小( client dimension),指的是元素内容及其内边距所占据的空间大小 ,即客户区大小就是元素内部的空间大小,因此滚动条占用的空间不计算在内 。
滚动大小
滚动大小( scroll dimension),指的是包含滚动内容的元素的大小 ,有些元素(例如<html>元素)即使没有执行任何代码也能自动地添加滚动条;
但另外一些元素,则需要通过 CSS 的overflow 属性进行设置才能滚动。以下是 4 个与滚动大小相关的属性。
scrollHeight:在没有滚动条的情况下,元素内容的总高度。
scrollWidth:在没有滚动条的情况下,元素内容的总宽度。
scrollLeft:被隐藏在内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动位置。
scrollTop:被隐藏在内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置。
load和scroll事件
<body> <div></div> <script> //load 加载事件 var img = new Image(); img.addEventListener("load", loadHandler); img.src = "img/icon01.png"; var s = 0; s++; function loadHandler(e) { console.log(this); console.log(this.width); //微任务和宏任务 document.querySelector("div").appendChild(this); } console.log(s); // 滚动条滚动事件scroll document.addEventListener("scroll",scrollHandler); function scrollHandler(e) { console.log("aaa"); } </script> </body>