DOM模型这个特别重要哦(三)

举报
龙哥手记 发表于 2022/09/17 13:46:46 2022/09/17
【摘要】 《JavaScript》系列,第十三篇希望你持续关注哦!

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();

下面比较一下,classNameclassList在添加和删除某个 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.abcDefdata-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部分,但是不包括bordermargin。如果有水平滚动条,还要减去水平滚动条的高度。注意,这个值始终是整数,如果是小数会被四舍五入。

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

document.documentElementclientHeight属性,返回当前视口的高度(即浏览器窗口的高度),等同于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)的宽度(单位像素),不包括左侧的paddingmargin。如果没有设置左边框,或者是行内元素(display: inline),该属性返回0。该属性总是返回整数值,如果是小数,会四舍五入。

Element.clientTop属性等于网页元素顶部边框的宽度(单位像素),其他特点都与clientLeft相同。

1.10 Element.scrollHeight 元素总高度,Element.scrollWidth 元素总宽度

Element.scrollHeight属性返回一个整数值(小数会四舍五入),表示当前元素的总高度(单位像素),包括溢出容器、当前不可见的部分。它包括padding,但是不包括bordermargin以及水平滚动条的高度(如果有水平滚动条的话),还包括伪元素(::before::after)的高度。

Element.scrollWidth属性表示当前元素的总宽度(单位像素),其他地方都与scrollHeight属性类似。这两个属性只读。

整张网页的总高度可以从document.documentElementdocument.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仍然会返回该元素的原始高度。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。