通过JS中提供的一系列属性和方法,获取页面中元素样式信息
<div id="box" name="abc" class="container" index="1"></div>
box.attributes.getNamedItem("id");
//通过属性名获取属性值
box.classList.add('test');
box.classList.remove('container');
//通过classList操作class属性值
//将div区域设置为可编辑
box.contentEditable = true
var box = document.getElementById("box");
var width = box.clientWidth;
var height = box.clientHeight;
var borderLeft = box.clientLeft;
var borderRight = box.clientRight;
若左右/上下边框一样,则offsetWidth = clientWidth+clientLeft*2
如果容器有内容溢出,则:scrollWidth为真实内容宽度加上左填充,scrollHeight为真实内容高度加上上填充。
同一个浏览器,对于元素是否设置overflow:hidden样式而获取的到的结果是不一样的;在不同的浏览器中获取到的结果也是不一样的,获取到的结果都是约等于值
关于JS盒子模型的取值问题 通过这些属性值获取的结果永远都是整数,浏览器在获取结果时会在原值基础上自动进行四舍五入
clientWidth/clientHeight获取当前浏览器可视窗口宽高
document.documentElement.scrollHeight当前整个页面的实际高度,但是是一个约等于值;
document.documentElement.scrollTop值一直为0,若要获取卷去的高度,则应该使用
document.body.scrollTop
兼容写法,准备两套获取方法:
document.documentElement[attr] || document.body[attr];
若设置值也要写两套 编写一个浏览器盒子模型的方法
//若只传了attr则默认为获取属性值;若都传递了两个参数,则为设置该属性值
function win(attr,val){
//获取
if(typeof val === "undefined"){
return document.documentElement[attr] || document.body[attr];
}
//设置
document.documentElement[attr] = val;
document.body[attr] = val;
}
ele.style.width 这种方式只能获取元素的行内样式,css中的获取不到
window提供了getComputedStyle()方法,获取所有经过浏览器计算过的样式
浏览器计算过的样式:只要当前元素标签在页面中显示,就表示它的所有样式经浏览器计算过或渲染过
window.getComputedStyle(curEle,null);
//获取的是元素所有的样式内容
但是在IE6-8是不兼容的,因为window下没有这个属性;在IE6-8可以使用currentStyle来获取所有经浏览器计算过的样式(currentStyle仅在IE6-8下存在)
var a = box.currentStyle.width;
处理兼容的方式:
function getCss(curEle,attr){
//获取当前元素所有经过浏览器计算过的样式
var val = null;
try{
val = window.getComputedStyle(curEle,null)[attr];
}catch(e){
val = curEle.currentStyle[width];
}
return val;
}
这个方法必须保证try中的代码在不兼容的浏览器中执行的时候报错,这样才能用catch捕获并进行处理;所以不管当前浏览器是否兼容该方法,都要先执行一遍try块中的代码(这样比较消耗性能),try/catch只有在万不得已的时候才拿来处理
function getCss(curEle,attr){
var val = null;
if("getComputedStyle" in window){
//if(window.getComputedStyle)
//若返回true表示window下有该属性
val = window.getComputedStyle(curEle,null)[attr];
}else{
val = curEle.currentStyle[attr];
}
retur val;
}
window.navigator.userAgent
function getBrowserInfo(){
var agent = navigator.userAgent.toLowerCase() ;
var regStr_ie = /msie [\d.]+;/gi ;
var regStr_ff = /firefox\/[\d.]+/gi
var regStr_chrome = /chrome\/[\d.]+/gi ;
var regStr_saf = /safari\/[\d.]+/gi ;
//IE
if(agent.indexOf("msie") > 0){
return agent.match(regStr_ie) ;
}
//firefox
if(agent.indexOf("firefox") > 0){
return agent.match(regStr_ff) ;
}
//Chrome
if(agent.indexOf("chrome") > 0){
return agent.match(regStr_chrome) ;
}
//Safari
if(agent.indexOf("safari") > 0 && agent.indexOf("chrome") < 0){
return agent.match(regStr_saf) ;
}
}
var browser = getBrowserInfo() ;
//alert(browser);
var verinfo = (browser+"").replace(/[^0-9.]/ig,"");
判定当前浏览器为IE6-8
if(/MSIE (6|7|8)/.test(navigator.userAgent)){...}
getComputedStyle和currentStyle获取到的样式值都是带单位的,如:“px”;而clientWidth获取到的是不带单位的。有必要去掉单位以便于计算。
var reg = null;
reg = /^(-?\d+(\.\d+)?)(px|pt|rem|em)?$/i;
return reg.test(val) ? parseFloat(val) : val;
getCss(ele,"border");
getCss(ele,"fontFamily");
在IE和谷歌浏览器里获取的值还是不一样的,主要是因为getComputedStyle和currentStyle在某些方面还是有区别的;这之间的差别没有办法可以解决,只能注意复合样式获取
时的差异;另外,在IE和标准浏览器之间有个属性opacity也存在不同的处理方式
function getCss(curEle,attr){
var val = null;
var reg = null;
if("getComputedStyle" in window){
//if(window.getComputedStyle)
//若返回true表示window下有该属性
val = window.getComputedStyle(curEle,null)[attr];
}else{
//IE 情况范围
if(attr === "opacity"){
val = curEle.currentStyle["filter"];
reg = /^alpha\(opacity=(\d+?:\.\d+)?\)$/i;
val = reg.test(val) ? reg.exec(val)[1] / 100 : 1;
}else{
val = curEle.currentStyle[attr];
}
val = curEle.currentStyle[attr];
}
reg = /^(-?\d+(\.\d+)?)(px|pt|rem|em)?$/i;
return reg.test(val) ? parseFloat(val) : val;
}
window.getComputedStyle(curEle,null) 获取伪类元素的样式和内容
#para:before{
display: block;
width: 100px;
height: 30px;
content: "Hello World!";
}
<p id="para">你好</p>
var con = window.getComputedStyle(para,"before").content;
var wth = window.getComputedStyle(para,"before").width;
var dis = window.getComputedStyle(para,"before").display;
offsetParent:父级参照物,在同一个平面中最外层的元素是所有元素的父级参照物,和层级没有必然联系
一般来说页面中所有元素的父级参照物都是body
body是没有参照物的document.body.offsetParent == null
想要改变父级参照物需要position定位来实现
<div id="outer">
<div id="inner">
<div id="center">
</div>
</div>
</div>
outer.style.position = "relative/absilute/fixed";
console.log(inner.offsetParnet) //div.outer
console.log(center.offsetParnet) //div.outer
console.log(outer.offsetParnet) //body
若将inner也进行设置
inner.style.position = "relative";
console.log(inner.offsetParnet) //div.outer
console.log(center.offsetParnet) //div.inner
console.log(outer.offsetParnet) //body
offsetLeft/offsetTop当前元素的外边框距离当前父级参照物的内边框的距离
在标准的IE8浏览器中,使用offsetLeft/offsetTop时其实已经把父级参照物的边框已经计算在内了
function offset(curEle){
var totalLeft = null;
var totalTop = null;
var parent = curEle.parentNode;
while(parent){
//累加父级参照物的左偏移
totalLeft += curEle.offsetLeft;
//累加父级参照物的边框
if(navigator.userAgent.indexOf("MSIE 8.0") === -1){
//非标准IE8浏览器
totalLeft += curEle.clientLeft;
parent = parent.parentNode;
}
}
return totalLeft;
}
<p id="top"></p>
<a href="#top">TOP</a>
scrollTop/scrollLeft存在边界值(最大值和最小值),如果设置的值超过了边界值也不会起作用
最大值 = 容器真实高度 - 当前一屏的高度
var maxTop = box.scrollTop - box.clientHeight;
aa.onclick = function(){
var scrollTop = document.body.scrollTop;
var screenHeight = document.documentElement.clientHeight;
var duration = 500;
var interval = 10;
var step = (scrollTop/duration)*interval;
var timer = window.setInterval(function(){
var cur = document.body.scrollTop;
if(cur <= 0){
clearInterval(timer);
}
cur -= step;
document.body.scrollTop = cur;
},interval);
}
JS为单线程,在当前事情没有完成时是不会做下一件事情
异步的四种情况:
1.定时器
2.事件绑定
3.ajax读取数据
4.回调函数
每一个浏览器对于定时器的等待时间都有一个最小等待时间;即使设置等待时间小于最小等待时间,也不起作用(谷歌等待时间约为5-6ms,IE等待时间约为10-13ms)
var n = 0;
setTimeout(function(){
n++;
console.log(n);
},0);
console.log(n);
定时器的等待时间不一定就是最后执行时间,如果定时器后还有其他事情要处理,不管定时器的时间有没有到达都不会执行
var n = 0;
setTimeout(function(){
n++;
console.log(n);
},1000);
console.log(n);
while(1){ //死循环
n++;
}
console.log(n)
结果只输出一次,为“0”
作用:保证页面打开的速度
原理:首屏内容图片,先用默认图片占位(一般在5kb以内),当首屏内容加载完成后再加载首屏的图片;其他屏幕的图片,也是一张默认图片占位,当滚动条滚到对应区域后再加载图片
网站性能优化:尽量减少http请求
html,css,img,js文件都会向服务器发起请求,优化方法:
图片距离顶部的距离:图片距body的上偏移+图片高度
浏览器底部距离顶部:浏览器一屏高度+页面卷去的高度
当图片从下往上露出时开始延迟加载,即图片底部距离页面顶部的距离小于浏览器底部距离顶部的距离
var ban = document.querySelector('.banner');
var img = ban.getElementsByTagName('img')[0];
window.onscroll = function(){
if(ban.loaded){
return
}
var a = ban.offsetHeight + ban.offsetTop;
var b = document.documentElement.clientHeight + document.body.scrollTop;
console.log(a,b);
if(a<b){
var oImg = new Image;
oImg.src = img.getAttribute("trueSrc");
oImg.onload = function(){
img.src = this.src;
img.style.display = "block";
oImg = null;
}
ban.loaded = true;
}
}
获取某一容器的元素子节点,只考虑子元素而不考虑所有后代元素 ele.children只能获取儿子级的子元素,而且不兼容
//获取ele的子级元素
function children(ele,tagname){
var arr = [];
if(/MSIE (6|7|8)/i.test(navigator.userAgent)){
//IE8及以下
var nodeList = ele.childNodes;
for(var i=0;i<nodeList.length;i++){
var cur = nodeList[i];
if(cur.nodeType === 1){
arr[arr.length] = cur;
}
}
}else{
//标准浏览器
arr = Array.prototype.slice.call(ele.children);
}
//二次筛选指定标签
if(typeof tagname === "string"){
for(var i=0;i<arr.length;i++){
var cur = arr[i];
if(cur.tagName.toLowerCase() !== tagname.toLowerCase()){
arr.splice(i,1);
i--;
}
}
}
return arr;
}
//在指定容器的末尾追加元素
function append(newEle,container){
container.appendChild(newEle);
}
//获取指定元素的第一个子元素
function first(ele){
var arr = children(ele)
return arr.length>0?arr[0]:null;
}
//在指定容器的开头追加元素
function prepend(newEle,container){
var first = window.first(container);
if(first){
container.insertBefore(newEle,first);
return;
}
//如果第一个元素都不在,表明该容器没有子元素
container.appendChild(newEle);
}
//在指定元素之前追加元素
function insertBefore(newEle,oldEle){
oldEle.parentNode.insertBefore(newEle);
}
//获取指定元素的后一个元素
function next(ele){
if("getComputedStyle" in window){
return ele.nextElementSibling;
}
var next = ele.nextSibling;
while(next && next.nodeType !== 1){
next = next.nextSibling;
}
return next;
}
//在指定元素之后追加元素
function insertAfter(newEle,oldEle){
var next = window.next(oldEle);
if(next){
oldEle.parentNode.insertBefore(newEle,next);
return ;
}
//如果下一个元素都不在,表明该该元素已为最后一个元素
oldEle.parentNode.appendChild(newEle);
}
function hasClass(ele,className){
var reg = new RegExp("(^| +)"+className+"( +|$)");
return reg.test(ele.className);
}
function addClass(ele,className){
//防止className中包含多个类名
var ary = className.split(/ +/g);
for(var i=0;i<arr.length;i++){
var cur = arr[i];
if(!this.hasClass(ele,cur)){
ele.className += " " + cur;
}
}
}
function removeClass(ele,className){
var ary = className.split(/ +/g);
for(var i=0;i<arr.length;i++){
var cur = arr[i];
if(this.hasClass(ele,cur)){
var reg = new RegExp("(^| +)"+cur+"( +|$)","g");
ele.className = ele.className.replace(reg," ");
}
}
}