我有一个iframe,点击它的任何内容,就会在其上应用css类(比如说“selected”)。之后
单击下一个按钮时,它应该在包含文本的下一个元素上应用此类
并返回文字。遍历应该是基于文本节点的。虽然我确实尝试过做一些非常丑陋的事情,但我想必须有一些简单的解决方案。
这是我的代码:
$(function(){
$('#next').click(function(){
var current_segment =$('#my_iframe').contents().find(".highlight");
// if current segment has children
if($(current_segment).children().not('.traversed_already').length > 0){
$(current_segment).children().not('.traversed_already').first().addClass('highlight');
$(current_segment).removeClass('highlight');
// add class to stop repitative traversing
$(current_segment).addClass('traversed_already');
// return false;
// if has siblings and no children
}else if($(current_segment).siblings().not('.traversed_already').length > 0
&& $(current_segment).children().not('.traversed_already').length <= 0){
$(current_segment).siblings().not('.traversed_already').first().addClass('highlight');
$(current_segment).removeClass('highlight');
// add class to stop repitative traversing
$(current_segment).addClass('traversed_already');
// return false;
// if no siblings and no children
}else if($(current_segment).siblings().not('.traversed_already').length == 0 &&
$(current_segment).children().not('.traversed_already').length == 0){
// check the very first parent if traversed check its siblings
var parent_segment = $(current_segment).parent().first();
// if parent is already traversed already
if($(parent_segment).hasClass('traversed_already')){
// if parent is traversed but parent has sibling that is untraversed
if($(parent_segment).siblings().not('.traversed_already').length > 0){
$(parent_segment).siblings().not('.traversed_already').first().addClass('highlight');
$(parent_segment).removeClass('highlight');
// add class to stop repitative traversing
$(parent_segment).addClass('traversed_already');
// return false;
// if no untraversed sibling then search for parent(s)
}else{
// Look for the parent in Dom tree which is not traversed
$(parent_segment).parents().not('.traversed_already').first().addClass('highlight');
$(parent_segment).removeClass('highlight');
// add class to stop repitative traversing
$(parent_segment).addClass('traversed_already');
// return false;
} // end of if traversed parent has siblings(untraversed).
// if parent is not traversed
} else {
$(parent_segment).addClass('highlight');
$(current_segment).removeClass('highlight');
// add class to stop repitative traversing
$(current_segment).addClass('traversed_already');
} // end of if parent is already traversed or not
// return false;
} // end of else if no siblings and no parents
本准则的问题是:
它只是通过首先看到孩子,然后是兄弟姐妹,然后是父母的兄弟姐妹来遍历下一个元素,但是当父母来到时,它会失败&gt;父母&gt;父母的兄弟姐妹。
注意:我相信这可以通过DOM遍历很容易完成,但我无法找到正确的解决方案。
答案 0 :(得分:2)
这是一个最小的DOM遍历脚本。我不知道它是最好的,还是最小的,但我很确定它是有效的(只有浏览器测试,但看起来很稳固)。
getNextElement = function(element, goingUp) {
if (element.firstChild && !goingUp){
return element.firstChild;
}
else if (element.nextSibling){
return element.nextSibling;
}
else if (element.parentNode) {
return arguments.callee(element.parentNode, true);
}
};
这实际上会击中文本节点以及其他节点。我想你实际上可以利用它。但是,如果您只想要元素,只需将firstChild
更改为firstElementChild
,将nextSibling
更改为nextElementSibling
。虽然IE8或更低版本不支持。
通过运行element = getNextElement(document.getElementsByTagName('body')[0])
然后运行
if (element.style){element.style.backgroundColor = 'yellow'};
element = getNextElement(element);
反复走路(并突出显示)DOM。
答案 1 :(得分:2)
最简单的解决方案是 DOM TreeWalker ,我很幸运,我花了太长时间才弄明白。
Here是指向它的链接。希望它能帮助遇到同样问题的人,而不是花费数小时或数天来帮助他们。
答案 2 :(得分:1)
我不确定iframe的标记有多复杂,所以我正在使用一些我自己很快创建的。
首先,单击一个元素以记下您的起始位置 - 该元素将突出显示 - 然后单击“下一步”按钮,代码将突出显示它找到的下一个元素。一旦突出显示所有元素,就不会再发生任何事情。取决于元素的嵌套程度取决于代码是否会看到元素并突出显示它。所有已发现的内容都将在控制台窗口中显示,并且会显示“已选择”类。
我知道您要求基于文本节点的解决方案,但我认为这可行。试试看,无论如何。
Iframe.html的:
<html>
<head>
<title>iFrame</title>
</head>
<body>
<ul>
<li><abbr title="Cascading Style Sheets">CSS</abbr> (an abbreviation; <code>abbr</code> markup used)</li>
<li><acronym title="radio detecting and ranging">radar</acronym> (an acronym; <code>acronym</code> markup used)</li>
<li><b>bolded</b> (<code>b</code> markup used - just bolding with unspecified semantics)</li>
<li><big>big thing</big> (<code>big</code> markup used)</li>
<li><cite>Origin of Species</cite> (a book title; <code>cite</code> markup used)</li>
<li><code>a[i] = b[i] + c[i);</code> (computer code; <code>code</code> markup used)</li>
<li>here we have some <del>deleted</del> text (<code>del</code> markup used)</li>
<li>an <dfn>octet</dfn> is an entity consisting of eight bits (<code>dfn</code> markup used for the term being defined)</li>
<li>this is <em>very</em> simple (<code>em</code> markup used for emphasizing a word)</li>
<li><i lang="la">Homo sapiens</i> (should appear in italics; <code>i</code> markup used)</li>
<li>here we have some <ins>inserted</ins> text (<code>ins</code> markup used)</li>
<li><q>Hello!</q> (<code>q</code> markup used for quotation)</li>
<li>He said: <q>She said <q>Hello!</q></q> (a quotation inside a quotation)</li>
<li><small>this is not that important</small> (<code>small</code> markup used)</li>
<li><strike>overstruck</strike> (<code>strike</code> markup used; note: <code>s</code> is a nonstandard synonym for <code>strike</code>)</li>
<li><strong>this is highlighted text</strong> (<code>strong</code> markup used)</li>
<li>In order to test how subscripts and superscripts (<code>sub</code> and <code>sup</code> markup) work inside running text, we need some dummy text around constructs like x<sub>1</sub> and H<sub>2</sub>O (where subscripts occur). So here is some fill so that you will (hopefully) see whether and how badly the subscripts and superscripts mess up vertical spacing between lines. Now superscripts: M<sup>lle</sup>, 1<sup>st</sup>, and then some mathematical notations: e<sup>x</sup>, sin<sup>2</sup><i>x</i>, and some nested superscripts (exponents) too: e<sup>x<sup>2</sup></sup> and f(x)<sup>g(x)<sup>a+b+c</sup></sup> (where 2 and a+b+c should appear as exponents of exponents).</li>
<li><u>underlined</u> text (<code>u</code> markup used)</li>
<li>the command <code>cat</code><var>filename</var> displays the file specified by the <var>filename</var> (<code>var</code> markup used to indicate a word as a variable).</li>
</ul>
</body>
</html>
demo.html:
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script><script type="text/javascript">
$(document).ready(function(){
$('#iframe').load(function(){
$all = $('#iframe').contents().find('body *').filter(function(){
var $this = $(this);
return $this.children().length == 0 && $.trim($this.text()).length > 0;
});
$('#next').on('click', highlightTextNode);
$('#iframe').contents().find('body').on('click', highlightTextNode);
});
var highlightTextNode = function(event){
event.stopPropagation();
$el = $(event.target).children().length == 0 ? $(event.target) : $(event.target).find(':first-child').first();
if(!$el.hasClass('selected') && $.trim($el.text()).length > 0 && $('#iframe').contents().find('body').find('.selected').length == 0){
$el.addClass('selected').css({backgroundColor: 'yellow'});
console.log($.trim($el.text()));
} else {
var found = false;
var finished = false;
$all.each(function(){
finished = true;
if(found && !$(this).hasClass('selected')){
found = false;
$(this).addClass('selected').css({backgroundColor: 'yellow'});
console.log($.trim($(this).text()));
finished = false;
return false;
}
if($(this).hasClass('selected'))
found = true;
});
if(finished){ //start at the beginning again
$all.each(function(){
if(found && !$(this).hasClass('selected')){
found = false;
$(this).addClass('selected').css({backgroundColor: 'yellow'});
console.log($.trim($(this).text()));
return false;
}
if($(this).hasClass('selected'))
found = true;
});
}
}
}
});
</script>
</head>
<body>
<input type="button" value="NEXT" id="next" />
<iframe id="iframe" src="iframe.html" width="100%" height="100%"></iframe>
</body>
</html>
答案 3 :(得分:0)
为什么不使用像
这样的while
函数
$(function(){
$('#next').click(function(){
var current_segment =$('#my_iframe').contents().find(".highlight");
var doWhile = true; // variable that will determine that You have to go again trough the loop
while (doWhile){
... // Your code
// Every time where You put
// add class to stop repitative traversing
$(element).addClass('traversed_already');
// give also
doWhile = false; // to stop while function
// of course return will take You out as well
}
它应该有用。
答案 4 :(得分:0)
以下解决方案应符合您的目标。
注意:
<div id="a">1<div id="b">2</div>3</div>
,它会选择1
然后2
然后选择3
而不是a
然后b
。我相信这就是你所要求的,但并非100%明确。代码:
// First grab the iframe's document object.
var iframeDocument = document.querySelector('iframe').contentDocument;
// Then generate the list of all text nodes in the iframe.
var textNodes = [];
function findTextNodes(curElem){
Array.prototype.slice.apply(curElem.childNodes).forEach(function(childNode) {
switch (childNode.nodeType) {
case Node.TEXT_NODE:
textNodes.push(childNode);
case Node.ELEMENT_NODE:
findTextNodes(childNode);
}
}, this);
}
findTextNodes(iframeDocument.body);
// Helper function to move the text node selection.
function selectTextNodeAtIndex(index){
if (index > 0) {
// Replace the old .selected wrapper with the original text node.
var oldWrapperElem = iframeDocument.querySelector('.selected');
oldWrapperElem.parentNode.replaceChild(textNodes[index - 1], oldWrapperElem);
}
// Replace the current text node with a .selected wrapper.
var wrapperElem = iframeDocument.createElement('span');
wrapperElem.classList.add('selected');
wrapperElem.textContent = textNodes[index].textContent;
textNodes[index].parentNode.replaceChild(wrapperElem, textNodes[index]);
}
// Finally, select the first text node and set up the click handler.
var curIndex = 0;
selectTextNodeAtIndex(curIndex);
document.querySelector('#next').addEventListener('click', function () {
curIndex++;
selectTextNodeAtIndex(curIndex);
}, true);