是否有一些代码可用于通过其父对象和文本索引来定位元素及其偏移量?

发布于 2024-08-18 11:45:21 字数 429 浏览 1 评论 0原文

我的意思是,以下面的 HTML 代码为例,忽略空格。

<p>
  paragraph-text
  <span>
   span text
   <i>it</i>
  </span>
</p>

我在 pNode.innerHTML 内有 pNode 对象和“span text”中的“a”索引,这里是 23,因为 pNode.innerHTML="paragraph-textspan textit”,开放跨度标签也应该被计算在内。

是否有一些现有的库可以像transform(pElement, 23)一样使用,以便我可以获得“spanElement and 2”的预期元素和偏移量?

提前致谢。 问候,

史蒂夫

I mean, take the following HTML codes as example, ignore the whitespaces.

<p>
  paragraph-text
  <span>
   span text
   <i>it</i>
  </span>
</p>

I have the pNode object and the index of "a" in "span text" within pNode.innerHTML as a whole, that is 23 here since pNode.innerHTML="paragraph-text<span>span text<i>it</i></span>", the open span tag should also be counted.

Is there some existing library that can be used like transform(pElement, 23), so that I can get the expected element and offset of "spanElement and 2"?

Thanks in adavance.
Regards,

Steve

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏日落 2024-08-25 11:45:21

您也许可以通过获取 innerHTML 来实现这一点,更改您要查找的偏移量的字符,然后重新解析和比较生成的文本节点以找到更改的 数据所在的节点结束了。

例如。

function findTextFromMarkupIndex(el1, ix) {
    // make comparison element
    var el2= document.createElement(el1.tagName);
    // replace any other use of * in its HTML out of the way
    var html= el1.innerHTML.split('*').join('x');
    // insert a * at the given index in HTML
    el2.innerHTML= html.substring(0, ix)+'*'+html.substring(ix);
    // search the resulting DOM for the * and return the matching descandent from the original
    return findTextInComparison(el1, el2, '*');
}

function findTextInComparison(el1, el2, text) {
    for (var i= 0; i<el1.childNodes.length; i++) {
        var child1= el1.childNodes[i];
        var child2= el2.childNodes[i];
        if (child2.nodeType===3) { // TEXT_NODE
            var ix= child2.data.indexOf(text);
            if (ix!==-1)
                return [child1, ix];
        } else if (child2.nodeType===1) { // ELEMENT_NODE
            var result= findTextInComparison(child1, child2, text);
            if (result!==null)
                return result;
        }
    }
    return null;
}

未经测试,但对于文本内容中的字符应该可以工作。如果需要,您可以将其扩展为查看属性值内部,但不能在标记内执行索引点,例如元素或实体/字符引用。为此,您基本上需要编写一个完整的 HTML 解析器。

这听起来像是一个不寻常的要求,你到底想做什么? innerHTML 中的索引可能非常脆弱,因为该属性的标记输出的确切格式根本没有标准化。

You could perhaps do it by getting the innerHTML, changing the character whose offset you're looking for, and then re-parsing and diffing the resulting text nodes to find the one where the changed data ended up.

eg.

function findTextFromMarkupIndex(el1, ix) {
    // make comparison element
    var el2= document.createElement(el1.tagName);
    // replace any other use of * in its HTML out of the way
    var html= el1.innerHTML.split('*').join('x');
    // insert a * at the given index in HTML
    el2.innerHTML= html.substring(0, ix)+'*'+html.substring(ix);
    // search the resulting DOM for the * and return the matching descandent from the original
    return findTextInComparison(el1, el2, '*');
}

function findTextInComparison(el1, el2, text) {
    for (var i= 0; i<el1.childNodes.length; i++) {
        var child1= el1.childNodes[i];
        var child2= el2.childNodes[i];
        if (child2.nodeType===3) { // TEXT_NODE
            var ix= child2.data.indexOf(text);
            if (ix!==-1)
                return [child1, ix];
        } else if (child2.nodeType===1) { // ELEMENT_NODE
            var result= findTextInComparison(child1, child2, text);
            if (result!==null)
                return result;
        }
    }
    return null;
}

Untested but should work, for characters in text content anyway. You could extend it to also look inside attribute values if you needed to, but you couldn't do index points inside markup such as an element or entity/character reference. For that to work, you'd essentially need to write an entire HTML parser.

This sounds like an unusual requirement, what exactly are you trying to do? Indexes within innerHTML can be quite fragile as the exact format of markup output for this property is not at all standardised.

一萌ing 2024-08-25 11:45:21

你所说的听起来像是 DOM Range ,在除 Internet Explorer 之外的所有主要浏览器中均实现。根据 HTML 中的字符偏移量指定位置并不是一个好主意,因为 innerHTML 的实现差异很大。 DOM Range 有一个开始和结束边界,每个边界都是根据节点和该节点内的偏移量指定的。在您的示例中,您可以创建一个表示位置的 Range:

var span = pNode.childNodes[1];
var spanText = span.firstChild;
var range = document.createRange();

// Next line takes into account whitespace at the start of the text node
range.setStart(spanText, 6); 

// For illustration, create a range that contains the letter "a" and selects it
range.setEnd(spanText, 7);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

一旦拥有 Range,您就可以将其用于各种用途,例如插入节点、定义用户选择以及将格式应用于 Range 封装的内容。

IE 定义了一个完全不同的对象,称为 TextRange 它具有根本不同的基于文本的方法,但具有大致相同的目的。要获得与上一个示例等效的 TextRange,您可以使用以下命令:

var textRange = document.body.createTextRange();
textRange.moveToElementText(pNode);
textRange.moveStart("character", 17);
textRange.collapse();

// For illustration, create a range that contains the letter "a" and selects it
textRange.moveEnd("character", 1);
textRange.select();

What you're talking about sounds something like a DOM Range, which is implemented in all the major browsers except Internet Explorer. Specifying a location in terms of character offsets within HTML is not a good idea, since implementations of innerHTML vary significantly. A DOM Range has a start and end boundary, each of which is specified in terms of a node and an offset within that node. In the case of your example, you could create a Range that represented the location:

var span = pNode.childNodes[1];
var spanText = span.firstChild;
var range = document.createRange();

// Next line takes into account whitespace at the start of the text node
range.setStart(spanText, 6); 

// For illustration, create a range that contains the letter "a" and selects it
range.setEnd(spanText, 7);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

Once you have a Range, you can use it for various things, such as inserting nodes, defining user selections and applying formatting to the content encapsulated by the Range.

IE defines an entirely different object called a TextRange that has a fundamentally different text-based approach but serves much the same purpose. To get the equivalent TextRange to the previous example, you could use the following:

var textRange = document.body.createTextRange();
textRange.moveToElementText(pNode);
textRange.moveStart("character", 17);
textRange.collapse();

// For illustration, create a range that contains the letter "a" and selects it
textRange.moveEnd("character", 1);
textRange.select();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文