在现代JavaScript应用程序中使用DOM Level 0 collections是否有一套商定的“最佳实践”? (document.forms
,document.images
等。)
在使用jQuery的应用程序中,我注意到,比如使用$(...).html()
更改下拉列表的内容以切换底层节点,而不是使用element.options[]
。这是因为最好避免使用DOM 0集合,还是因为jQuery使更改底层DOM结构变得更容易?
编辑:我想部分问题包括旧功能是否可靠的跨浏览器。我记得,曾经有一段时间,IE会自动将<tbody>
标签添加到你的桌面,而firefox则不会。这使得走在dom tree痛苦的跨浏览器。同样,element.options[]
有problems when changing the options in the collection。这些人是否可靠跨浏览器?
答案 0 :(得分:16)
首先,很好的问题。
DOM Level 0-1功能是我最喜欢的工具箱。支持是巨大的。我将在下面强调DOM Level 0的每个子集的优缺点:
由于这些是作为 ElementNode 的属性添加的,因此您只能拥有一个处理程序。对于某些情况(例如:事件委托),这是繁重的。但是,我觉得DOM足够多(特别是当你的项目变大时)为DOM 0级处理程序提供足够的空间。没有库/框架来平滑旧浏览器,DOM Level 2监听器很难实现。即使作为Flash开发人员(在任何地方都使用了侦听器),DOM 0事件对我来说也容易得多。其中一个亮点是为您设置this
值(没有IE浏览器和其他模型咳嗽)。例如,考虑这个标记:
<div id="foo">Cick Me!</div>
现在,所有需要做的就是选择和附加DOM Level 0处理程序。
var foo = document.getElementById("foo");
function bar()
{
console.log(this); //<div id="foo">
}
foo.onclick = bar;
这是选择元素的一种非常简单的方法,也是Event.currentTarget的替代方法;
这里有关于DOM Level 0事件与DOM Level 2事件的讨论:[link]
Bar none, HTMLCollections 是我最喜欢的DOM功能。由于为您选择了节点,因此无需运行查询。在我看来,它们是当今最容易被忽视的DOM功能。名称遍历如:collection["name"]
非常方便,在遍历表单时肯定有帮助。例如,考虑一下这个标记:
<form action="./" id="foo" name="foo" method="post" onsubmit="return false;">
<fieldset>
<legend>Dummy Form</legend>
<input type="text" name="bar">
<select name="baz">
<option selected value="1">1</option>
</select>
</fieldset>
</form>
有许多DOM Level 0方法可以解决这个问题。
var foo = document.forms.foo; //<form id="foo" onsubmit="return false;" method="post" name="foo" action="./">
var foo = document.forms[0]; //<form id="foo" onsubmit="return false;" method="post" name="foo" action="./">
var foo = document.getElementById("foo"); //<form id="foo" onsubmit="return false;" method="post" name="foo" action="./">
当然,方法3是更优选的。它是DOM级别1,而不是DOM级别0.但是,名称遍历自然适合HTMLFormElement.elements HTMLCollection 。由于您应该在表单元素上使用name
属性,因此您可以在没有id
属性的情况下轻松访问它们。
例如:var baz = foo.elements.baz;
使用共享相同名称的单选按钮(一次只能选择一个)时,可以使用HTMLFormElement.elements HTMLCollection 选择所有单选按钮。这非常强大。考虑这个标记:
<form action="./" id="foo" name="foo" method="post" onsubmit="return false;">
<fieldset>
<legend>Radio Buttons</legend>
<label for="select_1">1</label>
<input id="select_1" type="radio" name="selectable" value="a">
<label for="select_2">2</label>
<input id="select_2" type="radio" name="selectable" value="b">
<label for="select_3">3</label>
<input id="select_3" type="radio" name="selectable" value="c">
</fieldset>
</form>
您可以使用这个简单的代码,让每个单选按钮的name
属性值为“selectable”:
var foo = document.forms.foo;
var selectables = foo.elements.selectable;
console.log(selectables); //[input#select_1 a, input#select_2 b, input#select_3 c]
var foo = document.forms.foo;
var selectables = foo.selectable;
console.log(selectables); //[input#select_1 a, input#select_2 b, input#select_3 c]
选项2可让您完全绕过elements
HTMLCollection 。虽然肯定不如选项1那么明确,但它仍然在今天使用。
HTMLCollections 变得更加人性化,而且更加多样化。例如,看一下表格中可用的 HTMLCollections 。这令人震惊。有HTMLTableElement.rows,HTMLTableElement.tBodies,HTMLTableSectionElement (thead, tbody, tfoot).rows和HTMLTableRowElement.cells。这些集合非常强大,并且使表格的DOM遍历变得更加简单(允许您使用它们)。
虽然 ElementNodes 上的属性在DOM级别0中并不像现在这样多,但仍有几个宝石需要注意:
HTMLInputElement.defaultChecked
defaultChecked
使您可以完全绕过HTMLInputElement的checked
属性搜索,因为它会根据该属性的值存储布尔值。这意味着您不必通过与get / set / removeAttribute相关的IE构建的草率解决方案进行克服。稍后,还会添加defaultValue
属性以满足类似需求。
document.lastModified [非标准]
lastModified
将存储文档上次更改的时间。这是一个很酷的小功能,使用有限。
title
会为你抓住文件的标题。它的使用充其量只是一个小利基。
关于您的tbody
问题,如果您不推广正确的DOM结构,今天的浏览器会添加HTMLTableSectionElement(tbody)。您应该了解正确的表格标记,以便将来不会出现问题:)。
示例标记:
错误:
<table>
<!-- tbody will be inserted here and will wrap the tr -->
<tr>
<td>Hello, World!</tr>
</tr>
</table>
右:
<table>
<tbody>
<tr>
<td>Hello, World!</td>
</tr>
</tbody>
</table>
演示:http://jsbin.com/exomub/edit#preview
需要被驱动回家的要点是DOM级别0的大多数都是在DOM级别1和2中标准化的。这意味着浏览器支持是广泛的(因为它确实很旧)。除了旧浏览器版本中的一些边缘情况之外,不应该过多担心使用它。在一天结束时,这是你的选择。
我想补充一点,我过去只是非常简短地使用HTML / JavaScript进行开发。我这是一个爱好,所以我不知道有关浏览器/项目出错的“恐怖故事”。
我希望这能清除一些事情。
-Matt
ElementNode - nodeType == 1
HTMLCollection - 浏览器收集的类似实时阵列的NodeList
答案 1 :(得分:5)
这是一个非常有趣的问题。这是我的两分钱。
首先,它可能不言而喻,但它取决于您正在处理的代码。专业程序员的目标是遵循公司范围内(或者,对于大型公司,团队范围内)最佳实践,如果这些准则不鼓励或禁止DOM级别0,则不应使用它。如果它被允许或根本不被提及,那么该决定将解决为个人选择,例如您自己的代码。
现在,如果你愿意,没有明显的技术缺陷阻止你使用0级。例如,如果迭代element.options
比element.getElementsByTagName("option")
或$("option", element)
慢,我会感到惊讶。第一种语法也可以说比其他选择更多可读。
浏览器支持也不是问题。 0级是older than dirt,并且在太阳下每个脚本感知浏览器都支持了十多年。
但是,以上是关于选择,而不是效率,这是你问题的后半部分所关注的。实际上,您可以以或多或少相同的效率迭代element.options
或$("option", element)
或$(element).children("option")
,但如果您需要做大量工作(例如,消除现有的{{1}元素并添加新元素),然后使用<option>
或element.innerHTML
肯定会更快。
那是因为innerHTML Level 0属性和html() jQuery方法(内部使用$(element).html()
)都将所有标记解析和DOM操作委托给浏览器,这通常是写的在较低级别的语言中,严重针对这些任务进行了优化。在Javascript循环中逐个删除innerHTML
元素总是比较慢,在这种情况下,使用DOM Level 0或jQuery的所有铃声和口哨绝对没有区别。
答案 2 :(得分:3)
我首先要说的是,我不知道任何“官方”声明,例如“DOM Level 0被视为有害”。这只是我自己的看法。
我认为这取决于具体情况。
我遇到的问题是,使用documents.forms
或documents.images
这样的集合来定位特定元素时,尤其是动态生成/修改过的文档存在问题。每当我看到有人写document.forms[0]
时,我都会畏缩。
当前,甚至不那么流行的浏览器通过getElementsByTagName
等函数提供了模拟相同行为的能力,但是以更通用和可重用的方式。当然,当你在混合中添加jQuery时,根本没有理由使用这些集合。
我遇到的例外情况是,当您在非jQuery环境中工作并且正在访问selectElement.options
或tbodyElement.rows
之类的内容时。在这些情况下,当您进行添加或删除项目等基本操作时,它确实更简单。
答案 3 :(得分:3)
在使用jQuery的应用程序中,我注意到,比如使用$(...)。html()更改下拉列表的内容以切换底层节点,而不是使用元素。选项[]。这是因为最好避免使用dom0集合,还是因为jQuery使更改底层DOM结构变得更容易?
这可以很容易地解释。 95%的jQuery开发人员不了解DOM API存在或可以使用的事实。
jQuery被滥用于DOM可以更容易地做的事情这一事实仅仅是由于没有学习DOM的人造成的。
我个人会说使用DOM 0,但话说回来,我个人会说使用DOM shim并且不使用jQuery。这都是一个选择问题。
做最多 可维护的
答案 4 :(得分:1)
无论好坏,我使用纯DOM级别0功能主要用于调试。检查document.forms [0]。输入元素有时会更快。
当我正在检查一些使用某些深奥(或根本不为我所知)框架的页面时,我也使用了这些功能。我没有时间深入研究这些抽象,只是直接检查馆藏。
我相信你会更好地了解所有这些DOM零库,但如果你知道所有这些现代纯DOM不知道哪个级别它是exaclty级API,那就更好了。例如,ClassList集合很好。我的意思是,如果你使用的是框架,你应该总是知道,为什么完全需要它。