获取具有表情符号并插入标签的文本中的光标位置

时间:2020-08-07 18:07:03

标签: javascript jquery-plugins emoji

伙计们,你好吗?我在保存光标位置和插入动态标签时遇到麻烦。我使用Emojiarea插件创建了一个div,可以在其中编写文本,插入表情符号,模板和标签。 https://github.com/mervick/emojionearea

我使用以下功能在我的文本区域上创建一个div:

$("#email_campaign_description").emojioneArea({
    search: false,
    recentEmojis: false,
    pickerPosition: "right",
    events: {
      blur: function (editor, event) {
        $scope.lastPosition = getCaretCharacterOffsetWithin(editor[0])
      },
    }
  });

当我单击时,下一个函数返回光标的最后位置 文本中的某处:

function getCaretCharacterOffsetWithin(element) {
    var caretOffset = 0;
    var doc = element.ownerDocument;
    var win = doc.defaultView;
    var sel;
    if (typeof win.getSelection != "undefined") {
      sel = win.getSelection();
      if (sel.rangeCount > 0) {
        var range = win.getSelection().getRangeAt(0);
        var preCaretRange = range.cloneRange();
        preCaretRange.selectNodeContents(element);
        preCaretRange.setEnd(range.endContainer, range.endOffset);
        caretOffset = preCaretRange.toString().length;
      }
    } else if ( (sel = doc.selection) && sel.type != "Control") {
      var textRange = sel.createRange();
      var preCaretTextRange = doc.body.createTextRange();
      preCaretTextRange.moveToElementText(element);
      preCaretTextRange.setEndPoint("EndToEnd", textRange);
      caretOffset = preCaretTextRange.text.length;
    }
    debugger
    return caretOffset;
  }

最后一个函数将动态标签添加到文本:

$scope.chooseTag = function (label) {
    var domElement = $('#email_campaign_description');
    var emojiElement = domElement[0].emojioneArea;

    if (document.selection) {
      domElement.focus();
      var sel = document.selection.createRange();
      sel.text = $scope.tags.model;
      domElement.focus();
    } else if ($scope.lastPosition) {
      var startPos = $scope.lastPosition;
      var endPos = startPos + $scope.tags.model[0].length;
      emojiElement.setText(emojiElement.getText().substring(0, startPos) + ' ' + $scope.tags.model + ' ' + emojiElement.getText().substring(endPos, emojiElement.getText().length));
      domElement.focus();
    } else {
      emojiElement.setText($scope.tags.model);
      domElement.focus();
    }

    if ($scope.tags.model === '[vendor_name]') {
      emojiElement.setText(domElement.val().replace('[vendor_name]', $scope.vendor.name));
    }

    $scope.campaign.description = $('#email_campaign_description').val();
  };

会发生问题,即在文本中存储点击位置的函数无法读取表情符号。因此,如果我写这样的文字:“你好,[表情符号],欢迎光临!”在该文本的结尾,我尝试添加标签,我的函数将不会读取表情符号,而是将标签插入句子的最后一个字符(本例中为“!”)。同样,如果我添加两个表情符号,则在这种情况下,“ o!”将不会读取并在最后两个字符上插入标签。正确的方法是读取这两个表情符号并将我的标签准确地添加到所需位置的功能,即:“你好[表情符号],欢迎使用[标签]”

function getCaretCharacterOffsetWithin(element)可以读取表情符号作为字符或占用的空间怎么办?

1 个答案:

答案 0 :(得分:1)

问题在于javascript不能很好地处理Unicode字符串。

例如:

"hello".length === 5

"??‍?".length === 7

有几个库可以帮助准确测量unicode字符串的长度。 Graphemer是其中之一(完整披露:我已发布此库)。

要修复您的getCaretCharacterOffsetWithin(element)函数,请执行以下操作:

  1. 导入并实例化Graphemer库。
import Graphemer from 'graphemer';

const splitter = new Graphemer();

function getCaretCharacterOffsetWithin(element) {...}
  1. 更新第一个计算字符串长度的实例。
caretOffset = preCaretRange.toString().length; // original

caretOffset = splitter.countGraphemes(preCaretRange.toString()); // updated
  1. 更新第二个计算字符串长度的实例。
caretOffset = preCaretTextRange.text.length; // original

caretOffset = splitter.countGraphemes(preCaretTextRange.text); // updated