【问题标题】:JavaScript window.find() does not select search termJavaScript window.find() 不选择搜索词
【发布时间】:2012-09-08 20:41:01
【问题描述】:

当我尝试传递分布在几个块元素中的文本时,window.find 方法不起作用:

HTML

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
</head>
<body>
  <p>search me</p><b> I could be the answer</b>
</body>
</html>

JavaScript

window.find("meI could be");

或者:

str = "me";
str+= "\n";
str+="I could be t";

window.find(str);

&lt;p&gt; 元素出现在搜索词之间时会发生这种情况。
最终结果应该是页面中文本的 GUI 选择,如果存在,我不想搜索。

我想知道如何在 Firefox(至少)和 Internet Explorer 中实现这一点。
注意:我无法更改 dom(例如更改为内联显示)。

编辑:
这是我在@Alexey Lebedev 发表评论后尝试过的,但它也找到了脚本(标记 [...] 文本):

我可以让它更简单吗? (更好)?

function nativeTreeWalker(startNode) {
    var walker = document.createTreeWalker(
        startNode, 
        NodeFilter.SHOW_TEXT, 
        null, 
        false
    );
    var node;
    var textNodesV = [];
    var textNodes = [];
    node = walker.nextNode();

    while(node ) {
      if(node.nodeValue.trim()){
        textNodes.push(node);
        textNodesV.push(node.nodeValue);
        //console.log(node.nodeValue);
      }
        node = walker.nextNode();
    }
  return [textNodes,textNodesV];
}

var result = nativeTreeWalker(document.body);
var textNodes = result[0];
var textNodesV = result[1];

var param = " Praragraph.Test 3 Praragr";
paramArr = param.split(/(?=[\S])(?!\s)(?=[\W])(?=[\S])/g);
//Fix split PARAM
for(i=0;i<paramArr.length-1;i++){
  paramArr[i]= paramArr[i]+paramArr[i+1].charAt(0);
  paramArr[i+1] = paramArr[i+1].substring(1,paramArr[i+1].length);
}
//Fix last element PARAM
if(paramArr[paramArr.length-1] === ""){
  paramArr.splice(paramArr.length-1,1);
}
//console.log(paramArr);
var startNode,startOffset,sFound=false,
    endNode,endOffset;
for(i=0;i<paramArr.length;i++){
  for(j=0;j<textNodesV.length;j++){
    //Fully Equal
    var pos = textNodesV[j].indexOf(paramArr[i]);
    if(pos != -1){
      if(!sFound){
        startNode = textNodes[j];
        startOffset = pos;
        sFound=true;
      }else{
        endNode = textNodes[j];
        endOffset = pos+paramArr[i].length;
        break;
      }
    }
  }
}
console.log(startNode);
console.log(startOffset);
console.log(endNode);
console.log(endOffset);

var range = document.createRange();
range.setStart(startNode,startOffset);
range.setEnd(endNode,endOffset);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

注意:没有 jQuery(只有 Raw JS)。

【问题讨论】:

  • 如果你不能改变 DOM,你需要使用 window.find() 以外的东西。选择所有文本节点,使用正则表达式查找文本,并使用选择范围突出显示它。
  • @AlexeyLebedev,我添加了一些代码。

标签: javascript find


【解决方案1】:

JS Bin 演示:http://jsbin.com/aqiciv/1/

如果您希望它在 IE

function visibleTextNodes() {
    var walker = document.createTreeWalker(
        document.body,
        NodeFilter.SHOW_ALL,
        function(node) {
            if (node.nodeType == 3) {
                return NodeFilter.FILTER_ACCEPT;
            } else if (node.offsetWidth && node.offsetHeight && node.style.visibility != 'hidden') {
                return NodeFilter.FILTER_SKIP;
            } else {
                return NodeFilter.FILTER_REJECT;
            }
        },
        false
    );

    for (var nodes = []; walker.nextNode();) {
        nodes.push(walker.currentNode);
    }
    return nodes;
}

// Find the first match, select and scroll to it.
// Case- and whitespace- insensitive.
// For better scrolling to selection see https://gist.github.com/3744577
function highlight(needle) {
    needle = needle.replace(/\s/g, '').toLowerCase();

    var textNodes = visibleTextNodes();

    for (var i = 0, texts = []; i < textNodes.length; i++) {
        texts.push(textNodes[i].nodeValue.replace(/\s/g, '').toLowerCase());
    }

    var matchStart = texts.join('').indexOf(needle);
    if (matchStart < 0) {
        return false;
    }

    var nodeAndOffsetAtPosition = function(position) {
        for (var i = 0, consumed = 0; consumed + texts[i].length < position; i++) {
            consumed += texts[i].length;
        }
        var whitespacePrefix = textNodes[i].nodeValue.match(/^\s*/)[0];
        return [textNodes[i], position - consumed + whitespacePrefix.length];
    };

    var range = document.createRange();
    range.setStart.apply(range, nodeAndOffsetAtPosition(matchStart));
    range.setEnd.apply(  range, nodeAndOffsetAtPosition(matchStart + needle.length));
    window.getSelection().removeAllRanges();
    window.getSelection().addRange(range);
    range.startContainer.parentNode.scrollIntoView();
}

highlight('hello world');

【讨论】:

  • 抱歉通知晚了,但我更喜欢“原始” js 版本...(这就是为什么我的版本只有 js)。
  • @agam360,jQuery 文本节点检索有问题,嵌套节点的返回顺序可能与它们在文档中出现的顺序不同。我删除了 jQuery 依赖项并改用了 tree walker,它与嵌套节点一起正常工作。
  • 您能告诉我您在我提供的代码中看到的任何问题吗?
  • @agam360:我不完全理解它是如何工作的,尤其是 paramArr,但有几件事: 1. 脚本标签,很明显。 2. DOM 异常,如果您正在寻找单个单词 3. 区分大小写和空格。 4. 不像 window.find() 不会滚动到选择。 5. 不需要术语相邻,或者根本不需要在文档中。例如,如果“hello.world”以“hello”开头,它将匹配整个文档。并以“单词”结尾。而“one.two.three”将匹配“one.anything.three”。
  • 我接受了这个想法并尝试实现对 window.find 的完全替代。具体来说,这个想法是从当前选择开始搜索,这样我们每次搜索时都会找到下一个匹配项。不幸的是,选择有时会卡在不可见的区域中,例如在正文内容末尾的最后一个结束标记之后的空格中。知道如何检测吗?这是代码:github.com/drizzd/htmlsearch
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
  • 2013-09-17
  • 1970-01-01
  • 2011-03-15
  • 1970-01-01
  • 2019-10-14
  • 1970-01-01
相关资源
最近更新 更多