怎样获得一个textarea输入框中光标的位置

注意我要说的是position而不是index,其实我要做的是这样的效果

测试效果

让我知道当前光标的位置,我好做autocomplete下拉框的跟随

阅读 21.9k
6 个回答

可以考虑使用 Range,但是由于存在兼容性问题,也比较麻烦。

新浪的做法挺简单的。

用 css 控制,做一个和 textarea 一样样式的 div,放在一个不可见的地方。绑定事件保证 div 里面的内容和 textarea 一致。

如果输入的是 @ 或者其他需要关注的字符,就在 div 里面的 @ 外层用 包裹一下 <span>@</span>

这个时候,我们就可以用传统的方法获取 @ 相对 div 左上角的 xy 座标了。根据 xy 座标,就能确定弹出层相对 textarea 的位置了。

----- update -----

做了一个 demo,大致实现了一下效果。各种 bug 和错误都没处理(比如空格的处理,比如多个 @ 的情况)。输入 @ 的时候,弹出层会跟着。

仅供参考

http://jsfiddle.net/vDQnj/

如果你只是想获得输入框中光标的 offset 的话, 你可以用从 At.js 剥离出来的 jQuery 插件: Caret.js.

从别处搜索到的东西,希望能对你有帮助。目前也正在使用中~

//获取选择域位置,如果未选择便是光标位置
function getSelection(el) {
    return (
    ('selectionStart' in el && function () {
        var l = el.selectionEnd - el.selectionStart;
        return {
            start: el.selectionStart,
            end: el.selectionEnd,
            length: l,
            text: el.value.substr(el.selectionStart, l)
        };
    }) ||

    (document.selection && function () {

        el.focus();

        var r = document.selection.createRange();
        if (r === null) {
            return {
                start: 0,
                end: el.value.length,
                length: 0
            }
        }

        var re = el.createTextRange();
        var rc = re.duplicate();
        re.moveToBookmark(r.getBookmark());
        rc.setEndPoint('EndToStart', re);

        return {
            start: rc.text.length,
            end: rc.text.length + r.text.length,
            length: r.text.length,
            text: r.text
        };
    }) ||

    function () {
        return null;
    }

    )();

}
//替换选择
function replaceSelection(el) {

    var text = arguments[0] || '';

    return (

    /* mozilla / dom 3.0 */ ('selectionStart' in el && function () {
        el.value = el.value.substr(0, el.selectionStart) + text + el.value.substr(el.selectionEnd, el.value.length);
        return this;
    }) ||

    /* exploder */ (document.selection && function () {
        el.focus();
        document.selection.createRange().text = text;
        return this;
    }) ||

    /* browser not supported */function () {
        el.value += text;
        return jQuery(el);
    }

    )();
}

但是如果你想做,你题目描述的东西的话,还是建议用插件。 这里有一个不错的jquery插件: http://ichord.github.io/At.js/

可以是用AT-JS jquery插件来实现你需要的效果:

下载地址:

http://pan.baidu.com/share/link?shareid=495943&uk=386708086

使用方法:

$("input[name=message]").atWho("@",{
tpl: "<li id='${uid}' data-value='${name}'>${name} <small>${spacenote}</small></li>",
'data':friend_list
});

用这个库,可以看看源代码解决实现方式,没像上面那样引入了jquery那么重。
https://github.com/deshiknave...

以下是在Vue中的例子实现

// main.js中
import { position, offset } from 'caret-pos';

Vue.prototype.$positon = position
Vue.prototype.$offset = offset

// edior.vue 的 methods 中,然后在 mounted 钩子中挂一下这个方法
bindKeys() {
  let textarea = document.querySelector('.textarea')
  textarea.addEventListener('keyup', (e) => {
    console.log('____________', this.$offset(textarea))
  })
},
推荐问题
宣传栏