javascript - 当选择滚动文本时,Div 被放置在文本区域之外

标签 javascript jquery html css

在我的场景中,我需要在所选文本下方显示一个 div(替换为星号)。我在这里面临问题。

当滚动文本区域并选择滚动的文本(即文本区域框最后的文本)时,div(替换为星号)将出现在文本区域之外。但是,我需要在文本区域内显示。无需滚动即可正常工作。

JavaScript:

var edits = [""];
var interval = true;
var maxHistorySize = 10;
var saveInterval = 3000;

function undo(e) {
    var evtobj = window.event ? window.event : e;
    if (evtobj.keyCode == 90 && evtobj.ctrlKey) {
        evtobj.preventDefault();
        var txtarea = document.getElementById("mytextarea");
        var previousText = edits.length === 1 ? edits[0] : edits.pop();
        if (previousText !== undefined) {
            txtarea.value = previousText;
        }
    }
}

$(document).ready(function () {
    var replaceDiv = document.createElement('div');
    replaceDiv.id = 'rplceTxtDiv';
    document.getElementsByTagName('body')[0].appendChild(replaceDiv);
    $('<div id="starsRplce"></div>').appendTo('#rplceTxtDiv');
    $("#starsRplce").click(function () {
        var txtarea = document.getElementById("mytextarea");
        var start = txtarea.selectionStart;
        var finish = txtarea.selectionEnd;
        var allText = txtarea.value;
        edits.push(allText);
        if (edits.length > maxHistorySize) edits.shift();
        var sel = allText.substring(start, finish);
        sel = sel.replace(/[\S]/g, "*");
        var newText = allText.substring(0, start) + sel + allText.substring(finish, allText.length);
        txtarea.value = newText;
        $('#rplceTxtDiv').offset({ top: 0, left: 0 }).hide();
    });
    replaceDiv.style.display = "none";
    $('<span id="closePopUp">&#735;</span>').appendTo('#rplceTxtDiv');
    $("#closePopUp").click(function () {
        $('#rplceTxtDiv').offset({ top: 0, left: 0 }).hide();
    })
    var rplceTxtDiv = $('#rplceTxtDiv');
    $('#mytextarea').on('select', function (e) {
        replaceDiv.style.display = "block";
        var txtarea = document.getElementById("mytextarea");
        var start = txtarea.selectionStart;
        var finish = txtarea.selectionEnd;
        rplceTxtDiv.offset(getCursorXY(txtarea, start, 20)).show();
        rplceTxtDiv.find('div').text('replace with stars');
    }).on('input', function () {
        if (interval) {
            interval = false;
            edits.push($(this).val());
            if (edits.length > maxHistorySize) edits.shift();
            setTimeout(() => interval = true, saveInterval);
        }
    });
    document.onkeydown = undo;
});

var getCursorXY = function getCursorXY(input, selectionPoint, offset) {
    var inputX = input.offsetLeft,
        inputY = input.offsetTop;
    var div = document.createElement('div');
    var copyStyle = getComputedStyle(input);
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;
    try {
        for (var _iterator = copyStyle[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done) ; _iteratorNormalCompletion = true) {
            var prop = _step.value;

            div.style[prop] = copyStyle[prop];
        }
    } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
    } finally {
        try {
            if (!_iteratorNormalCompletion && _iterator.return) {
                _iterator.return();
            }
        } finally {
            if (_didIteratorError) {
                throw _iteratorError;
            }
        }
    }
    var swap = '.';
    var inputValue = input.tagName === 'INPUT' ? input.value.replace(/ /g, swap) : input.value;
    var textContent = inputValue.substr(0, selectionPoint);
    div.textContent = textContent;
    if (input.tagName === 'TEXTAREA') div.style.height = 'auto';
    if (input.tagName === 'INPUT') div.style.width = 'auto';
    var span = document.createElement('span');
    span.textContent = inputValue.substr(selectionPoint) || '.';
    div.appendChild(span);
    document.body.appendChild(div);
    var spanX = span.offsetLeft,
        spanY = span.offsetTop;
    document.body.removeChild(div);
    return {
        left: inputX + spanX,
        top: inputY + spanY + offset
    };
};

这是我的 plunker .

最佳答案

您还需要通过 scrollTop 属性在位置计算中考虑文本区域内容滚动的量:

var inputX = input.offsetLeft,
    inputY = input.offsetTop,
    inputScrollOffset = input.scrollTop;

.

return {
    left: inputX + spanX,
    top: inputY - inputScrollOffset + spanY + offset
};

https://plnkr.co/edit/7ScbeTL88tWDU3PqzGqY?p=preview

关于javascript - 当选择滚动文本时,Div 被放置在文本区域之外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48786768/

相关文章:

javascript - Highchart如何从xaxis底线向上做动画

jquery animate() 未从 FIREFOX 中的当前位置开始

jquery - 通过内容的精确匹配来选择元素

php - 我需要做什么才能看到数据库元素(foreach 循环)

javascript - React.js 错误 : Invariant Violation: Minified React error #37

javascript - 将\n 替换为 <br> 并将\r\n 替换为 javascript 中的 <p>

javascript - 如何跳转到特定文本或段落

jQuery Sizzle 语法错误 - 未捕获的表达式

javascript - HTML5 地理定位高度

html - 在父级上方可视化地创建子菜单/下拉菜单