DOM模型这个特别重要哦(三)
3.19 document.createTreeWalker() 返回一个DOM的子树遍历器(TreeWalker实例)
document.createTreeWalker
方法返回一个 DOM 的子树遍历器。它与document.createNodeIterator
方法基本是类似的,区别在于它返回的是TreeWalker
实例,后者返回的是NodeIterator
实例。另外,它的第一个节点不是根节点。
document.createTreeWalker
方法的第一个参数是所要遍历的根节点,第二个参数指定所要遍历的节点类型(与document.createNodeIterator
方法的第二个参数相同)。
和document.createNodeIterator
方法区别二是:TreeWalker
实例有currentNode
属性。
var treeWalker = document.createTreeWalker(
document.body, // 所要遍历的根节点
NodeFilter.SHOW_ELEMENT // 所要遍历的节点类型
);
var nodeList = [];
// 每调用一次nextNode(),currentNode属性的值将改为下一个节点
while(treeWalker.nextNode()) {
nodeList.push(treeWalker.currentNode); // TreeWalker实例有currentNode属性
}
上面代码遍历<body>
节点下属的所有元素节点,将它们插入nodeList
数组。
3.20 document.execCommand(),document.queryCommandSupported(),document.queryCommandEnabled()
(1)document.execCommand() 执行命令(实现复制文本等功能,富文本编辑器大量使用此方法)
概念一: 当一个HTML文档切换到设计模式时,document
暴露 execCommand
方法,该方法允许运行命令来操纵可编辑内容区域的元素。
概念二: execCommand方法是执行一个对当前文档,当前选择或者给出范围的命令。处理Html数据时常用
概念三:如果document.designMode
属性设为on
,那么整个文档用户可编辑;如果元素的contenteditable
属性设为true
,那么该元素可编辑。这两种情况下,可以使用document.execCommand()
方法,改变内容的样式,比如document.execCommand('bold')
会使得字体加粗。
document.execCommand(command, showDefaultUI, input)
该方法接受三个参数。
command
:字符串,表示所要实施的样式。showDefaultUI
:布尔值,表示是否要使用默认的用户界面,建议总是设为false
。input
:字符串,表示该样式的辅助内容,比如生成超级链接时,这个参数就是所要链接的网址。如果第二个参数设为true
,那么浏览器会弹出提示框,要求用户在提示框输入该参数。但是,不是所有浏览器都支持这样做,为了兼容性,还是需要自己部署获取这个参数的方式。
var url = window.prompt('请输入网址');
if (url) {
document.execCommand('createlink', false, url);
}
上面代码中,先提示用户输入所要链接的网址,然后手动生成超级链接。注意,第二个参数是false
,表示此时不需要自动弹出提示框。
document.execCommand()
的返回值是一个布尔值。如果为false
,表示这个方法无法生效。
这个方法大部分情况下,只对选中的内容生效。如果有多个内容可编辑区域,那么只对当前焦点所在的元素生效。
document.execCommand()
方法可以执行的样式改变有很多种,下面是其中的一些:bold、insertLineBreak、selectAll、createLink、insertOrderedList、subscript、delete、insertUnorderedList、superscript、formatBlock、insertParagraph、undo、forwardDelete、insertText、unlink、insertImage、italic、unselect、insertHTML、redo。这些值都可以用作第一个参数,它们的含义不难从字面上看出来。
命令列表
1. 2D-Position 允许通过拖曳移动绝对定位的对象。
2. AbsolutePosition 设定元素的 position 属性为“absolute”(绝对)。
3. BackColor 设置或获取当前选中区的背景颜色。
4. BlockDirLTR 目前尚未支持。
5. BlockDirRTL 目前尚未支持。
6. Bold 切换当前选中区的粗体显示与否。
7. BrowseMode 目前尚未支持。
8. Copy 将当前选中区复制到剪贴板。
9. CreateBookmark 创建一个书签锚或获取当前选中区或插入点的书签锚的名称。
10.CreateLink 在当前选中区上插入超级链接,或显示一个对话框允许用户指定要为当前选中区插入的超级链接的 URL。
11.Cut 将当前选中区复制到剪贴板并删除之。
12.Delete 删除当前选中区。
13.DirLTR 目前尚未支持。
14.DirRTL 目前尚未支持。
15.EditMode 目前尚未支持。
16.FontName 设置或获取当前选中区的字体。
17.FontSize 设置或获取当前选中区的字体大小。
18.ForeColor 设置或获取当前选中区的前景(文本)颜色。
19.FormatBlock 设置当前块格式化标签。
20.Indent 增加选中文本的缩进。
21.InlineDirLTR 目前尚未支持。
22.InlineDirRTL 目前尚未支持。
23.InsertButton 用按钮控件覆盖当前选中区。
24.InsertFieldset 用方框覆盖当前选中区。
25.InsertHorizontalRule 用水平线覆盖当前选中区。
26.InsertIFrame 用内嵌框架覆盖当前选中区。
27.InsertImage 用图像覆盖当前选中区。
28.InsertInputButton 用按钮控件覆盖当前选中区。
29.InsertInputCheckbox 用复选框控件覆盖当前选中区。
30.InsertInputFileUpload 用文件上载控件覆盖当前选中区。
31.InsertInputHidden 插入隐藏控件覆盖当前选中区。
32.InsertInputImage 用图像控件覆盖当前选中区。
33.InsertInputPassword 用密码控件覆盖当前选中区。
34.InsertInputRadio 用单选钮控件覆盖当前选中区。
35.InsertInputReset 用重置控件覆盖当前选中区。
36.InsertInputSubmit 用提交控件覆盖当前选中区。
37.InsertInputText 用文本控件覆盖当前选中区。
38.InsertMarquee 用空字幕覆盖当前选中区。
39.InsertOrderedList 切换当前选中区是编号列表还是常规格式化块。
40.InsertParagraph 用换行覆盖当前选中区。
41.InsertSelectDropdown 用下拉框控件覆盖当前选中区。
42.InsertSelectListbox 用列表框控件覆盖当前选中区。
43.InsertTextArea 用多行文本输入控件覆盖当前选中区。
44.InsertUnorderedList 切换当前选中区是项目符号列表还是常规格式化块。
45.Italic 切换当前选中区斜体显示与否。
46.JustifyCenter 将当前选中区在所在格式化块置中。
47.JustifyFull 目前尚未支持。
48.JustifyLeft 将当前选中区所在格式化块左对齐。
49.JustifyNone 目前尚未支持。
50.JustifyRight 将当前选中区所在格式化块右对齐。
51.LiveResize 迫使 MSHTML 编辑器在缩放或移动过程中持续更新元素外观,而不是只在移动或缩放完成后更新。
52.MultipleSelection 允许当用户按住 Shift 或 Ctrl 键时一次选中多于一个站点可选元素。
53.Open 打开。
54.Outdent 减少选中区所在格式化块的缩进。
55.OverWrite 切换文本状态的插入和覆盖。
56.Paste 用剪贴板内容覆盖当前选中区。
57.PlayImage 目前尚未支持。
58.Print 打开打印对话框以便用户可以打印当前页。
59.Redo 重做。
60.Refresh 刷新当前文档。
61.RemoveFormat 从当前选中区中删除格式化标签。
62.RemoveParaFormat 目前尚未支持。
63.SaveAs 将当前 Web 页面保存为文件。
64.SelectAll 选中整个文档。
65.SizeToControl 目前尚未支持。
66.SizeToControlHeight 目前尚未支持。
67.SizeToControlWidth 目前尚未支持。
68.Stop 停止。
69.StopImage 目前尚未支持。
70.StrikeThrough 目前尚未支持。
71.Subscript 目前尚未支持。
72.Superscript 目前尚未支持。
73.UnBookmark 从当前选中区中删除全部书签。
74.Underline 切换当前选中区的下划线显示与否。
75.Undo 撤消。
76.Unlink 从当前选中区中删除全部超级链接。
77.Unselect 清除当前选中区的选中状态。
(2)document.queryCommandSupported() 浏览器是否支持execCommand的某个命令
document.queryCommandSupported()
方法返回一个布尔值,表示浏览器是否支持document.execCommand()
的某个命令。
if (document.queryCommandSupported('SelectAll')) {
console.log('浏览器支持选中可编辑区域的所有内容');
}
(3)document.queryCommandEnabled() 当前是否可用execCommand的某个命令
document.queryCommandEnabled()
方法返回一个布尔值,表示当前是否可用document.execCommand()
的某个命令。比如,bold
(加粗)命令只有存在文本选中时才可用,如果没有选中文本,就不可用。
// HTML 代码为
// <input type="button" value="Copy" onclick="doCopy()">
function doCopy(){
// 浏览器是否支持 copy 命令(选中内容复制到剪贴板)
if (document.queryCommandSupported('copy')) {
copyText('你好');
}else{
console.log('浏览器不支持');
}
}
function copyText(text) {
var input = document.createElement('textarea');
document.body.appendChild(input);
input.value = text;
input.focus();
input.select();
// 当前是否有选中文字
if (document.queryCommandEnabled('copy')) {
var success = document.execCommand('copy');
input.remove();
console.log('Copy Ok');
} else {
console.log('queryCommandEnabled is false');
}
}
上面代码中,先判断浏览器是否支持copy
命令(允许可编辑区域的选中内容,复制到剪贴板),如果支持,就新建一个临时文本框,里面写入内容“你好”,并将其选中。然后,判断是否选中成功,如果成功,就将“你好”复制到剪贴板,再删除那个临时文本框。
3.21 document.getSelection()
这个方法指向window.getSelection()
,参见window
对象一节的介绍。
六、Element节点
Element
节点对象对应网页的 HTML 元素。每一个 HTML 元素,在 DOM 树上都会转化成一个Element
节点对象(以下简称元素节点)。
元素节点的nodeType
属性都是1
。
var p = document.querySelector('p');
p.nodeName // "P"
p.nodeType // 1 节点类型 1代表元素节点
Element
对象继承了Node
接口,因此**Node
的属性和方法在Element
对象都存在**。此外,不同的 HTML 元素对应的元素节点是不一样的,浏览器使用不同的构造函数,生成不同的元素节点,比如<a>
元素的节点对象由HTMLAnchorElement
构造函数生成,<button>
元素的节点对象由HTMLButtonElement
构造函数生成。因此,元素节点不是一种对象,而是一组对象,这些对象除了继承Element
的属性和方法,还有各自构造函数的属性和方法。
元素节点拥有 各自构造函数 的属性和方法,继承Element
的属性和方法,同时继承Node
的属性和方法。
1、实例属性
1.1 元素特性的相关属性
(1)Element.id 返回元素ID属性,可读写
Element.id
属性返回指定元素的id
属性,该属性可读写。
// HTML 代码为 <p id="foo">
var p = document.querySelector('p');
p.id // "foo"
注意,id
属性的值是大小写敏感,即浏览器能正确识别<p id="foo">
和<p id="FOO">
这两个元素的id
属性,但是最好不要这样命名。
(2)Element.tagName 返回元素的大写标签
Element.tagName
属性返回指定元素的大写标签名,与nodeName
属性的值相等。
// HTML代码为
// <span id="myspan">Hello</span>
var span = document.getElementById('myspan');
span.id // "myspan"
span.tagName // "SPAN"
(3)Element.dir 元素的文字方向,可读写(ltr、rtl)
Element.dir
属性用于读写当前元素的文字方向,可能是从左到右("ltr"
),也可能是从右到左("rtl"
)。
(4)Element.accessKey 分配给当前元素的快捷键,可读写
Element.accessKey
属性用于读写分配给当前元素的快捷键。
// HTML 代码如下
// <button accesskey="h" id="btn">点击</button>
var btn = document.getElementById('btn');
btn.accessKey // "h"
上面代码中,btn
元素的快捷键是h
,按下Alt + h
就能将焦点转移到它上面。
(5)Element.draggable 当前元素是否可拖动,布尔值,可读写
Element.draggable
属性返回一个布尔值,表示当前元素是否可拖动。该属性可读写。
<p draggable="true" ondragstart="drag(this)">这是一段可移动的段落。</p>
<script>
function drag(el) {
console.log(el.draggable) // true
}
</script>
(6)Element.lang 返回当前元素的语言设置,可读写
Element.lang
属性返回当前元素的语言设置。该属性可读写。
// HTML 代码如下
// <html lang="en">
document.documentElement.lang // "en"
(7)Element.tabIndex 当前元素在 Tab 键遍历时的顺序,整数,可读写
Element.tabIndex
属性返回一个整数,表示当前元素在 Tab 键遍历时的顺序。该属性可读写。
tabIndex
属性值如果是负值(通常是-1
),则 Tab 键不会遍历到该元素。如果是正整数,则按照顺序,从小到大遍历。如果两个元素的tabIndex
属性的正整数值相同,则按照出现的顺序遍历。遍历完所有tabIndex
为正整数的元素以后,再遍历所有tabIndex
等于0
、或者属性值是非法值、或者没有tabIndex
属性的元素,顺序为它们在网页中出现的顺序。
(8)Element.title 当前元素的 HTML 属性title
,可读写
Element.title
属性用来读写当前元素的 HTML 属性title
。该属性通常用来指定,鼠标悬浮时弹出的文字提示框。
1.2 元素状态的相关属性
(1)Element.hidden 当前元素的hidden属性,控制是否可见,布尔值,可读写
Element.hidden
属性返回一个布尔值,表示当前元素的hidden
属性,用来控制当前元素是否可见。该属性可读写。
var btn = document.getElementById('btn');
var mydiv = document.getElementById('mydiv');
btn.addEventListener('click', function () {
mydiv.hidden = !mydiv.hidden;
}, false);
注意,该属性与 CSS 设置是互相独立的。CSS 对这个元素可见性的设置,Element.hidden
并不能反映出来。也就是说,这个属性并不能用来判断当前元素的实际可见性。
**CSS 的设置高于Element.hidden
。**如果 CSS 指定了该元素不可见(display: none
)或可见(display: hidden
),那么Element.hidden
并不能改变该元素实际的可见性。换言之,这个属性只在 CSS 没有明确设定当前元素的可见性时才有效。
(2)Element.contentEditable元素内容的可编辑性,字符串,可读写,
Element.isContentEditable 元素内容是否可编辑,布尔值,只读
HTML 元素可以设置contentEditable
属性,使得元素的内容可以编辑。
<div contenteditable>123</div>
上面代码中,<div>
元素有contenteditable
属性,因此用户可以在网页上编辑这个区块的内容。
Element.contentEditable
属性返回一个字符串,表示是否设置了contenteditable
属性,有三种可能的值。该属性可写。
"true"
:元素内容可编辑"false"
:元素内容不可编辑"inherit"
:元素是否可编辑,继承了父元素的设置
Element.isContentEditable
属性返回一个布尔值,同样表示是否设置了contenteditable
属性。该属性只读。
1.3 Element.attributes 类数组,成员是元素的所有HTML属性节点
Element.attributes
属性返回一个类似数组的对象,成员是当前元素节点的所有属性节点,详见《属性的操作》一章。
var p = document.querySelector('p');
var attrs = p.attributes;
for (var i = attrs.length - 1; i >= 0; i--) {
console.log(attrs[i].name + '->' + attrs[i].value);
}
上面代码遍历p
元素的所有属性。
1.4 Element.className 元素的class,Element.classList 类数组,成员是各class,有自身方法
className
属性**用来读写当前元素节点的class
属性。**它的值是一个字符串,每个class
之间用空格分割。
classList
属性返回一个类似数组的对象,当前元素节点的每个class
就是这个对象的一个成员。
// HTML 代码 <div class="one two three" id="myDiv"></div>
var div = document.getElementById('myDiv');
div.className
// "one two three"
div.classList
// {
// 0: "one"
// 1: "two"
// 2: "three"
// length: 3
// }
上面代码中,className
属性返回一个空格分隔的字符串,而classList
属性指向一个类似数组的对象,该对象的length
属性(只读)返回当前元素的class
数量。
classList
对象有下列方法。
add()
:增加一个 class。remove()
:移除一个 class。contains()
:检查当前元素是否包含某个 class。toggle()
:将某个 class 移入或移出当前元素。item()
:返回指定索引位置的 class。toString()
:将 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
div.classList.item(0); // 返回第一个 Class
div.classList.toString();
下面比较一下,className
和classList
在添加和删除某个 class 时的写法。
var foo = document.getElementById('foo');
// 添加class
foo.className += 'bold';
foo.classList.add('bold');
// 删除class
foo.classList.remove('bold');
foo.className = foo.className.replace(/^bold$/, '');
**toggle
方法可以接受一个布尔值,作为第二个参数。**如果为true
,则添加该属性;如果为false
,则去除该属性。
el.classList.toggle('abc', boolValue);
// 等同于
if (boolValue) {
el.classList.add('abc');
} else {
el.classList.remove('abc');
}
1.5 Element.dataset 返回一个对象,读写元素的data-属性
网页元素可以自定义data-
属性,用来添加数据。
<div data-timestamp="1522907809292"></div>
上面代码中,<div>
元素有一个自定义的data-timestamp
属性,用来为该元素添加一个时间戳。
Element.dataset
属性返回一个对象,可以从这个对象读写data-
属性。
// <article
// id="foo"
// data-columns="3"
// data-index-number="12314"
// data-parent="cars">
// ...
// </article>
var article = document.getElementById('foo');
article.dataset.columns // "3"
article.dataset.indexNumber // "12314"
article.dataset.parent // "cars"
注意,dataset
上面的各个属性返回都是字符串。
HTML 代码中,data-
属性的属性名,只能包含英文字母、数字、连词线(-
)、点(.
)、冒号(:
)和下划线(_
)。它们转成 JavaScript 对应的dataset
属性名,规则如下。
- 开头的
data-
会省略。 - 如果连词线后面跟了一个英文字母,那么连词线会取消,该字母变成大写。
- 其他字符不变。
因此,data-abc-def
对应dataset.abcDef
,data-abc-1
对应dataset["abc-1"]
。
除了使用dataset
读写data-
属性,也可以使用Element.getAttribute()
和Element.setAttribute()
,通过完整的属性名读写这些属性。
var mydiv = document.getElementById('mydiv');
mydiv.dataset.foo = 'bar';
mydiv.getAttribute('data-foo') // "bar"
1.6 Element.innerHTML 返回一个字符串,是元素包含的所有 HTML 代码,可读写
Element.innerHTML
属性返回一个字符串,等同于该元素包含的所有 HTML 代码。该属性可读写,常用来设置某个节点的内容。它能改写所有元素节点的内容,包括<HTML>
和<body>
元素。
如果将innerHTML
属性设为空,等于删除所有它包含的所有节点。
el.innerHTML = '';
上面代码等于将el
节点变成了一个空节点,el
原来包含的节点被全部删除。
注意,读取属性值的时候,如果文本节点包含&
、小于号(<
)和大于号(>
),innerHTML
属性会将它们转为实体形式 & amp;
、& lt;
、& gt;
。如果想得到原文,建议使用element.textContent
属性。
// HTML代码如下 <p id="para"> 5 > 3 < 6 &</p>
document.getElementById('para').innerHTML
// 5 > 3 < &
写入的时候,如果插入的文本包含 HTML 标签,会被解析成为节点对象插入 DOM。注意,如果文本之中含有<script>
标签,虽然可以生成script
节点,但是插入的代码不会执行。
var name = "<script>alert('haha')</script>"; // 插入包含js代码字符串,插入后js不会执行
el.innerHTML = name;
上面代码将脚本插入内容,脚本并不会执行。但是,innerHTML
还是有安全风险的。
var name = "<img src=x onerror=alert(1)>";
el.innerHTML = name;
上面代码中,alert
方法是会执行的。因此为了安全考虑,如果插入的是文本,最好用textContent
属性代替innerHTML
。
1.7 Element.outerHTML 返回一个字符串,包含元素本身和所有子元素的HTML代码,可读写
Element.outerHTML
属性返回一个字符串,表示当前元素节点的所有 HTML 代码,包括该元素本身和所有子元素。
// HTML 代码如下
// <div id="d"><p>Hello</p></div>
var d = document.getElementById('d');
d.outerHTML
// '<div id="d"><p>Hello</p></div>'
outerHTML
属性是可读写的,对它进行赋值,等于替换掉当前元素。
// HTML 代码如下
// <div id="container"><div id="d">Hello</div></div>
var container = document.getElementById('container');
var d = document.getElementById('d');
container.firstChild.nodeName // "DIV"
d.nodeName // "DIV"
d.outerHTML = '<p>Hello</p>'; //div替换成p标签
container.firstChild.nodeName // "P"
d.nodeName // "DIV" 但是变量b依旧指向原来的div元素,还存在于内存中
上面代码中,变量d
代表子节点,它的outerHTML
属性重新赋值以后,内层的div
元素就不存在了,被p
元素替换了。但是,变量d
依然指向原来的div
元素,这表示被替换的DIV
元素还存在于内存中。
注意,如果一个节点没有父节点,设置outerHTML
属性会报错。
var div = document.createElement('div');
div.outerHTML = '<p>test</p>';
// DOMException: This element has no parent node.
上面代码中,div
元素没有父节点,设置outerHTML
属性会报错。
1.8 Element.clientHeight 元素高度,Element.clientWidth元素宽度
Element.clientHeight
属性返回一个整数值,表示元素节点的 CSS 高度(单位像素),只对块级元素生效,对于行内元素返回0
。如果块级元素没有设置 CSS 高度,则返回实际高度。
除了元素本身的高度,它还包括padding
部分,但是不包括border
、margin
。如果有水平滚动条,还要减去水平滚动条的高度。注意,这个值始终是整数,如果是小数会被四舍五入。
Element.clientWidth
属性返回元素节点的 CSS 宽度,同样只对块级元素有效,也是只包括元素本身的宽度和padding
,如果有垂直滚动条,还要减去垂直滚动条的宽度。
document.documentElement
的clientHeight
属性,返回当前视口的高度(即浏览器窗口的高度),等同于window.innerHeight
属性减去水平滚动条的高度(如果有的话)。document.body
的高度则是网页的实际高度。一般来说,document.body.clientHeight
大于document.documentElement.clientHeight
。
// 视口高度 不包括不可见的部分
document.documentElement.clientHeight
// 网页总高度
document.body.clientHeight
1.9 Element.clientLeft 左边框宽度,Element.clientTop上边框宽
Element.clientLeft
属性等于元素节点左边框(left border)的宽度(单位像素),不包括左侧的padding
和margin
。如果没有设置左边框,或者是行内元素(display: inline
),该属性返回0
。该属性总是返回整数值,如果是小数,会四舍五入。
Element.clientTop
属性等于网页元素顶部边框的宽度(单位像素),其他特点都与clientLeft
相同。
1.10 Element.scrollHeight 元素总高度,Element.scrollWidth 元素总宽度
Element.scrollHeight
属性返回一个整数值(小数会四舍五入),表示当前元素的总高度(单位像素),包括溢出容器、当前不可见的部分。它包括padding
,但是不包括border
、margin
以及水平滚动条的高度(如果有水平滚动条的话),还包括伪元素(::before
或::after
)的高度。
Element.scrollWidth
属性表示当前元素的总宽度(单位像素),其他地方都与scrollHeight
属性类似。这两个属性只读。
整张网页的总高度可以从document.documentElement
或document.body
上读取。
// 返回网页的总高度
document.documentElement.scrollHeight
document.body.scrollHeight
注意,如果元素节点的内容出现溢出,即使溢出的内容是隐藏的,scrollHeight
属性仍然返回元素的总高度。
// HTML 代码如下
// <div id="myDiv" style="height: 200px; overflow: hidden;">...<div>
document.getElementById('myDiv').scrollHeight // 356
上面代码中,即使myDiv
元素的 CSS 高度只有200像素,且溢出部分不可见,但是scrollHeight
仍然会返回该元素的原始高度。
- 点赞
- 收藏
- 关注作者
评论(0)