关键字提示编辑器一之可编辑div获取光标位置

没有考虑浏览器兼容性,暂时只考虑了Chrome。
效果
效果
在div中输入的时候,底下的蓝色部分(span)跟随光标变化而变化,而且内容为光标前的所有文本。
红色的部分是一个|,用来模拟光标。所以只要获得|的相对像素位置,以及div的位置,就可以计算出光标的绝对像素位置。还有个前提是蓝色部分的样式要和div文字的样式相同。
div获取光标位置比较复杂,如果是textarea和input框,内部是纯文本,比较好处理。
div中输入的时候,第一行输入的内容是div的第一个文本元素。换行之后,每一行都会自动被一个div包裹起来。如果该行为空,默认里面会有一个br标签,如果有内容,则br标签会消失。
select对象的anchorNode,是一个#text,通过它可以找到光标作用在div内部某一个div,也就是某一行,记作y坐标。而anchorOffset,记录了光标在这个#text的偏移量,记作x坐标。
index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div class="inputBox" contenteditable="true" oninput="handleInput(this)"></div>
<span style="background: #409EFF;" id="fakeContent"></span><!--
两个span之间用注释隔开,消除空隙(不能用浮动)
--><span style="background: crimson;" id="fakeCursor">|</span>
<br/>
</body>
</html>
<script>
    let fakeContent = document.querySelector('#fakeContent');

    /**
     * 输入事件
     * */
    function handleInput(that) {
        let cursorCoordinate = getCursorCoordinate(that);
        //文本数组,div每一行都是一个string
        let  contentStrList = getNodeList(that).map(node => node.textContent);
        let spanContent = '';
        //光标y坐标也就是contentStrList的索引
        let y = cursorCoordinate.y;
        for (let i = 0; i < y; i++) {
            //添加内容和换行
            spanContent += contentStrList[i]+'<br/>';
        }
        if(contentStrList.length > 0) {
            //如果长度为0,表示编辑框没有内容,y会是-1,contentStrList[y]会是undefined
            //按照光标偏移量截取字符串
            spanContent += contentStrList[y].substr(0,cursorCoordinate.x);
        }
        fakeContent.innerHTML = spanContent;
    }

    /**
     * 获取div内容并转为Node数组
     * @param elem
     * @returns {ChildNode[]}
     */
    function getNodeList(elem) {
        return Array.from(elem.childNodes);
    }

    /**
     * 获取光标的坐标
     * @param elem
     * @returns {{x: number 光标偏移量, y: number 光标在div子元素数组中的索引}}
     */
    function getCursorCoordinate(elem) {
        const selection = window.getSelection();
        const cursorIndex = getNodeList(elem).findIndex(node =>
            node.firstChild === selection.anchorNode|| node === selection.anchorNode);
        const cursorOffset = selection.anchorOffset;
        return {
            x: selection.anchorOffset,
            y: cursorIndex
        }
    }

</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值