range.setStart只使用字符偏移?

时间:2014-12-01 11:30:39

标签: javascript html ios

我对Javascript很陌生,过去几天我一直在阅读文档,试图解决这个问题。我终于不得不求助于在这里炫耀我的无知。

我有一个整数,它是段落中字符的索引。我想找到这个角色的边界矩形。我一直试图通过制作一个包含该角色的范围来做到这一点。

所以我尝试过:

var range = document.createRange();
range.setStart (node, offsetInsideNode);

并且对于节点我尝试传入段落元素,而对于offsetInsideNode我传入了characterOffset整数。

但后来我发现:“如果节点元素可以有子节点,则offsetInsideNode参数指定节点元素的childNodes集合中子节点的位置,否则它指定文本内容中的字符位置节点元素。“

但我想只使用角色位置。我无法弄清楚如何做到这一点,因为它似乎只想使用子节点位置。我猜我错过了什么。

说我有一个段落:

<p xmlns="http://www.w3.org/1999/xhtml" class="s12" style="color: rgb(0, 0, 0);"><span class="mySpanClass">The</span> quick brown <b>fox</b> jumps over the lazy dog</p>

我想找到第n个角色的边界矩形,我该怎么做呢?我是在吠叫错误的树吗?我忽略了一种更为简单的方法吗?

感谢。

注释:

  • 仅限javascript
  • 没有图书馆
  • 没有jquery
  • 适用于iOS设备上的UIWebview

2 个答案:

答案 0 :(得分:2)

我希望这就是你要找的东西。此函数基本上获取您要在其中找到的元素的内容,将其拆分为字符,查找nth而不计算HTML标记,将nth包装在临时范围内并读取{{1}在用原始内容替换它之前和offsetTop。然后将偏移量x和y作为对象返回。

offsetLeft

像这样使用:

function nthCharOffset(nth, element){
    var orgContent = element.innerHTML;   // Save the original content.
    var arr = orgContent.split('');         // Split every character.

    // Few vars to control the upcoming loop
    var content = '';
    var tag = false;
    var count = 0;

    // Loop through every character creating a new string and wrapping the nth in a temporary span
    for (var i = 0; i < arr.length; i++) {

        // if inside tag, don't count this in the nth count
        if (arr[i] == '<') tag = true
        if (!tag) count++;
        if (arr[i] == '>') tag = false;

        // If this charactar is nth, wrap it in a temporary span
        if (nth == count) content += '<span id="offset-check">' + arr[i] + '</span>';
        else content += arr[i];
    }

    // Set the content with the temporary span.
    element.innerHTML = content;

    // Get the offset of the temporary span.
    var offsetCheck = document.getElementById('offset-check');
    var offset = {x: offsetCheck.offsetLeft , y: offsetCheck.offsetTop }

    // Remove the span.
    element.innerHTML = orgContent;

    // Return the result.
    return offset;
}

我做了一个小提琴,所以你可以测试它here

This fiddle使用该函数将红色矩形定位并缩放为nthCharOffset(10, document.getElementById('element')); 个字符。

答案 1 :(得分:1)

据我所知,你想要

  

仅限角色位置

以指定选择的范围,而不是某个节点偏移。我相信我遇到了同样的问题。可以通过寻址节点或字符来创建偏移量。 Range.setStart方法同时执行两项操作,这很痛苦,但文档会提供您必须执行的操作:

  

如果startNode是Text,Comment或CDATASection类型的节点,则startOffset是startNode开头的字符数。

请参阅:https://developer.mozilla.org/en-US/docs/Web/API/Range/setStart

因此,您可以通过寻址元素的文本节点来指定字符索引范围。这是我提出的(乐观)解决方案。

假设您有一个文档,并且您希望将粘性CSS样式的黄色高光添加到一段选定的文本中。在Javascript中,创建一个范围并选择该元素。添加范围,但首先选择textnode。然后,偏移将引用字符,而不是节点。

// Magic happens here
function getTextNodeFrom(element) {

  // replace with more sophisticated method
  return element.childNodes[0];

}

// Create the range as you normally would
function createRange(node, start, end) {
  var range = document.createRange();
  range.setStart(node, start);
  range.setEnd(node, end);
  return range;
}

// Give it a nice name 
function createRangeByCharacterOffset(element, start, end) {

  // Rather than passing the element directly to createRange,  
  // extract the node first.
  var textNode = getTextNodeFrom(element)
  var range = createRange(textNode, start, end);

  return range;
}

// To illustrate, let's surround the range with a highlighting span
function highlight () {
    var span = document.createElement('span');
    span.setAttribute('class', 'highlight');
    return span;
}

var p = document.getElementsByTagName('p')[0];

createRangeByCharacterOffset(p, 50, 200)
.surroundContents(highlight()); // This performs the actual highlight. 

首先,选择给定的p元素。然后,我们使用函数getTextNodeFrom(element)提取textNode。请注意,此功能非常乐观。它假定节点列表包含textNode作为第一个元素,但不一定是这种情况。您如何获得此节点取决于您,此处仅显示一个简单的方法。我会假设迭代列表并检查节点的Text或CDATA类型就足够了。

创建范围并设置开始和结束。当'node'对象是textNode时,偏移量对字符进行寻址。看看这个小提琴,看看它在行动。

例如,显示的代码采用所选范围并用样式化的span元素围绕它,以突出显示从字符50200的范围。

https://jsfiddle.net/cessor/t6sroob1/2/