深说浅谈DOM对象,用4个版本demoplus让你扭断history.state头—dom操作样式后渲染—配合属性值+二级菜单收缩+dom常见属性的(宽高,位置)

发布于:2023-02-19 ⋅ 阅读:(539) ⋅ 点赞:(0)

什么是节点

HTML 文档中的每个成分都是一个节点。

(1)节点类型

DOM 是这样规定的:

  • 整个文档是一个文档节点
  • 每个 HTML 标签是一个元素节点
  • 包含在 HTML 元素中的文本是文本节点
  • 每一个 HTML 属性是一个属性节点 注释属于注释节点

(2)节点层次关系-节点彼此都有等级关系。

HTML 文档中的所有节点组成了一个文档树(或节点树)。
HTML文档中的每个元素、属性、文本等都代表着树中的一个节点。
树起始于文档节点,并由此继续伸出枝条,直到处于这棵树最低级别的所有文本节点为止。
当节点分享同一个父节点时,它们就是同辈(同级节点)。
节点也可以拥有后代,后代指某个节点的所有子节点,或者这些子节点的子节点。
节点也可以拥有先辈。先辈是某个节点的父节点,或者父节点的父节点,以此类推。

(3)节点属性

每个节点都拥有包含着关于节点某些信息的属性。这些属性是:
nodeName(节点名称)
元素节点的 nodeName 是标签名称
文本节点的 nodeName 永远是 #text
注释节点的 nodeName 永远是 #comment
文本节点,nodeValue 属性包含文本。
节点nodeValue元素节点nodeValue不可用不可用
nodeValue包括注释内容
nodeType(节点类型)

获取body后节点列表

document.body.childNodes

<p>a</p>
<form action="">
    <input type="text" name="user" id="">
    <input type="radio" name="sex" value="男" class="input1">
    <input type="radio" name="sex" value="女" class="input2">
</form>

<div id="div2">
    <span class="div1"></span>
    <span class="div1"></span>
</div>
<span class="div1"></span>
 console.log(document.body.childNodes);
//text, p, text, comment, text, script
 console.log(document.body.childNodes[1].nodeName==="P");
 //true

获取DOM元素

document.documentElement  //html标签
document.body //body 标签
document.title //标题
//所有的style标签列表和link标签列表有多少个样式style就有多少length
方法名称 调用描述
document.getElementById() 通过元素的id值获取
document.getElementsByTagName() 返回元素的HTML集合
document.getElementsByName() ame来获得对象,同一个Name可以对应多个对象(Name不是唯一的),所以它得到的是一个数组
document.getElementsByClassName(新) 通过类名来获取 元素
document.querySelector( 新) 根据标签名(类名)获取第一个元素
document.querySelectorAll(新) 获取所有标签名的元素

querySelector的用法

在js中可以通过标签选择器获取标签,现在发现还有querySelector可以实现选择器的功能。可以是标签名,也可以是类名。

<p id="demo" class="demo_1">单击按钮获取按钮元素的节点值。</p>
<button onclick="myFunction()">点我</button>
<script>
console.log(document.getElementById('demo'));
console.log(document.querySelector('.demo_1'));
console.log(document.querySelector('p'));

getElementsByTagName的用法

传回指定名称的元素集合。也就是一个数组集合,所以用的时候得注意这个后面指定是哪个元素。

var c=document.getElementsByTagName("BUTTON")[0];

节点遍历

方法名称 调用描述
childNodes 所有子节点 获取所有子节点(包括注释)
children 所有是标签类型的子节点 获取所有子元素
parentNode 获取已知节点的父节点
firstElementChild 第一个子节点 (元素)
firstChild 第一个子节点
lastElementChild() 最后一个子节点(元素)
lastChild: 最后一个子节点
nextElementSiblin 下一个兄弟节点(元素)
nextSibling 下一个兄弟节点
previousElementSibling 上一个兄弟节点
previousSibling 上一个兄弟节点
document.createTextNode(“”) 创建文本节点
<div id="div2">
    <span class="div1"></span>
    <span class="div1"></span>
</div>
console.log( div2.nextSibling);//#text
console.log(div2.childNodes);
//[text, span.div1, text, span.div1, text]
节点/元素 操作 功能描述
document.createElement(“标签名”) 创建新元素
父元素.appendChild() 追加在尾部
父元素.insertBefore(要插入的元素,要插入在谁的前面) 追加在谁之前
textContent 获取包含换行符合空格的结构性文本
innerText 获取父元素中所有文本和后代文本
innerHTML 父元素中所有的html标签文本及内容
document.createTextNode(“”) 创建文本节点
replaceChild(newNode,oldNode) newNode替换节点oldNode
removeChild(node) 移除父节点的某个子节点
cloneNode(boolean) 复制一个节点
被替换的元素.replaceWith(新元素) 替换
父元素.replaceChild(新元素,被替换的元素) 替换

innerText可以设置转义字符和空格换行等,textContent只能设置其文本,不能含转义,传统的获取渲染会丢失对象

DOM树
CSS树
DOM渲染树
异步加载渲染树
数据驱动显示

传统点击事件重新渲染丢失对象元素

<div id="div1">
    <span>1</span>
</div>

var div1=document.querySelector("#div1");
var span=div1.querySelector("span");
span.onclick = function(){
     span.style.color = 'red'
}
div1.innerHTML+="<span>2</span>";
//这样会失去点击对象

dom创建元素直接添加渲染

不改变原来对象:

div id="div1">
    <span>1</span>
</div>

var span_1 = document.createElement('span')
span_1.textContent = '2'
div1.appendChild(span_1,span);
//创建一个dom对象(元素/标签)然后在给赋值
span.onclick = function(){
     span.style.color = 'red'
}
//不会失去捕获对象

创建碎片容器(js创建一个table)

<script>
    // table.tr.dd
    /* 首先创建一个元素table */
    var table = document.createElement('table')
    
    for(var i=0;i<100;i++){
        //创建tr对象标签
        var tr = document.createElement('tr')
        for(var j=0;j<10;j++){
            // 创建td对象标签
            var td = document.createElement('td')
            // 给td添加内容
            td.textContent = '1'
            // 追加在这个父标签的最后位
            tr.appendChild(td)
        }
        // 追加在这个父标签的最后位
        table.appendChild(tr)
    }
    console.log(table);
    document.body.appendChild(table)
</script>

创建100个div插入到body中

var elem=document.createDocumentFragment();//创建碎片容器
for(var i=0;i<100;i++){
    var div=document.createElement("div");
    elem.appendChild(div);
}
document.body.appendChild(elem);

创建文本结点插在第一个子元素的前面

<div id="div1">
    <span>1</span>
</div>
var txtNode=document.createTextNode("3");
div1.insertBefore(txtNode,div1.firstChild);

只有img标签才可以new 创建

var img=document.createElement("img");
//var img=new Image();
img.src="./img/img_21.JPG"
document.body.appendChild(img);
var img1=img.cloneNode(false);
document.body.appendChild(img1);

删除元素

span.remove();
// 父元素删除子元素
div1.removeChild(span);
// 清空元素所有内容
div1.innerHTML="";

替换元素

var p=document.createElement("p");
// 父元素.replaceChild(新元素,被替换的元素)
document.body.replaceChild(p,div1)
// 被替换的元素.replaceWith(新元素)
div1.replaceWith(p)

根据loaction下的这个hash值变化,触发事件驱动函数

添加内容(数据驱动显示)版本一

无历史记录版本,纯dom操作

<input type="text"> <button>点击添加</button>
<ul></ul>
<script>
    var input,button,ul;
    init();

    function init(){
        /* 获取三个元素对象 */
        input = document.querySelector('input')
        button = document.querySelector('button')
        ul = document.querySelector('ul')
        /* 给button设置点击事件 */
        button.onclick = onclickHander;
    }
    function onclickHander(){
        /* 点击之后创建一个li元素 */
        var li = document.createElement('li') 
        console.log(input.value);
        li.textContent = input.value;
        ul.insertBefore(li,ul.firstChild);
        input.value = ''
    }
           
    </script>
</body>

数据驱动显示,碎片容器打包渲染(版本二)

<body>
    <input type="text"> <button>点击添加</button>
    <ul></ul>
    <script>
        var input,button,ul;
        var list =[];
        init();

        function init(){
            /* 获取三个元素对象 */
            // window.onpopstate = onclickHander;
            input = document.querySelector('input')
            button = document.querySelector('button')
            ul = document.querySelector('ul')
            // var li = history.state?
            /* 给button设置点击事件 */
            button.onclick = onclickHander;
        }
        function onclickHander(){
            /* 点击之后创建一个li元素 */
            // var li = document.createElement('li') 
            // console.log(input.value);
            list.push(input.value)
            upData();
            console.log(list);
            // ul.insertBefore(li,ul.firstChild);
            input.value = ''
            // history.pushState(li,li);
            // console.log(history.state);
        }
        function upData(){
            //每次渲染之前给ul清空内容
            ul.innerHTML = ''
            var emel = document.createDocumentFragment();
            for(var i=0;i<list.length;i++){
                var li = document.createElement('li');
                li.textContent = list[i];
                //每一次生成的li包裹在这emel胶囊中
                emel.appendChild(li)
            }
            ul.append(emel)    
        }
        
    </script>

新增删除按钮。添加属性标记条件,利于程序删除(版本三)

<input type="text"> <button>点击添加</button>
<ul></ul>
<script>
    var input,button,ul;
    var list =[];
    init();

    function init(){
        /* 获取三个元素对象 */
        // window.onpopstate = onclickHander;
        input = document.querySelector('input')
        button = document.querySelector('button')
        ul = document.querySelector('ul')
        // var li = history.state?
        /* 给button设置点击事件 */
        button.onclick = onclickHander;
    }
    function onclickHander(){
        /* 点击之后创建一个li元素 */
        // var li = document.createElement('li') 
        // console.log(input.value);
        if(!input.value){
            return;
        }
        list.push(input.value)
        upData();
        console.log(list);
        // ul.insertBefore(li,ul.firstChild);
        input.value = ''
        // history.pushState(li,li);
        // console.log(history.state);
    }
    function upData(){
        //每次渲染之前给ul清空内容
        ul.innerHTML = ''
        var emel = document.createDocumentFragment();
        for(var i=0;i<list.length;i++){
            var li = document.createElement('li');
            li.textContent = list[i];
            var bn = document.createElement('button');
            bn.innerHTML = '&times';
            bn.onclick = removeData;
            bn.i=i;
            li.append(bn)
            //每一次生成的li包裹在这emel胶囊中
            emel.appendChild(li)
        }
        ul.append(emel)    
    }
    function removeData(){
        list.splice(this.i,1)
        upData()
    }

添加history历史记录(版本四)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="text"> <button>点击添加</button>
    <ul></ul>
        <script>
        var input,button,ul;
        var list =[];
        init();

        function init(){
            /* 初始化启动history监听 */
            window.onpopstate = changehistoryHander;
            input = document.querySelector('input')
            button = document.querySelector('button')
            ul = document.querySelector('ul')
            button.onclick = onclickHander;
            /* 历史第一次替换为list */
            history.replaceState(list,'a')
        }
        /* 把数据框的里值放在数组当中 */
        function onclickHander(){
            if(!input.value){
                return;
            }
            list.push(input.value)
            upData();
            console.log(list);   
            input.value = ''
            //添加历史状态
            history.pushState(list,'b')

       
        }
         /* 数据驱动显示 */
        function upData(){

            ul.innerHTML = ''
            var emel = document.createDocumentFragment();
            for(var i=0;i<list.length;i++){
                var li = document.createElement('li');
                li.textContent = list[i];
                var bn = document.createElement('button');
                bn.innerHTML = '&times';
                bn.onclick = removeData;
                bn.i=i;
                li.append(bn)
                emel.appendChild(li)
            }
            ul.append(emel)    
        }
        /* 过程中做好数据标识 */
        function removeData(){
            list.splice(this.i,1)
            history.pushState(list,'c')
            upData()
        }
        function changehistoryHander(){
            list = history.state;
            upData()
        }
    </script>
</body>
</html>

Dom属性

DOM 的对象属性 部分标签属性和对象属性是相通的
大部分系统默认的标签属性都是相通
自定义的标签属性是不相通的
class 是特殊的,在对象属性中使用className
表单\超链接的name与对象属性name相同,但是其他元素的name不相通

<div id="div1" class="div2" name="abc" title="div3" names="xietian" data-main="asds-asdwe"></div>
<input type="checkbox" name="user" checked>

<a href="" name="abc"></a>

DOM标签上的属性叫做标签属性
标签属性配合样式来用

方法 功能
对象.getAttribute(“title”) 获取属性值
对象.setAttribute(“标签名”,“new内容”) 修改属性值
removeAttribute(“标签名”); 删除标签属性值
var div=document.querySelector("div");
console.log(div.style);//CSSStyleDeclaration
for(var i=0;i<div.style.length;i++){
    var key=div.style[i];
    console.log(key,div.style[key]);
//color blue
//width 100px
}

客户区大小

document.documentElement.clientWidth
document.documentElement.clientHeight
document.body.clientWidth
document.body.clientHeight

二级菜单收缩

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        ul{
            overflow: hidden;
            max-height: 0px;
            transition: all 0.5s;
        }
        ul[open]{
            max-height: 1000px;
        }
    </style>
</head>
<body>
     <ul class="city" open>
        <li>北京
            <ul>
                <li>海淀</li>
                <li>朝阳</li>
                <li>昌平</li>
                <li>大兴</li>
                <li>密云</li>
                <li>顺义</li>
            </ul>
        </li>
        <li>河北</li>
        <li>山西</li>
        <li>陕西
            <ul>
                <li>西安</li>
                <li>咸阳</li>
                <li>宝鸡</li>
                <li>铜川</li>
                <li>榆林</li>
            </ul>
        </li>
        <li>河南</li>
        <li>山东</li>
    </ul>
    <script>
        var lis;
        init();
        function init(){
            lis = document.querySelectorAll('li');
            for(var i=0;i<lis.length;i++){
                lis[i].onclick = clickHandler;
            }    
        } 
        function clickHandler(){
            if(!this.firstElementChild) return
            if(this.firstElementChild.getAttribute('open') === null){
                this.firstElementChild.setAttribute('open','')
            }else{
                this.firstElementChild.removeAttribute('open')
            }

        }

    </script>
</body>
</html>

样式

知识点:增加样式的优先级
background-color: red !important
有两种属性:

  • dom对象属性
  • dom标签上的叫做标签属性
  • 标签属性的名称和值都不区分大小写所以必须使用‘-’来链接字符串的方式
  • 标签的属性值必须是字符串
div{
    width: 50px;
    height: 50px;
    background-color: red !important
}
 </style>
</head>
<body>
	 <div style="color:blue ;width: 100px;">123</div>
	 <script>
	     var div = document.querySelector('div')
	     console.log(div.style);//CSSStyleDeclaration
	     console.log(document.styleSheets);//所有的stylecss标签;列表CSSStyleDeclaration
 </script>

修改css样式
document.styleSheets[1] 第几个style列表
document.styleSheets[1].cssRules[0] 第几个选择器
.cssRules[i].selectorText,第i个选择器的名称

document.styleSheets[1].rules[0].style.width ='500px'

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div{
            width: 50px;
            height: 50px;
            background-color: red ;
        }
    </style>
    <style>
        .div1{
            width: 100px;
            height: 100px;
        }
        .div2{
            width: 50px;
            height: 50px;
        }
        .div3{
            width: 200px;
            height: 200px;
        }
        .div4>.div1{
            width: 100px;
            height: 100px;
        }

    </style>
</head>
<body>
    <div style="color:blue ;;"></div>
    <div class="div1"></div>
    <div class="div2"></div>
    <div class="div3"></div>
    <div class="div4">
        <div class="div1"></div>
    </div>   
    <script>;
        var styleSheet = document.styleSheets[document.styleSheets.length-1];
        for(var i=0;i<styleSheet.cssRules.length;i++){
            if(styleSheet.cssRules[i].selectorText.includes('.div1')){
                styleSheet.cssRules[i].style.width = '500px'
            }
            styleSheet.cssRules[i].style.backgroundColor = Array(6).fill(1).reduce(function(v,item){
                return v+(~~(Math.random()*16)).toString(16)
            },"#")
        }



    </script>
</body>
</html>

dom常见的属性(宽高)

项目 Value
宽高 width height(对象)
clientWidth clientHeight 客户宽高
offsetWidth offsetHeight 偏量宽高
scrollWidth scrollHeight 滚动宽高
对象.getBoundingClientRect(); 获取元素的相对视口的矩形位置
返回值 {width,height,x,y,left,top,right,bottom}
div{
width: 50px;
height: 50px;
background-color: red !important
}
var div = document.querySelector('div')
console.log(div.style);//CSSStyleDeclaration
console.log(div.clientWidth,div.clientHeight);//width+padding*2-滚动条轨道宽高
console.log(div.offsetWidth,div.offsetHeight);//width+padding*2+border*2 实际占位宽高
console.log(div.scrollWidth,div.scrollHeight);//实际内容宽高
console.log(document.documentElement.clientWidth,document.documentElement.clientHeight);// 视口宽高
console.log(document.body.clientWidth,document.body.clientHeight); //body的宽高
onsole.log(document.documentElement.offsetWidth,document.documentElement.offsetHeight);//html被撑开的宽高
console.log(document.body.offsetWidth,document.body.offsetHeight);//body的宽高
//滚动条的宽高
console.log(document.documentElement.scrollWidth,document.documentElement.scrollHeight); console.log(document.body.scrollWidth,document.body.scrollHeight);

left

dom常见的属性(位置)

位置Left Top (DOM)
没有定位的是 相对于视口
做了定位的是 相对父容器的距离
div.clicentLeft 边线粗细
div.clientLeft 边线粗细
div.offsetLeft 相对于视口/相对父容器的左上角距离
div.offsetTop 相对于视口/相对父容器的左上角距离
div.scrollLeft div滚动条的位置
div.scrollTop div滚动条的位置,可以设置也可以获取

在这里插入图片描述

.div1{
	width: 300px;
	height: 300px;
	position: relative;
	left: 100px;
	top: 3000px;
	background-color: red;
}
.div2{
	width: 50px;
	height: 50px;
	position: absolute;
	left: 50px;
	top: 50px;
	background-color: blue;
}
var div2=document.querySelector(".div2");
console.log(div2.offsetLeft,div2.offsetTop)//50.50

在这里插入图片描述

获取元素的相对视口的矩形位置 Value
var rect=div2.getBoundingClientRect();
{width,height,x,y,left,top,right,bottom}
 console.log(rect);
本文含有隐藏内容,请 开通VIP 后查看