在文本区域中显示DIV在光标位置

61

我希望为我的一个项目提供特定textarea的自动完成功能,类似于intellisense/omnicomplete的工作原理。为此,我需要确定绝对光标位置,以便知道DIV应该出现在哪里。

事实证明:这几乎是不可能实现的。是否有人有一些巧妙的想法来解决这个问题?


1
考虑使用 contenteditable div 替代 textarea 是否更好呢?只是随便提一下。 - Cade Roux
3
赏金提示:您需要修复的 jsfiddle 链接是:http://jsfiddle.net/eMwKd/1/。 - Sam Saffron
越来越接近 Chrome:http://jsbin.com/egadoj/1/edit - Sam Saffron
@xyu,是的,但我担心它们在这里被认为有点沉重。 - Sam Saffron
1
@xyu 基于 DOM 的编辑器(CodeMirror / Ace)可以使用 DOM 插入技术来确定位置,这非常简单明了。 - Sam Saffron
显示剩余3条评论
11个回答

-1
怎么样在克隆的div中添加一个span元素,并根据这个span的偏移量设置虚拟光标?我已经更新了你的fiddle here。这里只有JS部分。
// https://dev59.com/4nVC5IYBdhLWcg3wihmv
var map = [];
var pan = '<span>|</span>'

//found @ http://davidwalsh.name/detect-scrollbar-width

function getScrollbarWidth() {
    var scrollDiv = document.createElement("div");
    scrollDiv.className = "scrollbar-measure";
    document.body.appendChild(scrollDiv);

    // Get the scrollbar width
    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;

    // Delete the DIV 
    document.body.removeChild(scrollDiv);

    return scrollbarWidth;
}

function getCaret(el) {
    if (el.selectionStart) {
        return el.selectionStart;
    } else if (document.selection) {
        el.focus();

        var r = document.selection.createRange();
        if (r == null) {
            return 0;
        }

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

        return rc.text.length;
    }
    return 0;
}


$(function() {
    var span = $('#pos span');
    var textarea = $('textarea');

    var note = $('#note');

    css = getComputedStyle(document.getElementById('textarea'));
    try {
        for (i in css) note.css(css[i]) && (css[i] != 'width' && css[i] != 'height') && note.css(css[i], css.getPropertyValue(css[i]));
    } catch (e) {}

    note.css('max-width', '300px');
    document.getElementById('note').style.visibility = 'hidden';
    var height = note.height();
    var fakeCursor, hidePrompt;

    textarea.on('keyup click', function(e) {
        if (document.getElementById('textarea').scrollHeight > 100) {
            note.css('max-width', 300 - getScrollbarWidth());
        }

        var pos = getCaret(textarea[0]);

        note.text(textarea.val().substring(0, pos));
        $(pan).appendTo(note);
        span.text(pos);

        if (hidePrompt) {
            hidePrompt.remove();
        }
        if (fakeCursor) {
            fakeCursor.remove();
        }

        fakeCursor = $("<div style='width:5px;height:30px;background-color: #777;position: absolute;z-index:10000'>&nbsp;</div>");

        fakeCursor.css('opacity', 0.5);
        fakeCursor.css('left', $('#note span').offset().left + 'px');
        fakeCursor.css('top', textarea.offset().top + note.height() - (30 + textarea.scrollTop()) + 'px');

        hidePrompt = fakeCursor.clone();
        hidePrompt.css({
            'width': '2px',
            'background-color': 'white',
            'z-index': '1000',
            'opacity': '1'
        });

        hidePrompt.appendTo(textarea.parent());
        fakeCursor.appendTo(textarea.parent());



        return true;
    });
});

更新:我发现如果第一行没有硬换行符,会出现错误,但如果有硬换行符,它似乎可以正常工作。


我喜欢关于找到滚动条宽度的部分。然而,大多数光标坐标库都存在一个常见的错误component.io textarea-caret-position 插件处理了这个问题,不仅不需要jQuery,在Chrome、FF和IE中也可以使用,而且只有80行代码。 - Dan Dascalescu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接