javascript中DOM总结(二)
使用Nodelist
NodeList,和HTMLColletion,以及NamedNodeMap是实时的。所以下面的循环是无限循环
let div = document.getElementsByTagName("div");
for(let i =0;i<div.length;i++){
let ele = document.createElement("div");
ele.appendChild(document.createTextNode("11"));
document.body.appendChild(ele);
}
// 解决方案一:先将长度保存起来
let div = document.getElementsByTagName('div');
for(let i =0,len = div.length;i<len;i++){
let ele = document.createElement("div");
ele.appendChild(document.createTextNode('11'));
document.body.appendChild(ele);
}
// 解决方案二:使用反向迭代
let div = document.getElementsByTagName("div");
for(let i = div.length -1;i>=0;i--){
let ele = document.createElement("div");
ele.appendChild(document.createTextNode('11'));
document.body.appendChild(ele);
}
一、动态加载脚本文件
①外部引入脚本封装函数
function loadScript(url){
let script = document.createElement("script");
script.src = url;
document.body.appendChild(script);
}
loadScript('file.js')
②内部生成标签封装函数(在这里需要考虑ie,对ie浏览器需要设置text),需要使用try–catch来进行设置
function loadScriptString(code){
var script = document.createElement("script");
script.type = "text/javascript";
try{
script.appendChild(document.createTextNode(code));
}catch(ex){
script.text = code;
}
document.body.appendChild(script);
}
var code = "console.log('大家好aa');"
loadScriptString(code);
二、动态加载样式
①动态样式,使用外联进行添加
//这里是link标签
function loadStyle(url){
var link = document.createElement("link");
var head = document.getElementsByTagName("head")[0];
link.rel = "stylesheet";
link.href = url
head.appendChild(link);
}
loadStyle('file.css');
②动态添加样式,使用内部添加,此时需要注意ie的问题,使用try-catch进行兼容浏览器
//这里是使用style标签
function loadStyleSheet(code){
var style = document.createElement("style");
var head = document.getElementsByTagName("head")[0];
style.type = "text/css";
try{
style.appendChild(document.createTextNode(code));
}catch(ex){
style.styleSheet.cssText = code;
}
head.appendChild(style);
}
var code = "body{background:red}"
loadStyleSheet(code);
三、动态操作表格
let table = document.createElement("table");
table.border =1 ;
table.width = "100%";
// 创建表体
let tbody = document.createElement("tbody");
table.appendChild(tbody);
// 创建第一行
tbody.insertRow(0);
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode("11"));
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode('12'));
// 创建第二行
tbody.insertRow(1);
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode("21"));
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode('22'));
document.body.appendChild(table);
// 这样就相比于普通的更简便
如果使用document.createElement创建表格以及代码过于繁琐。
四、MutationObserver对象
MutationObserver对象是可以对一个对象节点进行观察,当其内部的一些属性或者方法发生变化的时候,就会触发,所以其是一个异步函数。
①observe() 传入两个参数,一个是需要监控的对象,另一个是一个键值对,表示需要监控的内容。
let observer = new MutationObserver(()=>{
console.log("DOM was mutated");
})
observer.observe(document.body,{attributes:true});
document.body.className = "set";
console.log("主程序");
这个最终输出结果是:主程序,DOM was mutated,
所以可以看出是异步处理操作。
②MutationRecord对象:其是一个数组,当监控到设置的属性改变时,就会向数组中添加内容。
let observer = new MutationObserver((MutationRecord)=>{
console.log(MutationRecord);
})
observer.observe(document.body,{attributes:true});
document.body.setAttribute("foo","bar");
// 也可以使用setAttributeNs()来设置具有命名的空间属性
document.body.setAttributeNS("baz","foo",'bar');
//第一个参数就是给attributeNamespace传值。
传给回调的第二个参数,是观察MutationObserver的实例
let observer = new MutationObserver((MutationRecord,MutationObserver) => {
console.log(MutationRecord);
console.log(MutationObserver);
})
observer.observe(document.body, { attributes: true });
document.body.setAttribute("foo", "bar");
// Array(1)
// MutationObserver
disconnect()方法:将观察者断开,后面属性改变不会触发异步函数,
let observer = new MutationObserver((value)=>{
console.log("Attributes changes");
})
observer.observe(document.body,{attributes:true});
// 这样便会显示Attributes changes
document.body.className = "foo";
setTimeout(function(){
observer.disconnect();
},0)
// 这样则不会显示Attributes changes
document.body.className = "foo";
observer.disconnect();
MutationObserver()可以同时观察多个对象的属性变化:最终得到的任然是一个数组
let observer = new MutationObserver((mutationRecords)=>{
console.log(mutationRecords.map(mutationRecord=>{
return mutationRecord.target;
}));
})
let div = document.createElement("div");
let span = document.createElement("span");
document.body.appendChild(div);
document.body.appendChild(span);
observer.observe(div,{attributes:true});
observer.observe(span,{attributes:true});
div.setAttribute("foo","bar");
span.setAttribute("foo","bar");
disconnect()一刀切,将全部的观察去除,没有日志输出
let observer = new MutationObserver((MutationRecords)=>{
console.log(MutationRecords.map(MutationRecord=>{
return MutationRecord.target;
}));
})
let div = document.createElement("div");
let span = document.createElement("span");
document.body.appendChild(div);
document.body.appendChild(span);
observer.observe(div,{attributes:true});
observer.observe(span,{attributes:true});
div.setAttribute("foo",'bar');
span.setAttribute("bar",'set');
observer.disconnect();
这里observer.disconnect()是同步的,观察是异步的。
重用MutationServer(),就是先断开,再连上
let observer = new MutationObserver(MutationRecord=>{
console.log("Attribute has changed");
})
observer.observe(document.body,{attributes:true});
setTimeout(()=>{
document.body.className = "foo";
},0)
setTimeout(()=>{
observer.disconnect();
document.body.className = "bar";
})
setTimeout(()=>{
observer.observe(document.body,{attributes:true});
document.body.className = "baz";
},0)
三、MutationObserverInit与观察范围
①观察属性 设置attributes为true
let observer = new MutationObserver((MutationRecord)=>{
console.log(MutationRecord);
})
let div = document.createElement("div");
document.body.appendChild(div);
observer.observe(div,{attributes:true});
div.setAttribute("foo","bar");
div.removeAttribute("foo");
②、attributesFilter()设置白名单,是一个数组,并且只会记录这个数组中的属性。
let observer = new MutationObserver((value)=>{
console.log(value);
})
let div = document.createElement("div");
document.body.appendChild(div);
observer.observe(div,{attributeFilter:["foo"]});
div.setAttribute("foo",'bar');
div.setAttribute("aa",'dssd');
③attributeOldValue属性 使用可以记录这个属性对应的值
let observer = new MutationObserver((value)=>{
console.log(value.map(item=>{
return item.oldValue;
}));
})
let div = document.createElement("div");
document.body.appendChild(div);
observer.observe(div,{attributeOldValue:true});
div.setAttribute("foo","name");
div.setAttribute("foo","20");
div.setAttribute("foo","sss");
最终显示结果:[null, “name”, “20”]
观察字符文本
document.body.innerText和document.body.innerHTML两者的区别是innerText是输出body中的文本内容,而innerHTML输出body中的全部内容。
观察子节点
这里创建一个节点和添加一个节点都会被观察到
document.body.innerHTML = "";
let observer = new MutationObserver((value)=>{
console.log(value);
})
observer.observe(document.body,{childList:true});
// 这里创建一个节点和添加一个节点都会被观察到
document.body.appendChild(document.createElement("div"));
观察子树的变化
这里将参数设置为{attributes:true,subtree:true},就是可以设置该节点以及其子节点的属性的值
let observer = new MutationObserver((value)=>{
console.log(value);
})
let div = document.createElement("div");
document.body.appendChild(div);
observer.observe(document.body,{attributes:true,subtree:true});
div.setAttribute("foo","bar");
将节点移动到外面吗,任然有效
document.body.innerHTML = "";
let observer = new MutationObserver(value=>{
console.log(value);
})
let div = document.createElement("div");
let span = document.createElement("span");
div.appendChild(span);
document.body.appendChild(div);
observer.observe(document.body,{attributes:true,subtree:true});
document.body.insertBefore(span,div);
span.setAttribute("foo","bar");
takeRecords()方法:清空队列,并将观察到的数组返回
let observer = new MutationObserver((value)=>{
console.log(value);
})
observer.observe(document.body,{attributes:true});
document.body.className = "foo";
document.body.className = 'nnn';
document.body.className = "se";
console.log(observer.takeRecords());
console.log(observer.takeRecords());
总结: MutationObserver对象是用来观察某一个对象的属性变化的,当该对象属性发生变化,则会将其放入一个微任务队列中等待执行相关操作。MutationObserver对象对节点对象的引用是弱引用,而节点对象对MutationObserver对象的引用时强引用,当节点消失,MutationObserver会自动触发垃圾回收机制。