回顾文档对象模型 (DOM)(二)

一、Element

1、属性

(1)Element.attributes

属性返回该元素所有属性节点的一个实时集合。该集合是一个 NamedNodeMap 对象,不是一个数组,所以它没有 数组 的方法,其包含的 属性 节点的索引顺序随浏览器不同而不同。更确切地说,attributes 是字符串形式的名/值对,每一对名/值对对应一个属性节点。

在这里插入图片描述

// 获取文档中的第一个 <p> 元素
var para = document.getElementsByTagName("p")[0];
var atts = para.attributes;

(2)Element.innerHTML

属性设置或获取HTML语法表示的元素的后代。

获取元素的HTML
let contents = myElement.innerHTML;

替换元素的内容
document.documentElement.innerHTML = "<pre>" + 
         document.documentElement.innerHTML.replace(/</g,"&lt;") +
            "</pre>";

(3)name

获取或设置一个 DOM 对象的 name 属性;它只能应用于下列元素:a applet button, form, frame, iframe, img, input, map, meta object param select textarea.

// 获取表单中第一个元素的引用
  var formElement = document.forms['formA'].elements[0];
  // 设置一个 name
  formElement.name = 'inputA';
  // 显示 input 的 value 值
  alert(document.forms['formA'].elements['inputA'].value);

(4)element.outerHTML

DOM接口的outerHTML属性获取描述元素(包括其后代)的序列化HTML片段。它也可以设置为用从给定字符串解析的节点替换元素。

const d = document.getElementById("d");
console.log(d.outerHTML);

(5)NonDocumentTypeChildNode

接口包含专属于某些(特殊) Node 对象的方法,这些对象可以拥有父对象,但不适用于 DocumentType 接口。NonDocumentTypeChildNode 是一个裸接口(raw interface),无法创建拥有此类型的对象;它是由 Element,和 CharacterData 对象实现的。

**nextElementSibling **
返回当前元素在其父元素的子元素节点中的后一个元素节点,如果该元素已经是最后一个元素节点,则返回null,该属性是只读的.

<div id="div-01">Here is div-01</div>
<div id="div-02">Here is div-02</div>

<script type="text/javascript">
  var el = document.getElementById('div-01').nextElementSibling;
  document.write('<p>Siblings of div-01</p><ol>');
  while (el) {
    document.write('<li>' + el.nodeName + '</li>');
    el = el.nextElementSibling;
  }
  document.write('</ol>');
</script>

**previousElementSibling **
回当前元素在其父元素的子元素节点中的前一个元素节点,如果该元素已经是第一个元素节点,则返回null,该属性是只读的.

<div id="div-01">Here is div-01</div>
<div id="div-02">Here is div-02</div>
<li>This is a list item</li>
<li>This is another list item</li>
<div id="div-03">Here is div-03</div>

<script type="text/javascript">
  var el = document.getElementById('div-03').previousElementSibling;
  document.write('<p>Siblings of div-03</p><ol>');
  while (el) {
    document.write('<li>' + el.nodeName + '</li>');
    el = el.previousElementSibling;
  }
  document.write('</ol>');
</script>

2、方法

(1)Element.attachShadow() 方法给指定的元素挂载一个Shadow DOM,并且返回对 ShadowRoot 的引用。
ShadowRoot

接口是一个 DOM 子树的根节点, 它与文档的主 DOM 树分开渲染。
你可以通过使用一个元素的 Element.shadowRoot 属性来检索它的参考,假设它是由 Element.attachShadow() 创建的并使 mode 设置为 open.

  // 创建一个shadow root
    var shadow = this.attachShadow({mode: 'open'});

    // 创建文本节点并向其添加计数器
    var text = document.createElement('span');
    text.textContent = count;

    // 将其添加到shadow root上
    shadow.appendChild(text);

    // 当元素内容发生变化时更新计数
    setInterval(function() {
      var count = 'Words: ' + countWords(wcParent);
      text.textContent = count;
    }, 200);
  }

(2)Element.closest() 法用来获取:匹配特定选择器且离当前元素最近的祖先元素(也可以是当前元素本身)。如果匹配不到,则返回 null

var el = document.getElementById('div-03');

var r1 = el.closest("#div-02");  
// 返回 id 为 div-02 的那个元素

var r2 = el.closest("div div");  
// 返回最近的拥有 div 祖先元素的 div 祖先元素,这里的话就是 div-03 元素本身

var r3 = el.closest("article > div");  
// 返回最近的拥有父元素 article 的 div 祖先元素,这里的话就是 div-01

var r4 = el.closest(":not(div)"); 
// 返回最近的非 div 的祖先元素,这里的话就是最外层的 article

(3) getAttribute() 返回元素上一个指定的属性值。如果指定的属性不存在,则返回 null 或 “” (空字符串)

let div1 = document.getElementById("div1");
let align = div1.getAttribute("align");

alert(align); 

(4)Element.getAttributeNode() 返回指定元素的指定属性节点

// html: <div id="top" /> 
var t = document.getElementById("top"); 
var idAttr = t.getAttributeNode("id"); 
alert(idAttr.value == "top")

(5)Element.getElementsByClassName()

方法返回一个即时更新的(live) HTMLCollection,包含了所有拥有指定 class 的子元素。当在 document 对象上调用此方法时,会检索整个文档,包括根元素。
相似地,getElementsByClassName() 方法会在整个文档上执行;它返回指定拥有指定 class 名称的 document 根节点的后代元素。

element.getElementsByClassName('test');

(6)Element.hasAttribute() 返回一个布尔值,指示该元素是否包含有指定的属性(attribute)。

// 在为属性设置新值前检测该属性是否存在
var d = document.getElementById("div1"); 

if (d.hasAttribute("align")) { 
  d.setAttribute("align", "center"); 
}

(7)insertAdjacentElement() 方法将一个给定的元素节点插入到相对于被调用的元素的给定的一个位置。

A DOMString 表示相对于该元素的位置;必须是以下字符串之一:

'beforebegin': 在该元素本身的前面.
'afterbegin':只在该元素当中, 在该元素第一个子孩子前面.
'beforeend':只在该元素当中, 在该元素最后一个子孩子后面.
'afterend': 在该元素本身的后面.
beforeBtn.addEventListener('click', function() {
  var tempDiv = document.createElement('div');
  tempDiv.style.backgroundColor = randomColor();
  activeElem.insertAdjacentElement('beforebegin',tempDiv);
  setListener(tempDiv);
});

afterBtn.addEventListener('click', function() {
  var tempDiv = document.createElement('div');
  tempDiv.style.backgroundColor = randomColor();
  activeElem.insertAdjacentElement('afterend',tempDiv);
  setListener(tempDiv);
});

(8)insertAdjacentHTML() 方法将指定的文本解析为 Element 元素,并将结果节点插入到DOM树中的指定位置。它不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素。这避免了额外的序列化步骤,使其比直接使用innerHTML操作更快。

// 原为 <div id="one">one</div> 
var d1 = document.getElementById('one'); 
d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');

// 此时,新结构变成:
// <div id="one">one</div><div id="two">two</div>

(9)insertAdjacentText() 方法将一个给定的文本节点插入在相对于被调用的元素给定的位置。

beforeBtn.addEventListener('click', function() {
  para.insertAdjacentText('afterbegin',textInput.value);
});

afterBtn.addEventListener('click', function() {
  para.insertAdjacentText('beforeend',textInput.value);
});

(10)Element.setAttribute() 设置指定元素上的某个属性值。如果属性已经存在,则更新该值;否则,使用指定的名称和值添加一个新的属性。

var b = document.querySelector("button"); 

b.setAttribute("name", "helloButton");
b.setAttribute("disabled", "");

3、事件

(1)contextmenu 事件会在用户尝试打开上下文菜单时被触发。该事件通常在鼠标点击右键或者按下键盘上的菜单键时被触发,如果使用菜单键,该上下文菜单会被展示 到所聚焦元素的左下角,但是如果该元素是一棵DOM树的话,上下文菜单便会展示在当前这一行的左下角。

noContext = document.getElementById('noContextMenu');

noContext.addEventListener('contextmenu', e => {
  e.preventDefault();
});

二、Event

接口表示在 DOM 中出现的事件。
一些事件是由用户触发的,例如鼠标或键盘事件;而其他事件常由 API 生成,例如指示动画已经完成运行的事件,视频已被暂停等等。事件也可以通过脚本代码触发,例如对元素调用 HTMLElement.click() 方法,或者定义一些自定义事件,再使用 EventTarget.dispatchEvent() 方法将自定义事件派发往指定的目标(target)。

1、使用网页事件的方式

(1)事件处理器属性

const btn = document.querySelector('button');

btn.onclick = function() {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  document.body.style.backgroundColor = rndCol;
}

这个 onclick 是被用在这个情景下的事件处理器的属性,它就像 button 其他的属性(如 btn.textContent, or btn.style), 但是有一个特别的地方——当您将一些代码赋值给它的时候,只要事件触发代码就会运行

(2)行内事件处理器 - 请勿使用

<button onclick="bgChange()">Press me</button>

function bgChange() {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  document.body.style.backgroundColor = rndCol;
}

在Web上注册事件处理程序的最早方法是类似于上面所示的事件处理程序HTML属性(也称为内联事件处理程序)—属性值实际上是当事件发生时要运行的JavaScript代码。

(3)addEventListener() 和removeEventListener()

const btn = document.querySelector('button');

function bgChange() {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  document.body.style.backgroundColor = rndCol;
}   

btn.addEventListener('click', bgChange);

新的事件触发机制被定义在 Document Object Model (DOM) Level 2 Events Specification, 这个细则给浏览器提供了一个函数 — addEventListener()。

2、其他事件概念

事件对象

有时候在事件处理函数内部,您可能会看到一个固定指定名称的参数,例如event,evt或简单的e。 这被称为事件对象,它被自动传递给事件处理函数,以提供额外的功能和信息。

function bgChange(e) {
  const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  e.target.style.backgroundColor = rndCol;
  console.log(e);
}  

btn.addEventListener('click', bgChange);

阻止默认行为

const form = document.querySelector('form');
const fname = document.getElementById('fname');
const lname = document.getElementById('lname');
const submit = document.getElementById('submit');
const para = document.querySelector('p');

form.onsubmit = function(e) {
  if (fname.value === '' || lname.value === '') {
    e.preventDefault();
    para.textContent = 'You need to fill in both names!';
  }
}

我们在事件对象上调用preventDefault()函数,这样就停止了表单提交

事件冒泡及捕获

当一个事件发生在具有父元素的元素上,现代浏览器运行两个不同的阶段 - 捕获阶段和冒泡阶段。

在捕获阶段

浏览器检查元素的最外层祖先,是否在捕获阶段中注册了一个onclick事件处理程序,如果是,则运行它。然后,它移动到中单击元素的下一个祖先元素,并执行相同的操作,然后是单击元素再下一个祖先元素,依此类推,直到到达实际点击的元素。

在冒泡阶段,恰恰相反

浏览器检查实际点击的元素是否在冒泡阶段中注册了一个onclick事件处理程序,如果是,则运行它
然后它移动到下一个直接的祖先元素,并做同样的事情,然后是下一个,等等,直到它到达元素。

用 stopPropagation() 修复问题

stopPropagation()的函数, 当在事件对象上调用该函数时,它只会让当前事件处理程序运行,但事件不会在冒泡链上进一步扩大,因此将不会有更多事件处理器被运行(不会向上冒泡)

video.onclick = function(e) {
  e.stopPropagation();
  video.play();
};

3、属性

(1)bubbles 返回一个布尔值,表明当前事件是否会向DOM树上层元素冒泡.

 function goInput(e) {
  // 检查事件对象是否冒泡
  if (!e.bubbles) {
     // 如果不冒泡,则手动传递事件
     passItOn(e); 
  }
  // 如果冒泡的话
  doOutput(e)
}

(2)cancelable 实例的只读属性 cancelable 表明该事件是否可以被取消,当事件被阻止之后,该事件就好像没有被触发一样。如果事件不能被取消,则其 cancelable 属性的值为 false,且事件发生时无法在事件监听回调中停止事件。

(3)cancelBubble 属性是 Event.stopPropagation()的一个曾用名。在从事件处理程序返回之前将其值设置为true可阻止事件的传播。

ele.onclick = function(e) {
  // 在这儿可以做点儿有趣的事情 
  e.cancelBubble = true;
}

(4)currentTarget 标识是当事件沿着 DOM 触发时事件的当前目标。它总是指向事件绑定的元素,而 Event.target 则是事件触发的元素。

function hide(e){
  e.currentTarget.style.visibility = "hidden";
  console.log(e.currentTarget);
  // 该函数用作事件处理器时: this === e.currentTarget
}

var ps = document.getElementsByTagName('p');

for(var i = 0; i < ps.length; i++){
  // console: 打印被点击的p元素
  ps[i].addEventListener('click', hide, false);
}
// console: 打印body元素
document.body.addEventListener('click', hide, false);

(5)defaultPrevented 返回一个布尔值,表明当前事件是否调用了 event.preventDefault()方法。

(6)isTrusted 属性是一个只读属性,它是一个布尔值(Boolean)。当事件是由用户行为生成的时候,这个属性的值为 true ,而当事件是由脚本创建、修改、通过 EventTarget.dispatchEvent() 派发的时候,这个属性的值为 false 。

if (e.isTrusted) {
  /* Event 事件可信 */
} else {
  /* Event 事件不可信 */
}

(7)returnValue 属性表示该事件的默认操作是否已被阻止。默认情况下,它被设置为 true,即允许进行默认操作。将该属性设置为 false 即可阻止默认操作。

(8)target 触发事件的对象 (某个DOM元素) 的引用。当事件处理程序在事件的冒泡或捕获阶段被调用时,它与event.currentTarget不同。
(9)type 只读属性 Event.type 会返回一个字符串, 表示该事件对象的事件类型。

4、方法

(1)preventDefault() 告诉user agent:如果此事件没有被显式处理,它默认的动作也不应该照常执行。此事件还是继续传播,除非碰到事件侦听器调用stopPropagation() 或stopImmediatePropagation(),才停止传播。

document.querySelector("#id-checkbox").addEventListener("click", function(event) {
         document.getElementById("output-box").innerHTML += "Sorry! <code>preventDefault()</code> won't let you check this!<br>";
         event.preventDefault();
}, false);

(2)stopImmediatePropagation 方法阻止监听同一事件的其他事件监听器被调用。

(3)stopPropagation 阻止捕获和冒泡阶段中当前事件的进一步传播。

三、EventTarget

EventTarget 是一个 DOM 接口,由可以接收事件、并且可以创建侦听器的对象实现。

Element,document 和 window 是最常见的 event targets ,但是其他对象也可以作为 event targets,比如 XMLHttpRequest,AudioNode,AudioContext 等等。

var EventTarget = function() {
  this.listeners = {};
};

EventTarget.prototype.listeners = null;
EventTarget.prototype.addEventListener = function(type, callback) {
  if(!(type in this.listeners)) {
    this.listeners[type] = [];
  }
  this.listeners[type].push(callback);
};

EventTarget.prototype.removeEventListener = function(type, callback) {
  if(!(type in this.listeners)) {
    return;
  }
  var stack = this.listeners[type];
  for(var i = 0, l = stack.length; i < l; i++) {
    if(stack[i] === callback){
      stack.splice(i, 1);
      return this.removeEventListener(type, callback);
    }
  }
};

EventTarget.prototype.dispatchEvent = function(event) {
  if(!(event.type in this.listeners)) {
    return;
  }
  var stack = this.listeners[event.type];
  event.target = this;
  for(var i = 0, l = stack.length; i < l; i++) {
      stack[i].call(this, event);
  }
};

1、方法

(1)addEventListener

方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。 事件目标可以是一个文档上的元素 Element,Document和Window或者任何其他支持事件的对象 (比如 XMLHttpRequest)。

addEventListener()的工作原理是将实现EventListener的函数或对象添加到调用它的EventTarget上的指定事件类型的事件侦听器列表中。

target.addEventListener(type, listener, options);
target.addEventListener(type, listener, useCapture);
target.addEventListener(type, listener, useCapture, wantsUntrusted  );  // Gecko/Mozilla only

type
表示监听事件类型的字符串。
listener
当所监听的事件类型触发时,会接收到一个事件通知(实现了 Event 接口的对象)对象。listener 必须是一个实现了 EventListener 接口的对象,或者是一个函数。
options 可选
一个指定有关 listener 属性的可选参数对象。可用的选项如下:

    capture:  Boolean,表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发。
    once:  Boolean,表示 listener 在添加之后最多只调用一次。如果是 true, listener 会在其被调用之后自动移除。
    passive: Boolean,设置为true时,表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。查看 使用 passive 改善的滚屏性能 了解更多.

useCapture 可选
Boolean,在DOM树中,注册了listener的元素, 是否要先于它下面的EventTarget,调用该listener。 当useCapture(设为true) 时,沿着DOM树向上冒泡的事件,不会触发listener。当一个元素嵌套了另一个元素,并且两个元素都对同一事件注册了一个处理函数时,所发生的事件冒泡和事件捕获是两种不同的事件传播方式。事件传播模式决定了元素以哪个顺序接收事件。

// 改变t2的函数
function modifyText() {
  var t2 = document.getElementById("t2");
  if (t2.firstChild.nodeValue == "three") {
    t2.firstChild.nodeValue = "two";
  } else {
    t2.firstChild.nodeValue = "three";
  }
}

// 为table添加事件监听器
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);

(2)dispatchEvent

向一个指定的事件目标派发一个事件,
并以合适的顺序同步调用目标元素相关的事件处理函数。标准事件处理规则(包括事件捕获和可选的冒泡过程)同样适用于通过手动的使用dispatchEvent()方法派发的事件。

const event = new Event('build');

// Listen for the event.
elem.addEventListener('build', function (e) { /* ... */ }, false);

// Dispatch the event.
elem.dispatchEvent(event)

(3)removeEventListener

删除使用 EventTarget.addEventListener() 方法添加的事件。使用事件类型,事件侦听器函数本身,以及可能影响匹配过程的各种可选择的选项的组合来标识要删除的事件侦听器。

匹配要删除的事件监听

需要提供以前调用addEventListener()所提供的监听事件, 这样你或许可以达到移除此监听事件的目的. 很明显, 你需要提供相同的 type 和 listener 参数给 removeEventListener(), 但是 options 或者 useCapture 参数呢?

当使用 addEventListener() 时, 如果 options参数不同, 那么你可以在相同的type 上多次添加相同的监听, 唯一需要 removeEventListener() 检测的是 capture/useCapture 标志. 这个标志必须与 removeEventListener() 的对应标志匹配, 但是其他的值不需要.

element.addEventListener("mousedown", handleMouseDown, true);

element.removeEventListener("mousedown", handleMouseDown, false);     // 失败
element.removeEventListener("mousedown", handleMouseDown, true);      // 成功
element.addEventListener("mousedown", handleMouseDown, { passive: true });

element.removeEventListener("mousedown", handleMouseDown, { passive: true });     // Succeeds
element.removeEventListener("mousedown", handleMouseDown, { capture: false });    // Succeeds
element.removeEventListener("mousedown", handleMouseDown, { capture: true });     // Fails
element.removeEventListener("mousedown", handleMouseDown, { passive: false });    // Succeeds
element.removeEventListener("mousedown", handleMouseDown, false);                 // Succeeds
element.removeEventListener("mousedown", handleMouseDown, true);                  // Fails
var body = document.querySelector('body'),
    clickTarget = document.getElementById('click-target'),
    mouseOverTarget = document.getElementById('mouse-over-target'),
    toggle = false;

function makeBackgroundYellow() {
    'use strict';

    if (toggle) {
        body.style.backgroundColor = 'white';
    } else {
        body.style.backgroundColor = 'yellow';
    }

    toggle = !toggle;
}

clickTarget.addEventListener('click',
    makeBackgroundYellow,
    false
);

mouseOverTarget.addEventListener('mouseover', function () {
    'use strict';

    clickTarget.removeEventListener('click',
        makeBackgroundYellow,
        false
    );
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值