Get current word on caret position

2020-07-13 09:16发布

问题:

How can I get a word in textarrea by its current caret position?

I tried something like this, however this returns just the words first letter upto the character at caret position. For example:

if the cursor is between fo and o it returns fo and not foo as excpected.

Fo|o bar is not equal to bar foo. => Fo expects Foo

Foo bar is not equ|al to bar foo. => equ expects equal.

Here's what I've done so far:

function getCaretPosition(ctrl) {
    var start, end;
    if (ctrl.setSelectionRange) {
        start = ctrl.selectionStart;
        end = ctrl.selectionEnd;
    } else if (document.selection && document.selection.createRange) {
        var range = document.selection.createRange();
        start = 0 - range.duplicate().moveStart('character', -100000);
        end = start + range.text.length;
    }
    return {
        start: start,
        end: end
    }
}

$("textarea").keyup(function () {
    var caret = getCaretPosition(this);

    var result = /\S+$/.exec(this.value.slice(0, caret.end));
    var lastWord = result ? result[0] : null;
    alert(lastWord);
});

http://fiddle.jshell.net/gANLv/

回答1:

Try change this line in your code to this:

 var result = /\S+$/.exec(this.value.slice(0, this.value.indexOf(' ',caret.end)));


回答2:

Stumbled accross this looking for a vanilla JS answer and ended up writing one. Here is a relatively safe utility function that will work on all modern browsers (you can pass in any node or call it without any args to default to document.activeElement).

Note that this method can return undefined, zero, or N length whitespace strings:

  • given a selection like this " " a 2 length whitespace string would be returned
  • given no selection and no caret is on the page (i.e. a textarea is not focused) undefined would be returned
  • given a caret inside a textarea that is not at the start/end/within a word, a zero length string would be returned
  • given a caret inside a textarea that is at the start/end/within a word, that word (including punctuation and special chars) would be returned
// returns the current window selection if present, else the current node selection if start and end
// are not equal, otherwise returns the word that has the caret positioned at the start/end/within it
function getCurrentSelection (node = document.activeElement) {
  if (window.getSelection().toString().length > 0) {
    return window.getSelection().toString()
  }

  if (node && node.selectionStart !== node.selectionEnd) {
    return node.value.slice(node.selectionStart, node.selectionEnd)
  }

  if (node && node.selectionStart >= 0) {
    const boundaries = {
      start: node.selectionStart,
      end: node.selectionStart
    }
    const range = document.createRange()
    range.selectNode(node)
    const text = range.cloneContents().textContent
    if (text) {
      let i = 0
      while (i < 1) {
        const start = boundaries.start
        const end = boundaries.end
        const prevChar = text.charAt(start - 1)
        const currentChar = text.charAt(end)

        if (!prevChar.match(/\s/g) && prevChar.length > 0) {
          boundaries.start--
        }

        if (!currentChar.match(/\s/g) && currentChar.length > 0) {
          boundaries.end++
        }

        // if we haven't moved either boundary, we have our word
        if (start === boundaries.start && end === boundaries.end) {
          console.log('found!')
          i = 1
        }
      }
      return text.slice(boundaries.start, boundaries.end)
    }
  }
}