首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >textRange MoveToPoint() IE

textRange MoveToPoint() IE
EN

Stack Overflow用户
提问于 2016-07-26 12:08:30
回答 3查看 509关注 0票数 2

moveToPoint()方法textRange IE11有问题;

似乎它不工作,如果点节点不在第一个屏幕;

代码语言:javascript
复制
document.addEventListener( "click", function(e) {
	var x = e.clientX; 
	var y = e.clientY; 
	var range = document.body.createTextRange();
	range.moveToPoint(x, y);
	range.expand('word');
	console.log(range);
	console.log(range.text);
});

这段代码从点击点抓取单词,但只有在第一个滚动点的节点上单击时,它才会正常运行。

如果我们向下滚动一点到第一个滚动中没有的节点,我们就会捕捉到exeception。

有人知道如何正确处理这种情况吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-07-27 20:22:18

受“dinalt”和“JAYBEkster”的启发,我想出了这个解决方案。也许最终会有人需要这个。

下面的代码(对于IE,没有检查所有的11+,但它工作得很好)在复杂嵌套的html中捕获单词。

一步一步如何工作:

  1. 首先,我们从e.target创建范围
  2. 我们把它弄得一塌糊涂。
  3. 如果我们能扩展(“word”)并迭代每个单词,那就太棒了,但不幸的是,我们不能。因此,我们循环字符分割成单词,并比较他们的边界与e.clientX,和Y,另一方面,通过迭代字符的词,我们得到更多的控制。
  4. 我们得到正确的一个,并与它分割target.innerText,得到节点文本的左和右部分。
  5. 在那之后,我们再次分割每个部分,但这是我们的分隔符(用所有空格和单词分隔符,我可以想象),我们得到两个arr。

我们为什么要做第4和第5步?因为我们在那个节点上找到了一些文字,但它可能不是这个词的结尾或开头,出于一些造型上的原因,它是这个词的一部分--我在它自己的节点上,而target.node我只是这个词的中间部分。所以我们必须跳过节点找到单词的结尾。

如果你确信你没有抱怨你可以跳过所有其他步骤。

  1. 然后,如果arr为空,则运行递归函数,该函数通过节点和抓取的文本运行,直到查找分隔符。

是的,这看起来真的很像,因为对于这样的,我们认为简单的任务。但实际上我找不到更好的解决方案,有几种选择,但它们都不是我所需要的那样普遍。

这段代码的好处在于它根本不关心html的复杂性。

我将在这里张贴到我的github网站的链接,在那里你可以找到完整的wordGraber代码,这将工作这个Chrome,Safari,FF和IE当然。

https://github.com/6graNik/wordGrabber

下面只是IE的一部分。

代码语言:javascript
复制
function getWordFromEventIE(e) {
  const x = e.clientX;
  const y = e.clientY;
  const innerText = e.target && e.target.innerText;
  const separators = /([\s&^:;,!?(){}])+/;
  const IErange = global.document.body.createTextRange();

  try {
    IErange.moveToElementText(e.target);
    IErange.collapse(true);

    let wholeSentenceLength = 0;
    const reqIEcharTest = () => {
      do {
        IErange.expand("character");
        wholeSentenceLength += 1;
      }
      while (!separators.test(IErange.text.slice(-1)) && wholeSentenceLength <= innerText.length);
      const {boundingLeft, boundingTop, boundingWidth, boundingHeight, text} = IErange;

      if (boundingLeft <= x && x <= (boundingLeft + boundingWidth)
       && boundingTop <= y && y <= (boundingTop + boundingHeight)) {
        if (wholeSentenceLength <= innerText.length && !separators.test(text.slice(-1)) ) {
          return text;
        }
        return text.substr(0, text.length - 1);
      }
      IErange.collapse(false);
      return reqIEcharTest();
    };
    const text = reqIEcharTest().trim();
    const innerTextArr = innerText.split(text);
    const innerTextLeft = innerTextArr[0].split(separators);
    const innerTextRight = innerTextArr[1].split(separators);

    let leftPart;
    if (innerTextLeft <= 1) {
      leftPart = recursionWordGet(e.target, 'left') + innerTextLeft.slice(-1)[0];
    } else {
      leftPart = innerTextLeft.slice(-1)[0];
    }
    let rightPart;
    if (innerTextRight <= 1) {
      rightPart = innerTextRight[0] + recursionWordGet(e.target, 'right');
    } else {
      rightPart = innerTextRight[0];
    }

    return leftPart + text + rightPart;
  } catch (err) {
    console.log('>>>>>>>>>>>>>>>>>> text', err);
  }
}


function recursionWordGet(target, option) {
  const separators = /([\s&^:;,!?(){}])+/;
  const uniqString = Date.now();

  target.setAttribute("data-target", uniqString);
  const {parentNode} = target;
  const copyNode = parentNode.cloneNode(true);

  copyNode.querySelector(`[data-target="${uniqString}"]`).innerText = uniqString;
  const tagName = copyNode.tagName;


  const text = copyNode.innerText;
  const textArr = text.split(uniqString);
  const textLeftPartArr = textArr[0].split(separators);
  const textRightPartArr = textArr[1].split(separators);

  if (option === 'right') {
    let returnText;
    if (textRightPartArr.length <= 1 && tagName === 'span') {
      returnText = textRightPartArr[0] + recursionWordGet(parentNode, 'right');
    } else {
      returnText = textRightPartArr[0];
    }
    return returnText;
  }

  if (option === 'left') {
    let returnText;
    if (textLeftPartArr <= 1 && tagName === 'span') {
      returnText = recursionWordGet(parentNode, 'left') + textLeftPartArr.slice(-1)[0];
    } else {
      returnText = textLeftPartArr.slice(-1)[0];
    }
    return returnText;
  }

  return '';
}

票数 0
EN

Stack Overflow用户

发布于 2016-07-26 14:59:41

您可以使用offsetX,offsetY属性。或者可以使用父元素的scrollLeft和scrollTop属性将滚动位置添加到x和y vars。

票数 0
EN

Stack Overflow用户

发布于 2016-07-27 11:01:51

我可以确认IE11中存在这样的bug。您可以在注释中找到详细信息:http://generatedcontent.org/post/69213745095/ie11review-part1

可能的解决方案(在创建范围之后):

代码语言:javascript
复制
range.moveToElementText(e.target);
range.collapse(true)
range.expand("word")

现在,您已经选择了第一个单词。现在您必须使用TextRange属性boundingHeight、boundingWidth、boundingLeft和boundingTop检查所选单词是否适合您的鼠标单击位置。如果没有,您可以循环到下一个单词:

代码语言:javascript
复制
range.collapse(false);
range.expand("word");
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38589496

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档