jQuery 到常规 Javascript 的映射
Posted
技术标签:
【中文标题】jQuery 到常规 Javascript 的映射【英文标题】:jQuery to Conventional Javascript mapping 【发布时间】:2011-10-22 10:30:11 【问题描述】:我只想将一些 jQuery 方法映射到它们的普通 javascript DOM 方法;
例如
prev()
next()
before()
after()
如果你能提供 jQuery/Javascript 到类似 DOM 操作方法的映射,那就太好了。
【问题讨论】:
为什么不直接看一下jQuery源码? (它的来源是github.com/jquery/jquery/blob/master/src/traversing.js,但它是个脑筋急转弯,它的声明仍然是坚定的“jQuery”,而不是原生DOM方法)。 完整功能中的方法?例如。prev
和 next
采用选择器...
【参考方案1】:
这些 jQuery 方法在普通的基于 DOM 的 JS 中都没有精确的一对一模拟。如果他们这样做了,jQuery 就不需要实现自己的方法来完成这些任务。
您可以使用elem.previousSibling
和elem.nextSibling
获取元素的上一个和下一个兄弟姐妹。例如,使用这种 html 结构:
<ul>
<li>First</li>
<li id="second">Second</li>
</ul>
你会使用这个 JS:
var elem = document.getElementById("second");
var p = elem.previousSibling;
alert(p.nodeType);
在这种情况下,第二个 LI 的前一个兄弟不是第一个 LI。相反,前一个兄弟是两个 LI 标记之间的空白区域。这样做是为了让您可以操作文档中除了实际的 HTML 元素之外的任何文本节点。 nextSibling
属性的工作原理相同。
这在理论上很好,但在实际使用中或多或少会让人头疼,因为您实际上很少或永远不需要操作文档中的空白。要解决此问题,请遍历检查nodeType
的兄弟姐妹。如果 nodeType 为 1,那么它是一个文本节点,所以跳到下一个,直到找到 nodeType 不是 1 的那个。
您可能会发现博客文章 Finding HTML elements using Javascript nextSibling and previousSibling 很有帮助。只要避免他使用的扩展 Object.prototype 的技术——这样做很容易打破 for/in
在对象上的循环。
对于before()
和after()
,DOM 等价物是insertBefore()
和insertBefore()
在您想要的目标之后运行在兄弟姐妹上。但是,您不能只是将一些 HTML 放入其中并期望它能够工作。相反,您必须手动将每个元素、属性和值创建为 DOM 节点,然后插入它们。例如:
var welcomingDiv;
function sayHi()
welcomingDiv = document.createElement("div");
welcomingDiv.innerHTML = "Welcome, and be amazed!";
target = document.getElementById("a-tag-someplace");
document.body.insertBefore(welcomingDiv, target);
这会将它插入到您的文档中,任何标签的 ID 为“a-tag-someplace”。不过,即使这是一种欺骗,因为 innerHTML 不是官方 JS 标准的一部分。如果您操作正确,则必须创建一个文本节点并将其附加到新创建的 DIV 中。
所以,简而言之:jQuery 让生活变得更加简单。不要在没有充分理由的情况下重新发明***。
【讨论】:
【参考方案2】:prev() - previousSibling, its a property
next() - nextSibling, its a property
before() - insertBefore,
after() - There is no insertAfter method but we implement it using insertBefore
【讨论】:
我相信它们实际上是 $(node.previousSibling) 等。人。是吗? +1 请注意,“after”可以通过使用“insertBefore”来实现,正如你所提到的,或者在父元素上使用“appendChild”来实现在最后一个兄弟之后添加内容的情况。【参考方案3】:以下是TreeWalker(play with it at jsbin.com)的JavaScript实现。
<html>
<head></head>
<body>
<script>
var NodeFilter =
FILTER_ACCEPT: 1,
FILTER_REJECT: 2,
FILTER_SKIP: 3,
SHOW_ALL: -1,
SHOW_ELEMENT: 1,
SHOW_ATTRIBUTE: 2,
SHOW_TEXT: 4,
SHOW_CDATA_SECTION: 8,
SHOW_ENTITY_REFERENCE: 16,
SHOW_ENTITY: 32,
SHOW_PROCESSING_INSTRUCTIONS: 64,
SHOW_COMMENT: 128,
SHOW_DOCUMENT: 256,
SHOW_DOCUMENT_TYPE: 512,
SHOW_DOCUMENT_FRAGMENT: 1024,
SHOW_NOTATION: 2048
;
var TreeWalker = function (root, whatToShow, filter, expandEntityReferences)
this.root = root;
this.whatToShow = whatToShow;
this.filter = filter;
this.expandEntityReferences = expandEntityReferences;
this.currentNode = root;
this.NodeFilter = NodeFilter;
;
TreeWalker.prototype.parentNode = function ()
var testNode = this.currentNode;
do
if (
testNode !== this.root &&
testNode.parentNode &&
testNode.parentNode !== this.root
)
testNode = testNode.parentNode;
else
return null;
while (this._getFilteredStatus(testNode) !== this.NodeFilter.FILTER_ACCEPT);
(testNode) && (this.currentNode = testNode);
return testNode;
;
TreeWalker.prototype.firstChild = function ()
var testNode = this.currentNode.firstChild;
while(testNode)
if(this._getFilteredStatus(testNode) === this.NodeFilter.FILTER_ACCEPT)
break;
testNode = testNode.nextSibling;
(testNode) && (this.currentNode = testNode);
return testNode;
;
TreeWalker.prototype.lastChild = function ()
var testNode = this.currentNode.lastChild;
while (testNode)
if(this._getFilteredStatus(testNode) === this.NodeFilter.FILTER_ACCEPT)
break;
testNode = testNode.previousSibling;
(testNode) && (this.currentNode = testNode);
return testNode;
;
TreeWalker.prototype.nextNode = function ()
var testNode = this.currentNode;
while (testNode)
if (testNode.childNodes.length !== 0)
testNode = testNode.firstChild;
else if (testNode.nextSibling)
testNode = testNode.nextSibling;
else
while (testNode)
if (testNode.parentNode && testNode.parentNode !== this.root)
if (testNode.parentNode.nextSibling)
testNode = testNode.parentNode.nextSibling;
break;
else
testNode = testNode.parentNode;
else return null;
if (testNode && this._getFilteredStatus(testNode) === this.NodeFilter.FILTER_ACCEPT)
break;
(testNode) && (this.currentNode = testNode);
return testNode;
;
TreeWalker.prototype.previousNode = function ()
var testNode = this.currentNode;
while (testNode)
if (testNode.previousSibling)
testNode = testNode.previousSibling;
while (testNode.lastChild)
testNode = testNode.lastChild;
else
if (testNode.parentNode && testNode.parentNode !== this.root)
testNode = testNode.parentNode;
else testNode = null;
if (testNode && this._getFilteredStatus(testNode) === this.NodeFilter.FILTER_ACCEPT)
break;
(testNode) && (this.currentNode = testNode);
return testNode;
;
TreeWalker.prototype.nextSibling = function ()
var testNode = this.currentNode;
while(testNode)
(testNode.nextSibling) && (testNode = testNode.nextSibling);
if(this._getFilteredStatus(testNode) === this.NodeFilter.FILTER_ACCEPT)
break;
(testNode) && (this.currentNode = testNode);
return testNode;
;
TreeWalker.prototype.previousSibling = function ()
var testNode = this.currentNode;
while(testNode)
(testNode.previousSibling) && (testNode = testNode.previousSibling);
if(this._getFilteredStatus(testNode) == this.NodeFilter.FILTER_ACCEPT)
break;
(testNode) && (this.currentNode = testNode);
return testNode;
;
TreeWalker.prototype._getFilteredStatus = function (node)
var mask = (
/* ELEMENT_NODE */ 1: this.NodeFilter.SHOW_ELEMENT,
/* ATTRIBUTE_NODE */ 2: this.NodeFilter.SHOW_ATTRIBUTE,
/* TEXT_NODE */ 3: this.NodeFilter.SHOW_TEXT,
/* CDATA_SECTION_NODE */ 4: this.NodeFilter.SHOW_CDATA_SECTION,
/* ENTITY_REFERENCE_NODE */ 5: this.NodeFilter.SHOW_ENTITY_REFERENCE,
/* ENTITY_NODE */ 6: this.NodeFilter.SHOW_PROCESSING_INSTRUCTION,
/* PROCESSING_INSTRUCTION_NODE */ 7: this.NodeFilter.SHOW_PROCESSING_INSTRUCTION,
/* COMMENT_NODE */ 8: this.NodeFilter.SHOW_COMMENT,
/* DOCUMENT_NODE */ 9: this.NodeFilter.SHOW_DOCUMENT,
/* DOCUMENT_TYPE_NODE */ 10: this.NodeFilter.SHOW_DOCUMENT_TYPE,
/* DOCUMENT_FRAGMENT_NODE */ 11: this.NodeFilter.SHOW_DOCUMENT_FRAGMENT,
/* NOTATION_NODE */ 12: this.NodeFilter.SHOW_NOTATION
)[node.nodeType];
return (
(mask && (this.whatToShow & mask) == 0) ?
this.NodeFilter.FILTER_REJECT :
(this.filter && this.filter.acceptNode) ?
this.filter.acceptNode(node) :
this.NodeFilter.FILTER_ACCEPT
);
;
if (!document.createTreeWalker)
document.createTreeWalker = function (root, whatToShow, filter, expandEntityReferences)
return new TreeWalker(root, whatToShow, filter, expandEntityReferences);
;
window.onload = function ()
var walker = document.createTreeWalker(document.getElementById('rootNodeDiv'), NodeFilter.SHOW_ELEMENT, null, false);
alert('currentNode: ' + walker.currentNode.id + ': firstChild: ' + walker.firstChild().id);
alert('currentNode: ' + walker.currentNode.id + ': nextNode: ' + walker.nextNode().id);
alert('currentNode: ' + walker.currentNode.id + ': lastChild: ' + walker.lastChild().id);
alert('currentNode: ' + walker.currentNode.id + ': parentNode: ' + walker.parentNode().id);
alert('currentNode: ' + walker.currentNode.id + ': previousNode: ' + walker.previousNode().id);
alert('currentNode: ' + walker.currentNode.id + ': nextSibling: ' + walker.nextSibling().id);
alert('currentNode: ' + walker.currentNode.id + ': previousSibling: ' + walker.previousSibling().id);
;
</script>
<div id="parentNodeDiv">
<div id="rootNodeDiv">
<span id="previousNodeDiv"></span>
<span id="span01">
<p id="span01p01"> </p>
<p id="span01p02"> </p>
</span>
<span id="span02"></span>
<span id="span03">
<p id="span02p01"> </p>
</span>
<span id="span04"></span>
<span id="span05"></span>
</div>
</div>
</body>
【讨论】:
以上是关于jQuery 到常规 Javascript 的映射的主要内容,如果未能解决你的问题,请参考以下文章
如何将 jQuery each() 变成常规的 javascript 循环