首页 前端知识 前端知识学习笔记-四(DOM、CSS操作)

前端知识学习笔记-四(DOM、CSS操作)

2024-05-03 18:05:16 前端知识 前端哥 226 917 我要收藏

DOM概述

DOM 是JavaScript 操作网页的接口,全称为“文档对象模型”(Document Object Model)。它的作用是将网页转为一个JavaScript对象,从而可以用脚本进行各种操作(比如对元素增删内容)。
浏览器会根据 DOM 模型,将结构化文档HTML解析成一系列的节点,再由这些节点组成一个树状结构(DOMTree)。所有的节点和最终的树状结构,都有规范的对外接口。
DOM 只是一个接口规范,可以用各种语言实现。所以严格地说,DOM 不是JavaScript 语法的一部分,但是DOM操作是JavaScript 最常见的任务,离开了DOM,JavaScript 就无法控制网页。另一方面JavaScript 也是最常用于DOM 操作的语言。
节点
DOM 的最小组成单位叫做节点 (ode)。文档的树形结构(DOM 树),就是由各种不同类型的节点组成每个节点可以看作是文档树的一片叶子。

节点的类型有七种
Document: 整个文档树的顶层节点
DocumentType: doctype标签
Element: 网页的各种HTML标签
Attribute: 网页元素的属性 (比如class="right”Text: 标签之间或标签包含的文本
Comment:注释
DocumentFragment: 文档的片段

节点树
一个文档的所有节点,按照所在的层级,可以抽象成一种树状结构。这种树状结构就是 DOM 树。它有一个顶然后子节点又有自己的子节点,就这样层层衍生出一个金字塔结构,层节点,下一层都是顶层节点的子节点,倒过来就像一棵树。
浏览器原生提供document节点,代表整个文档。

document
// 整个文档树

除了根节点,其他节点都有三种层级关系

父节点关系 (parentNode) : 直接的那个上级节点
子节点关系 (childNodes) : 直接的下级节点
同级节点关系(sibling) : 拥有同一个父节点的节点

Node.nodeType属性
不同节点的nodeType属性值和对应的常量如下:

文档节点 (document): 9,对应常量Node.DOCUMENT_NODE
元素节点 (element):1,对应常量Node.ELEMENT_NODE
属性节点 (attr) : 2,对应常量Node.ATTRIBUTE_NODE
文本节点(text):3,对应常量Node.TEXT_NODE
文档片断节点(DocumentFragment) :11,对应常量Node.DOCUMENT_FRAGMENT_NODE

document对象方法/获取元素

document.getElementsByTagName()
documentgetEementsByTagName 方法搜索 HTML标签名,返回符合条件的元素。它的返回值是一个类似数组对象可以实时反映 HTML 文档的变化。如果没有任何匹配的元素,就返回一个空集。

<body>
    <div>hello world</div>
    <script>
        var divs=document.getElementsByTagName('div');
    </script>
</body>

如果传入"*",就可以返回文档中所有 HTML 元素;

var a11Elements = documentgetElementsByTagName('*');

document.getElementsByClassName()
documen.getElementsByClassName 方法返回一个类似数组的对象(HTMLClecion 实例),包括了所有 class 名字符合指定条件的元素,元素的变化实时反映在返回结果中。

> var elements = document.getElementsByClassName(names);

由于class 是保留字,所以JavaScript 一律使用className 表示CSS的cass参数可以是多个 coss ,它们之间使用空格分隔。

var elements = documentgetElementsByClassName( 'foo bar');

document.getElementsByName()
document.getElementsByName 方法用于选择拥有 name 属性的 HTML元素 (比如form、radio、img等),返回个类似数组的的对象 ( NodeList 实例),因为 name 属性相同的元素可能不止一个。

// 表单为 <form name="username"></form>
2 var forms = document.getElementsByName('username');

document.getElementByld()
document.getElementById 方法返回匹配指定id 属性的元素节点。如果没有发现匹配的节点,则返回null

var elem = document.getElementById('login');

注意,该方法的参数是大小写敏感的。比如,如果某个节点的id 属性是 man ,那么 document.getElementById(Main)将返回 null

document.querySelector()
document.querySeletor方法接受一个CSS 选择器作为参数,返回匹配该选择器的元素节点。如果有多个节点满足匹配条件,则返回第一个匹配的节点。如果没有发现匹配的节点,则返回 null

var e11 = document.queryselector(' .myclass');

document.querySelectorAll()
document.querySelectorAll 方法与 queySelector 用法类似,区别是返回一个 NodeList 对象,包含所有匹配给定选择器的节点.

var elementList = document.queryselectorA11(' .myclass');

document对象方法/创建元素

document.createElement()
document.createElement 方法用来生成元素节点,并返回该节点

var newDiv=document.createElement("div");

document.createTextNode()
document.createTextNode 方法用来生成文本节点( Te 实例),并返回该节点。它的参数是文本节点的内容

var newP=document.createElement("p");//创建新的P标签
var newcontent=document.createTextNode("新内容");//创建P标签内容
newP.appendChild(newcontent);//把内容放到P标签中
document.body.appendChild(newP);//把新创建的P标签放到body中

document.createAttribute()
document.createAtribure 方法生成一个新的属性节点(Ar实例),并返回它

var newP=document.createElement("p");//创建新的P标签
var newcontent=document.createTextNode("新内容");//创建P标签内容
var id=document.createAttribute("id");//创建id
newP.appendChild(newcontent);
id.value="新标题";//给id赋值
newP.setAttributeNode(id);//给新创建的P标签设置Id
document.body.appendChild(newP);
console.log(newP);

Element对象_属性

Element对象对应网页的 HTML 元素。每一个HTML元素,在 DOM 树上都会转化成一个Element节点对象
(以下简称元素节点)。
Element.id
Elementd 属性返回指定元素的d 属性,该属性可读写

// HTML 代码为 <p id="foo">
var p = document.querySelector('p');
p.id // "foo"

Element.className
className 属性用来读写当前元素节点的 css 属性。它的值是一个字符串,每个 class之间用空格分割

// HTML 代码 <div class="one two three" id="myDiv"></div>
var div = document .getElementById('myDiv');
div.className

Element.classList

classLis: 对象有下列方法
add() : 增加一个 class。
remove() : 移除一个 class。
contains(): 检查当前元素是否包含某个 class。
toggle() : 将某个 class 移入或移出当前元素。

var div = document .getElementById('myDiv') ;
div.classList.add('myCssClass');div.classList.add('foo' ,'bar');
div.classList.remove('myCssClass');
div.classList.toggle('myCssClass'); // 如果 myCssClass 不存在就加入,否则移除
div.classList.contains('myCssClass'); // 返回 true 或者 false

Element.innerHTML
Elementinner.HTML属性返回一个字符串,等同于该元素包含的所有 HTML代码。该属性可读写,常用来设置某个节点的内容。它能改写所有元素节点的内容,包括HTML和body 元素.

 <div class="one two three" id="myDiv"></div>
 <script>
     var div = document .getElementById('myDiv');
     div.innerHTML = '<p>hello world</p>';
 </script>

Element.innerText
innerTex 和innerHTML 类似,不同的是innerText 无法识别元素,会直接染成字符串.

 div.innerHTML = '<p>hello world</p>';//hello world
 div.innerText='<p>hello world</p>';//<p>hello world</p>

Element获取元素位置

在这里插入图片描述
Element.clientHeight,Element.clientWidth

Element.clientHeight 属性返回一个整数值,表示元素节点的CSS
高度(单位像素),只对块级元素生效,对于行内元素返回0。如果块级元素没有设置 CSS 高度,则返回实际高度。

除了元素本身的高度,它还包括 podding 部分,但是不包括 border 、 mrgin
。如果有水平滚动条,还要减去水平滚动条的高度。注意,这个值始终是整数,如果是小数会被四舍五入。

Element.clientWidth
属性返回元素节点的CSS宽度,同样只对块级元素有效,也是只包括元素本身的宽度和padding,如果有垂直滚动条,还要减去垂直滚动条的宽度.

document.documentElement 的 clientHeght 属性,返回当前视口的高度 (即浏览器窗口的高度)。
document.body 的高度则是网页的实际高度

// 视口高度(屏幕高度)
document.documentETement.clientHeight
//视口宽度(屏幕宽度)
document.documentElement.clientWidth
//网页总宽度
document.body.clientWidth
//网页总高度
document.body.clientHeight

CSS操作

HTML 元素的 style 属性
操作CSS 样式最简单的方法,就是使用网页元素节点的 setAmrbute 方法直接操作网页元素的 style 属性

<script>
 div.setAttribute(
'style' 
'background-color:red;' + ' border:1px solid black';
</script>
)

元素节点的 style 属性

var divstyle = document.queryselector('div').style;
divstyle.backgroundcolor = 'red";
divstyle.border = "1px solid black' ;
divStyle.width = '100px';
divstyle.height = '100px';
divStyle.fontsize = '10em;

cssText 属性

var divstyle = document.querySelector('div').style;
diystyle,cssText='background-color: red; border:solid black;height: 100px;width: 100px;';

事件处理程序

事件处理程序分为:
HTML事件处理
DOM0级事件处理
DOM2级事件处理

HTML事件处理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <button onclick="clickHandler()">提交</button>
    <script>
        function clickHandler(){
            alert("是否确认提交");
        }
    </script>

</body>
</html>

DOM0级事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <button id="btn"">提交</button>
    <script>
        var btn=document.getElementById("btn");
        btn.onclick=function(){
            alert("是否确认提交");
        }
    </script>

</body>
</html>

DOM2级事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <button id="btn"">提交</button>
    <script>
        var btn=document.getElementById("btn");
        btn.addEventListener("click",function(){
            alert("确认提交");
        })
    </script>

</body>
</html>

hetm事件(一般不选)
缺点:HTML和JS未分离
DOM0级事件
优点:HTML和JS分离
缺点:无法添加多个事件
DOM2级事件
优点:HTML和JS分离;可以添加多个事件
缺点:写起来麻烦

鼠标事件

鼠标事件指与鼠标相关的事件,具体的事件主要有以下一些
click:按下鼠标时触发
dblclick:在同一个元素上双击鼠标时触发
mousedown:按下鼠标键时触发
mouseup:释放按下的鼠标键时触发
mousemove:当鼠标在节点内部移动时触发。当鼠标持续移动时,该事件会连触发。
mouseenter:鼠标进入一个节点时触发,进入子节点不会触发这个事件
mouseleave:鼠标离开一个节点时触发,离开父节点不会触发这个事件
mouseover:鼠标进入一个节点时触发,进入子节点会再一次触发这个事件mouseout:鼠标离开一个节点时触发,离开父节点也会触发这个事件
wheel:滚动鼠标的滚轮时触发

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <button id="btn1">单击</button>
    <button id="btn2">双击</button>
    <button id="btn3">鼠标按下</button>
    <button id="btn4">鼠标抬起</button>
    <button id="btn5">鼠标移动</button>
    <button id="btn6">鼠标进入</button>
    <button id="btn7">鼠标离开</button>
    <script>
        var btn1=document.getElementById("btn1");
        var btn2=document.getElementById("btn2");
        var btn3=document.getElementById("btn3");
        var btn4=document.getElementById("btn4");
        var btn5=document.getElementById("btn5");
        var btn6=document.getElementById("btn6");
        var btn7=document.getElementById("btn7");
        btn1.addEventListener('click',function(){
            alert("单击了");
        })
        btn2.addEventListener('dblclick',function(){
            alert("双击了");
        })
        btn3.addEventListener('mousedown',function(){
            alert("鼠标按下了");
        })
        btn4.addEventListener('mouseup',function(){
            alert("鼠标抬起了");
        })
        btn6.addEventListener('mouseenter',function(){
            alert("鼠标进入了");
        })
        btn7.addEventListener('mouseleave',function(){
            alert("鼠标离开了");
        })
        btn5.addEventListener('mousemove',function(){
            alert("鼠标移动了");
        })


    </script>

</body>
</html>

温馨提示 这些方法在使用的时候,除了DOM2级事件,都需要添加前缀 on

Event事件对象

Event对象属性
Event.Target
Event.type

Event.target
Event.target属性返回事件当前所在的节点

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <button id="btn">提交</button>

    <script>
       var btn = document.getElementById("btn");
       btn.onclick = function(){
                   event.target.innerHTML = "提交中";
       }


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

Event.type
Event.type属性返回一个字符串,表示事件类型。事件的类型是在生成事件的时候。该属性只读。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <button id="btn">提交</button>

    <script>
       var btn = document.getElementById("btn");
       btn.onclick = function(){
                   event.target.innerHTML = "提交中";
                   console.log(event.type)//click
       }
    </script>
</body>
</html>

Event对象方法
Event.preventDefault()
Event.stopPropagation()

Event.preventDefault
Event.preventDefault方法取消浏览器对当前事件的默认行为。比如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <a href="https://baidu.com" id="baidu">百度</a>
    <script>
       var baidu= document.getElementById("baidu");
       baidu.onclick=function(){
           event.preventDefault();//阻止跳转
       }
    </script>
</body>
</html>

Event.stopPropagation()
stopPropagation方法阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数

键盘事件

键盘事件由用户击打键盘触发,主要有keydown、keypress、keyup三个事件

keydown: 按下键盘时触发
keypress: 按下有值的键时触发,即按下 Ctrl、Alt、Shift、Meta这样无值的键,这个事件不会触发。对于有值的键,按下时先触发keydown事件,再触发这个事件。
okeyup:松开键盘时触发该事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <input type="text" id="username">
    <input type="password" id="password">
    <script>
       var username = document.getElementById("username");
       username.onkeydown = function(e){
           console.log("按下了");
       }
       username.onkeyup = function(e){
           console.log(e.target.value);
       }
       username.onkeypress = function(){
           console.log("123");
       }
      var password = document .getElementById("password")
       password.onkeyup = function(e){
           //keyCode:代表每个按键的唯一标识
           console.log(e.keyCode);
           if(e.keyCode ===  13){
               console.log("开始搜索");
           }
       }
    </script>
</body>
</html>

表单事件

表单事件是在使用表单元素及输入框元素可以监听的一系列事件

input事件
select事件
Change事件
reset事件
submit事件

input事件
input事件当input,select、textarea 的值发生变化时触发。对于复选框(input type=checkbox )或单选框( input type=radio>),用户改变选项时,也会触发这个事件
input事件的一个特点,就是会连续触发,比如用户每按下一次按键,就会触发一次input事件.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
 	<input type="text" id="username">
 	<script>
    	var username = document.getElementById("username");
    	username.oninput = function(){
       		alert("输入了"+username.value);
   		}
	</script>
</body>
</html>

select事件
当在 input、textarea 里面选中文本时触发

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <input type="text" id="username">
    <script>
       var username = document.getElementById("username");
       username.onselect=function(){
           alert("hello");
       }
    </script>
</body>
</html>

change 事件
Change事件当input、select、textarea的值发生变化时触发。它与input事件的最大不同,就是不会连续触发,只有当全部修改完成时才会触发。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <input type="text" id="username">
    <input type="password" id="password">
    <input type="submit" value="登录" id="login">
    <script>
       var password = document.getElementById("password");
       password.onchange = function (e) {
           console.log(e.target.value)
       }
    </script>
</body>
</html>

reset 事件,submit 事件
这两个事件发生在表单对象 form上,而不是发生在表单的成员上。
reset事件当表单重置 (所有表单成员变回默认值)时触发
submit事件当表单数据向服务器提交时触发。注意,submit事件的发生对象是form元素,而不是button元
素,因为提交的是表单,而不是按钮。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <form action="http://localhost" id="myForm",onsubmit="submitHandle">
        <input type="text">
        <button id="resetBtn">重置</button>
        <button>提交</button>
    </form>
    <script>
        var resetBtn=document.getElementById("resetBtn");
        var myForm=document.getElementById("myForm");
        resetBtn.onclick = function(){
            myForm.reset();
        }
        function submitHandle(){
            console.log("提交成功");
            alert("提交成功");
        }
    </script>
</body>
</html>

事件代理(事件委托)

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理 (delegation)。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>

</head>
<body>
    <ul id="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    </form>
    <script>
        var list = document.getElementById('list');
        list.addEventListener('click',function(e){
            var target = e.target;
            if(target.tagName === 'LI'){
                target.style.color ='green';
            }
        })
        list.addEventListener('mouseover',function(e){
            var target = e.target;
            if(target.tagName === 'LI'){
                target.style.background='red';
            }
        })
        list.addEventListener('mouseout',function(e){
            var target = e.target;
            if(target.tagName === 'LI'){
                target.style.background='white';
            }
        })

定时器-setTimeout

JavaScript 提供定时执行代码的功能,叫做定时器 (timer),主要由setTmeout()和senterval()这两个函数来完成。它们向任务队列添加定时任务。

setTimeout 函数用来指定某个函数或某段代码,在多少毫秒之后执行。它返回一个整数,表示定时器的编号,以后可以用来取消这个定时器。

var timerId = setTimeout(funclcode, delay);

setTimeout 函数接受两个参数,第一个参数 func|code 是将要推迟执行的函数名或者一段代码,第二个参数 delay 是推迟执行的毫秒数。

setTimeout(function(){
console.log("定时器")
},1000)

温馨提示
还有一个需要注意的地方,如果回调函数是对象的方法,那么setTimeout 使得方法内部的 this 关键字指向全局环境,而不是定义时所在的那个对象.

<script>
	name="idear";
	user={
		name:"iwen",
		getName:function(){
			setTimeout(function(){console.log(this.name),3000})
			}
		}
		user.getName()//结果为idear
</script>
	

定时器可以取消

var timer=setTimeout(function(){
	console.log("延迟3秒打印")}3000)
clearTimeout(timer)//取消定时器

定时器-setInterval
setintervel 函数的用法与setTimu 完全一致,区别仅仅在于stnel 指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>
</head>
<body>
    <script>
        var i=0;
	    var timer = setInterval(function() {
            i++
            console.log(i);
            },1000)
</script>
</body>
</html>

动画效果

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>
    <style>
        #someDiv {
            background-color: red;
            height: 100px;
            width: 100px;
            opacity: 0;
        }
    </style>
    </style>

</head>
<body>
    <div id="someDiv"></div>
    <script>

        var someDiv = document.getElementById("someDiv");
        var opacity = 0;
	    var fade= setInterval(function() {
            opacity += 0.1;
            if (opacity >= 1) {
                clearInterval(fade);
            } else {
                someDiv.style.opacity = opacity;
            }
            },1000)
</script>
</body>
</html>

防抖

防抖严格算起来应该属于性能优化的知识,但实际上遇到的频率相当高,处理不当或者放任不管就容易引起浏览器卡死。
从滚动条监听的例子说起。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>
    <style>
        #someDiv {
            background-color: red;
            height: 2000px;
            width: 100px;
            opacity: 1;
        }
    </style>
</head>
<body>
    <div id="someDiv"></div>
    <script>
        window.onscroll = showTop
        function showTop(){
            var scro11Top = document.documentElementscrollTop;
            console.log("滚动条位置: + scro11Top");
        }

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

在运行的时候会发现存在一个问题:这个函数的默认执行频率,太!高!了!。高到什么程度呢? 以chrome为例,我们可以点击选中一个页面的滚动条,然后点击一次键盘的[向下方向键],会发现函数执行了8-9次!

然而实际上我们并不需要如此高频的反馈,毕竟浏览器的性能是有限的,不应该浪费在这里,所以接着讨论如何优化这种场景。

基于上述场景,首先提出第一种思路: 在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后

如果在200ms内没有再次触发滚动事件,那么就执行函数
如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时

效果:如果短时间内大量触发同一事件,只会执行一次函数

实现:既然前面都提到了计时,那实现的关键就在于setTimeout这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>
    <style>
        #someDiv {
            background-color: red;
            height: 2000px;
            width: 100px;
            opacity: 1;
        }
    </style>
</head>
<body>
    <div id="someDiv"></div>
    <script>
        //降低执行频率,防抖
        function debounce(fn,delay){
            var timer = null;
            return function(){
                if(timer){
                    clearTimeout(timer);
                }
                timer = setTimeout(fn,delay);
            }
        }
        //滚动事件
        window.onscroll = debounce(showTop,200)
        function showTop(){
            var scrollTop = document.documentElementscrollTop;
            console.log("滚动条位置:" + scrollTop);
        }
</script>
</body>
</html>

节流

如果在限定时间段内,不断触发滚动事件(比如某个用户闲着无聊,按住滚动不断的拖来拖去),只要不停止触发,理论上就永远不会输出当前距离顶部的距离
但是如果产品同学的期望处理方案是: 即使用户不断拖动滚动条,也能在某个时间间隔之后给出反馈呢?其实很简单: 我们可以设计一种类似控制阀门一样定期开放的函数,也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活(类似于技能冷却时间)效果:如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>javaScrip</title>
    <style>
        #someDiv {
            background-color: red;
            height: 2000px;
            width: 100px;
            opacity: 1;
        }
    </style>
</head>
<body>
    <div id="someDiv"></div>
    <script>
        //节流
        function throttle(fn,delay){
            var valid = true;
            return function(){
                if(!valid){
                    return false;
                }
                setTimeout(function(){
                    fn();
                    valid = true;
                },delay);
            }
        }
        //滚动事件
        window.onscroll = throttle(showTop,300)
        function showTop(){
            var scrollTop = document.documentElementscrollTop;
            console.log("滚动条位置:" + scrollTop);
        }
</script>
</body>
</html>
转载请注明出处或者链接地址:https://www.qianduange.cn//article/6776.html
标签
评论
会员中心 联系我 留言建议 回顶部
复制成功!