JS高级语法与JS选择器

元素(element)和节点(node)

childNode属性和children属性的区别




    
    Title


 

JS高级语法与JS选择器_第1张图片

childNodes属性返回的是NodeList数组,是属于节点(也包括元素)的属性,而children属性返回的是子元素,是属于元素的属性

而在Nodelist数组里面也有元素存在,证明了元素也是节点的一种,即元素节点。

W3C中的解释是:

在 HTML DOM (文档对象模型)中,每个部分都是节点

文档本身是文档节点
所有 HTML 元素是元素节点
所有 HTML 属性是属性节点
HTML 元素内的文本是文本节点 (包括回车符,空格,空白字符也是属于文本节点)
注释是注释节点

Element 对象可以拥有类型为元素节点、文本节点、注释节点的子节点。

NodeList 对象表示节点列表,比如 HTML 元素的子节点集合。

元素也可以拥有属性。属性是属性节点。
总结:元素是元素节点,是节点中的一种,但元素节点中可以包含很多的节点

nodeName(纯大写) 属性含有某个节点的名称

元素节点的nodeName 是标签名称
属性节点的nodeName 是属性名称
文本节点的nodeName 永远是 #text
文档节点的nodeName 永远是 #document

nodeValue 对于文本节点,nodeValue 属性包含文本。 对于属性节点,nodeValue 属性包含属性值
nodeValue 属性对于文档节点和元素节点是不可用的 

nodeType 属性可返回节点的类型

Element 元素     1
Attribute 属性   2
Text 文本        3
CDATA Section CDATA断     4
Entity Reference 实体参数  5
Entity 实体       6
Processing Instrucion 处理指令  7
Comment 注释    8
Document 文档    9
Document Type 文档类型   10
Document Fragment 文档片断   11

添加和删除节点(HTML 元素)

创建新的 HTML 元素

如需向 HTML DOM 添加新元素,您必须首先创建该元素(元素节点),然后向一个已存在的元素追加该元素




    
    Title


这是一个段落

这是另一个段落

JS高级语法与JS选择器_第2张图片

删除已有的 HTML 元素

如需删除 HTML 元素,您必须首先获得该元素的父元素




    
    Title



这是一个段落。

这是另一个段落。

常用节点操作

1.节点查找
document.getElementById,document.getElementByTagName,document.getElementByName ,document.getElementByClassName
document.querySelector() 参数为选择器
document.forms 选取页面中的所有表单元素
2.增加节点
增加节点前必须先使用document.createElement()创建元素节点,参数为标签名
m.appendChild(n) 为m元素在末尾添加n节点
m.insertBefore(k,n) 在m元素的k节点前添加n节点
3.删除节点
m.removeChild(n)删除m元素中的n节点
m.replaceChild(k,n)用n节点取代m元素中的k节点
4.复制节点
m.cloneChild() 复制m节点,并将复制出来的节点作为返回值
参数为true时,则将m元素的后代元素也一并复制。否则,仅复制m元素本身


节点属性操作

节点(自身)属性:
  
attributes - 节点(元素)的 属性节点
nodeType – 节点类型
nodeValue – 节点值
nodeName – 节点名称
innerHTML - 节点(元素)的文本值

1.节点属性值选取
m.属性名  (:驼峰形式 )     m.className
m[“属性名”]      m.['className']

m.getAttribute(“属性名”)  :加引号,html的形式       m.getAttribute("class")

2.节点属性修改
前两种选取方法时,直接赋值即可
m.setAttribute("属性名",“值”)


3.创建属性节点并设置属性值
var info_node=document.createAttribute(\"info\");//创建
info_node.value='123';//设置
sup1.setAttributeNode(info_node);//添加

4.复制节点
var body = document.querySelector('body');
true深拷贝,拷贝自身与内容, false浅拷贝,只拷贝自身标签
var cl_body = body.cloneNode(true);
console.log(cl_body);


 
JS DOM节点(当前标签和同级、父级、子级..之间的关系)
1. 通过顶层document节点获取
    1) document.getElementById(elementId) //根据id获得
    2) document.getElementsByName(elementName) //根据name获得
    3) document.getElementsByTagName(tagName) //根据标签名获得
2、通过父节点获取
    1) parentObj.firstChild //获得第一个子节点
    2) parentObj.lastChild //获得第二个子节点
    3) parentObj.childNodes //获取作为指定对象直接后代的HTML元素和TextNode对象的集合
    4) parentObj.children //非标准dom集合,建议使用childNodes
    5) parentObj.getElementsByTagName(tagName) //获得该标签下标签名为tagName的所有标签
3、通过临近节点获取
    1) neighbourNode.previousSibling //获得同级前一个标签
    2) neighbourNode.nextSibling //获得同级后一个标签
4、通过子节点获取
    1) childNode.parentNode //获得父标签

事件

onload:页面加载完毕事件,只附属于window对象
onclick:鼠标点击时间
onmouseover:鼠标悬浮事件
onmouseout:鼠标移开事件

on事件绑定方式

document.onclick = function() {
console.log("文档点击");
}

on事件只能绑定一个方法,重复绑定保留最后一次绑定的方法

document.onclick = function() {
console.log("文档点击");
}

事件的移除

document.onclick = null;

非on事件绑定方式

document.addEventListener('click', function() {
console.log("点击1");
})
document.addEventListener('click', function() { console.log("点击2"); })

非on事件可以同时绑定多个方法,被绑定的方法依次被执行
addEventListener第三个参数(true|false)决定冒泡的方式

function fn () {}
document.addEventListener('click', fn);

事件的移除
document.removeEventListener('click', fn,false);

事件的三种绑定方式的思考

方法一:嵌入dom
把onclick绑定在标签上
HTML元素行间事件(也可以叫HTMl事件处理程序),直接在html标签里添加事件。
缺点:html和js代码紧密耦合

 
方法二:直接绑定
onclick的js绑定办法

//把一个函数赋值给一个事件处理程序属性。(这种方式也叫做Dom0级事件处理程序)
var btn1 = document.getElementById('btn1');
function abc() {
    alert('abc');
}
btn1.onclick = abc; //当点击的时候执行abc这个函数,等价于 btn1.οnclick=function abc(){alert('abc');}
//btn1.onclick = null; //去掉绑定的事件

方法三:事件监听

 click的js绑定办法(js的话推荐这种)
//通过“事件监听”的方式来绑定事件(也叫Dom2级事件处理程序)

var btn2 = document.getElementById('btn2');
btn2.addEventListener('click', showMsg, false); //鼠标单击的时候调用showMes这个函数  
function showMsg() {
    alert("事件监听");
}
//btn2.removeEventListener('click', showMsg, false); //去除绑定


方法一
最原始的写法:和html混合在一起写,缺点是代码高冗余,且无法添加多个事件处理函数如上文对事件的举例则为典型的**html事件处理程序*写法

方法二
dom0级:将html代码和js代码分离,且支持匿名函数,可以看到完美的改进了1的冗余缺憾,所有的事件相关操作都在js中完成

方法三
dom2级:ie使用attachEventListener其他非ie使用addEventListener,可以支持绑定多个事件,瞧吧,又一个缺憾被完美解决了~,而且dom2级还可以自定义事件流,下一篇会分析事件流模型

dom3级:对事件进行了更广而全的分类,请自行查阅

实例运用一



    

实例运用二

复习并延伸



    
    复习预习
    


    
div div div

事件参数event

存放事件信息的回调参数

在触发DOM上某个事件时,会产生一个事件对象event,这个对象包含着所有事件有关的信息(导致事件的元素、事件的类型、与特定事件相关的信息)
所有浏览器都支持Event对象,但支持方式不同
IE中的事件对象:window.event

阻止事件冒泡 

DOM中提供stopPropagation()方法,但IE不支持,使用event对象在事件函数中调用就行
IE中提供的是,cancelBubble属性,默认为false,当它设置为true时,就是阻止事件冒泡,也是用event对象在事件函数中调用 
 
jQuery中提供了stopPropagation()方法来停止事件冒泡,当需要时,只需用用event对象来调用就行,即event.stopPropagation();

默认行为

阻止默认行为 
DOM中提供preventDefault()方法来取消事件默认行为,但是只有当cancelable属性设置为true的事件,才可以使用preventDefault()来取消事件默认行为,使用event对象在事件函数中调用就行
IE中提供的是returnValue属性,默认为true,当它设置为false时,就是取消事件默认行为,也是用event对象在事件函数中调用
jQuery中提供了preventDefault()方法来阻止元素的默认行为,只需要用event对象来调用就好,即event.preventDefault()
如果想同时对事件对象停止冒泡和默认行为,可以在事件处理函数中返回false。这是对事件对象同时调用stopPropagation()方法和preventDefault()方法的一种简写方式 

事件注意点

1、event代表事件的状态,例如触发event对象的元素、鼠标的位置及状态、按下的键等等;
2、event对象只在事件发生的过程中才有效。
firefox里的event跟IE里的不同,IE里的是全局变量,随时可用;
firefox里的要用参数引导才能用,是运行时的临时变量

在IE/Opera中是window.event,在Firefox中是event;
而事件的对象,在IE中是window.event.srcElement,在Firefox中是event.target,Opera中两者都可用

处理冒泡与默认事件

事件的冒泡:父子都具有点击事件,不处理的话,点击子级也会出发父级的点击事件

如果提供了事件对象,则这是一个非IE浏览器
if ( e && e.stopPropagation )
因此它支持W3C的stopPropagation()方法
e.stopPropagation(); 
else
否则,我们需要使用IE的方式来取消事件冒泡 
window.event.cancelBubble = true;
return false;

处理冒泡实例




    
    事件对象
    


    
12345
只想相应点击事件

事件默认行为:当一个事件发生时浏览器自己会做的事情

如果提供了事件对象,则这是一个非IE浏览器 
if ( e && e.preventDefault ) 
阻止默认浏览器动作(W3C) 
e.preventDefault(); 
else
IE中阻止函数器默认动作的方式 
window.event.returnValue = false; 
return false;

既然return false 和 e.preventDefault()都是一样的效果,那它们有区别吗?当然有
仅仅是在HTML事件属性 和 DOM0级事件处理方法中 才能通过返回 return false 的形式组织事件宿主的默认行为

处理默认事件实例




    
    事件对象
    


    
12345
只想相应点击事件

再补充一些

默认操作 具体指的是什么呢?
(1)把单击事件处理程序注册到一个锚元素,而不是一个外层的

上,那么就要面对另外一个问题:当用户单击链接时,浏览器会加载一个新页面。

(2)当用户在编辑完表单后按下回车键时,会触发表单的submit事件,在此事件发生后,表单提交才会真正发生。
这种行为与我们讨论的事件处理程序不是同一个概念,它是单击标签元素的默认操作。

如果我们不希望执行这种默认操作,那么在事件对象上调用.stopPropagation()方法也无济于事,因为默认操作不是在正常的事件传播流中发生的
在这种情况下,处理方法有:

1、w3c的方法是e.preventDefault(),IE则是使用e.returnValue = false;
preventDefault它是事件对象(Event)的一个方法,作用是取消一个目标元素的默认行为。既然是说默认行为,当然是元素必须有默认行为才能被取消,如果元素本身就没有默认行为,调用当然就无效了。什么元素有默认行为呢?如链接,提交按钮等。当Event 对象的 cancelable为false时,表示没有默认行为,这时即使有默认行为,调用preventDefault也是不会起作用的。
1 caibaojian.com

var a = document.getElementById("testA");
a.onclick =function(e){
    if(e.preventDefault){
        e.preventDefault();//
    }else{
        window.event.returnValue = false;//IE
     //注意:这个地方是无法用return false代替的 
     //return false只能取消元素
    }
}


2、return false;
javascript的return false只会阻止默认行为,而是用jQuery的话则既阻止默认行为又防止对象冒泡

常见事件

鼠标事件

var box = document.querySelector('.box');

1. 点击事件
box.onclick = function () {
    console.log("单击");
};
2. 双击事件(应用场景不广)
box.ondblclick = function () {
    console.log("双击");
};
3. 鼠标右键
box.oncontextmenu = function () {
    console.log("右键了");
    return false;
};
4. 鼠标悬浮 | 移动 | 按下 | 抬起 | 离开
box.onmouseover = function () {
    console.log("悬浮");
};
box.onmousemove = function () {
    console.log("移动");
};
box.onmousedown = function () {
    console.log("按下");
};
box.onmouseup = function () {
    console.log("抬起");
};
box.onmouseout = function () {
    console.log("离开");
}

事件参数ev
ev.clientX:点击点X坐标
ev.clientY:点击点Y坐标

over | out   VS   enter | leave

总结:
1. 将子级与父级分开考虑, 大家都有各自的悬浮离开事件, 采用 over | out 组合
2. 将子级纳入父级考虑范围, 也就是只有父级去相应悬浮离开事件, 采用 enter | leave 组合
3. 单独考虑一个盒子的悬浮离开事件, 两套均可以

特性
从父级移至子级, 会触发out事件, 紧接着触发子级的over事件, 并可以冒泡给父级

从父级移至子级, leave事件并不会触发, 它认为子级是属于父级的一部分, enter事件, 也不会再次触发

悬浮子级:
sub over => sup over  支持冒泡
sup enter => sub enter  不支持冒泡

键盘事件

键盘事件
onkeydown:键盘按下会触发,长按持续触发
onkeyup:键盘抬起

事件参数ev

ev.keyCode:按键编号
ev.altKey:alt特殊按键
ev.ctrlKey:ctrl特殊按键
ev.shiftKey:shift特殊按键



    
    键盘事件
    


    

表单事件

onfocus:获取焦点
onblur:失去焦点
onselect:文本被选中
oninput:值改变
onchange:值改变,且需要在失去焦点后才能触发
onsubmit:表单默认提交事件

文档事件

文档事件由window调用
onload:页面加载完毕触发
onbeforeunload:页面退出或刷新警告,需要设置回调函数返回值,返回值随意

图片事件 

onerror:图片加载失败

页面事件

onscroll:页面滚动
onresize:页面尺寸调整
window.scrollY:页面下滚距离

文档页面事件运用实例




    
    其他事件
    


    




































































































JS选择器

getElement系列

通过id名获取唯一满足条件的页面元素

document.getElementById('id名');
该方法只能由document调用
任何HTML元素可以有一个id属性,在文档中该值必须唯一
若浏览器中出现多个id名的情况,CSS样式对所有该id名的元素都生效,但javascript脚本仅对第一个出现该id名的元素生效。
getElementById()该方法接收一个参数:要取得元素的id,若找到则返回该元素,若不存在则返回null
注意:document.getElementById方法的内部实现需要用到this,这个this本来被期望指向document

跨浏览器兼容
1:在ie7中,使用getElementById()的时候,接收的参数id不区分大小写。
2:在表单元素中,如果表单设置有name属性,其name属性会被当做id识别出来。
3:id是唯一的,但name属性并不是唯一的。具有该名称的隐式全局变量会引用一个类数组对象,包括所有该命名的元素

通过class名获取所有满足条件的页面元素

document.getElementsByClassName('class名');
该方法可以由document及任意页面元素对象调用
document.getElementsByClass("class1
class2")可以拿到同时拥有class1和class2的元素,中间用空格隔开,不区分class1和class2的顺序。

兼容性:IE8及其以下版本的浏览器未实现getElementsByClassName方法
返回值为HTMLCollection (一个类数组结果的对象,使用方式同数组)
没有匹配到任何结果返回空HTMLCollection对象 ([]) 

通过name属性获取元素

getElementsByName(返回值是一个nodeList集合(区别于Array),可作用于Dom元素)
getElementsByName()方法接收一个参数,即要取得元素的name值。

document.getElementsByName("Name");Name为要获取元素的name属性值,这个方法一般适用于提交表单数据,当
元素为form、img、iframe、applet、embed、object的时候设置name属性时,会自动在Document对象中创建以该
name属性值命名的属性。
所以可以通过document.domName引用相应的dom对象。

在ie9中,getElementsByName()只对表单元素起作用。
IE9-浏览器中使用getElementsByName()方法也会返回id属性匹配的元素。因此,不要将name和id属性设置为相同的值。

通过tag名获取所有满足条件的页面元素

document.getElementsByTagName('tag名');
该方法可以由document及任意页面元素对象调用
返回值为HTMLCollection (一个类数组结果的对象,使用方式同数组)
没有匹配到任何结果返回空HTMLCollection对象 ([]) 
可以使用方括号语法或item()方法来访问类数组对象中的项,length属性表示对象中元素的数量。
[注意]通过getElementsByTagName()方法取得的类数组对象有一个namedItem()方法,可以通过元素的name属性取得集合中的第一个值。safari和IE不支持该方法。document.getElementsByTagName("*")表示匹配文档的所有元素

querySelect系列

获取第一个匹配到的页面元素

document.querySelector('css语法选择器');
该方法可以由document及任意页面对象调用 

获取所有匹配到的页面元素

document.querySelectorAll('css语法选择器');
该方法可以由document及任意页面对象调用
返回值为NodeList (一个类数组结果的对象,使用方式同数组)
没有匹配到任何结果返回空NodeList对象 ([])

id名

可以通过id名直接获取对应的页面元素对象,但是不建议使用

js选择器运用实例




    
    js选择器
    


    
    
我是ddd111
我是ddd222

选择器分类

1. ID选择器

使用ID选择器时,需在前面添加“#”,区分大小写,语法如下:document.querySelector('#id'); //等同于document.getElementById('id')

2. 元素选择器

元素选择器通过指定的标签查询元素,此时querySelectorAll等同于getElementsByTagName,语法如下:document.querySelectorAll('a'); //获取页面上的所有a元素并返回元素

3. 样式类选择器

使用元素的样式类获取一个或一类元素,样式名字前使用“.”(英文句号)开头,语法如下:document.querySelectorAll('.btn'); //获取所有样式类中包含btn类名的元素

4. 分组选择器

使用querySelectorAll不仅可以获取一个或一类元素,还可以同时获取其他类别元素,两种类型之间使用逗号隔开,语法如下:document.querySelectorAll('a,p'); 
//获取页面上所有a元素和p元素,并通过一个列表返回document.querySelectorAll('.btn,.txt'); //获取页面上所有包含btn和txt样式类名的元素

5. 属性选择器

获取页面上包含指定属性的元素,属性名称可以是元素原生属性和用户自定义属性,语法如下:document.querySelectorAll('a[target="_blank"]'); 
//获取页面上所有target属性为_blank的a元素document.querySelectorAll('img[data-id]'); //获取页面上所有带有自定义属性data-id的img元素

6. 后代选择器

主要用于选择作为某元素后代的元素,规则左边的选择器一端包含两个或多个用空格分隔的选择器,如div a可以理解为查找所有被div包围的所有a元素,语法如下:document.querySelectorAll('div a'); 
//获取页面上所有被div包含的a元素document.querySelectorAll('div .btn'); //获取页面上所有被div包含的带有btn样式类名的元素
 
7. 子元素选择器

后代选择器会将元素底下的所有相关元素都搜索出来,如果想进一步缩小范围,可以使用子元素选择器,只会选择某个元素的一级子元素,子元素用“>”(大于号)表示,代码如下:
    
8. 相邻兄弟选择器(比较少用) 选择紧接在另一个元素后的元素,而且两者有相同的父元素,相邻兄弟选择器使用“+”(加号),代码如下:

9. 伪类选择器 “:first-child”表示选择元素的第一个子元素,“:last-child”表示选择元素的最后一个子元素,“:nth-child(n)”表示选择元素的第n个子元素。“:first-child”的使用例子,代码如下:

闭包

function outer() {
var data = {}
function inner() {
return data;
}
return inner;
}

闭包目的:不允许提升变量作用域时,该函数的局部变量需要被其他函数使用
闭包本质:函数的嵌套,内层函数称之为闭包
闭包的解决案例:①影响局部变量的生命周期,持久化局部变量;②解决变量污染




    
    闭包


闭包


循环绑定

.html文件

  • 列表项
  • 列表项
  • 列表项

.js文件

var lis = document.querySelector('li');
for (var i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
// 打印列表项的索引
console.log(i);
}
}

会发生变量污染

解决方法

1 获取局部作用域解决   2  闭包解决  3  对象属性解决




    
    循环绑定


0000000000000000001
0000000000000000002
0000000000000000003

面向对象JS

属性与方法

var obj = {}; | var obj = new Object();

属性

obj.prop = "";

方法

obj.func = function () {}

删除属性与方法

delete obj.prop
delete obj.func

属性和方法实际使用

对象: 特征与行为的结合体, 是一个具象的实体

// js对象语法
var obj = {
// 属性
name: 'Zero',
// 方法
teach: function () {
 console.log("教学");
}
};
// 对象使用属性与方法, 采用.语法
console.log(obj.name);
obj.teach();

JS中中括号([ ])与 .

中括号运算符总是能代替点运算符。但点运算符却不一定能全部代替中括号运算符
中括号运算符可以用字符串变量的内容作为属性名。点运算符不能
中括号运算符可以用纯数字为属性名。点运算符不能
中括号运算符可以用js的关键字和保留字作为属性名。点运算符不能

下面的例子中,a.b表示对象a的属性b,既可以设置也可以读取

object[key]=>key为常量时,object[key]等价于object.key,例如:a.b == a['b'] 

特殊的,object[key] 中key为变量时,只能用中括号形式

var a = {};
 // a.b = 1; 
a['b'] = 1; 
c = a.b; 
// c = a['b'];
alert(c);

标识符是否合法对两种用法的影响

var obj = {}; 
// 为obj添加一个属性name,name是合法的标识符,即也可以通过obj.name方式来定义

obj['name'] = 'jack'; 

// 为obj添加一个属性2a,2a不是合法的标识符(不能以数字开头),不能通过obj.2a来定义

obj['2a'] = 'test';

var obj = {name:'jack'};
obj['2a'] = 'test';
obj['name']; // --> jack 
obj['2a']; // --> test (不能通过obj.2a获取)

总结:常量用点,变量就用中括号

运算符左侧应当是一个表达式,它返回一个对象。
对于点(.)来说,右侧必须是一个以属性名称命名的简单标识符。
对于方括号([])来说,方括号里必须是一个计算结果为字符串的表达式,这个字符串就是属性的名字

当通过点运算符(.)方法对象属性时,属性名用一个标识符来表示。标识符必须直接出现在js程序中,它们不是数据类型,因此程序无法修改它们。
反过来讲,当通过[]来方式对象的属性时,属性名通过字符串表示。字符串是js的数据类型,在程序运行时可以修改和创建它们

这段代码读取customer对象的address0,adddress1,address2,adddress3属性,并将他们连接起来

类字典结构使用

结构

var dict = {name: "zero", age: 18}

拓展

var dict = {"my-name": "zero", fn: function () {}, fun () {}}

使用

dict.name | dict["my-name"] | dict.fn()

构造函数(ES5)

// 构造函数: 声明与普通函数一样, 只是函数名采用大驼峰命名规则
function Person(name) {  // 类似于python中的类一样来使用
   // 构造函数内部属性方式不同于普通函数
   this.name = name;  // this代表Person构造函数实例化出的所有具体对象中的某一个
   this.teach = function () {
       console.log(this.name + "正在教学");
   }
}
// 如何使用构造函数中的属性与方法
// 1. 通过构造函数实例化出具体对象
// 2. 通过对象.语法调用属性与方法
var p1 = new Person("杨虎虎");  // name: 杨虎虎
var p2 = new Person("刘xx");  // name: 刘xx
console.log(p1.name);
console.log(p2.name);
p1.teach();
p2.teach();


为什么要用new?

new  会创建  pre 的对象,
但是没有 new 的话就没有没有可返回的值或对象了,所以是  undefined。
如果不想new 新的对象的话,可以在 pre 的方法里 返回一个值或对象。
function pre(){
    this.radius = Math.random();
    return this.radius;
}

加 new 会把这个函数当作是一个构造器,返回一个对象。
不加的话,就是调用一个普通的函数,结果视函数返回值而定。 
有new,就返回对象,不管函数返回值如何。
无new,就看函数返回值。
构造函数最好返回 this 或者无返回值, 否则容易混淆。

类及继承(ES6)

// ES6
// 引入了类
class Student {  // 类, 可以实例化对象, 但实例化出的对象需要加以区分
// 需要构造器(构造函数)来完成对象的声明与初始化
// ES6规定方法的语法
constructor (name) {
   // 属性在构造器中声明并完成初始化
   this.name = name;
}
// 类中规定普通方法
study () {
   console.log(this.name + "正在学习");
}
// 类方法
static fn() {
console.log("我是类方法")
  }
}
// 1.实例化类的对象
let stu1 = new Student("嘿嘿");
// 2.使用属性与方法
console.log(stu1.name);
stu1.study();

let stu2 = new Student("嘻嘻");
console.log(stu2.name);
stu2.study();

Student.fn()


 

转载于:https://www.cnblogs.com/596014054-yangdongsheng/p/10142691.html

你可能感兴趣的:(JS高级语法与JS选择器)