关键字提示编辑器二

做了一些改进。
当前行无内容时,隐藏提示框。
存在的问题,如果某一行的文字过多,则会自动换行,但是这种换行只是在视觉上的,html代码中没有体现。所以可能会导致高度计算不够。
效果:
效果
index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>div提示框跟随光标移动</title>
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <div id="editorDiv" contenteditable="true" oninput="handleInput(this)" class="editorDiv" style="font-family: 黑体;font-size: 20px"></div>
    <div>
        <span id="fakeContent"></span>
    </div>
    <div id="info" class="info">Demo</div>
<script src="index.js"></script>
</body>
</html>

index.css

* {
    margin: 0;
    padding: 0;
}
.editorDiv {
    width: 340px;
    height: 210px;
    color: #606266;
    resize:vertical;
    overflow: hidden;
    border: 1px solid #DCDFE6;
    border-radius: 4px;
    transition: border-color .2s cubic-bezier(.645,.045,.355,1);
    margin: 50px;
    padding: 20px;
}
.editorDiv:focus {
    border:1px solid #409EFF;
    outline: none;
}
.info {
    width: 47px;
    height: 20px;
    position: absolute;
    border:1px solid crimson;
    top: 0;
    left: 0;
    display: none;
}
#fakeContent  {
    visibility: hidden;
    display: inline-block;
    background-color: #409EFF;
}

index.js

let editorDiv = document.querySelector('#editorDiv');
let fakeContent = document.querySelector('#fakeContent');
let info = document.querySelector('#info');

/**
 * 输入事件
 * */
function handleInput(that) {
    info.style.display = 'inherit';
    const parentOffset = getParentOffset();
    const cursorCoordinate = getCursorCoordinate(that);
    //文本数组,div每一行都是一个string
    const  contentStrList = getNodeList(that).map(node => node.textContent);
    //光标y坐标也就是contentStrList的索引
    if(cursorCoordinate.x === 0) {
        info.style.display = 'none';
        return;
    }
    const y = cursorCoordinate.y;
    //按照光标偏移量截取字符串
    fakeContent.textContent = contentStrList[y].substr(0,cursorCoordinate.x);
    const fakeContentStyle = getComputedStyle(fakeContent,null);
    info.style.left = (parseFloat(fakeContentStyle.width)+parentOffset.leftOffset)+'px';
    info.style.top = ((y+1)*parseFloat(fakeContentStyle.height)+parentOffset.topOffset)+'px';
}

/**
 * 获取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
    }
}

/**
 * 克隆字体和字号
 * @param src
 * @param dest
 */
function cloneFont(src,dest) {
    let srcStyle = getComputedStyle(src);
    dest.style.fontFamily = srcStyle.fontFamily;
    dest.style.fontSize  = srcStyle.fontSize;
}

/**
 * 获取div编辑框编辑区域左上角距离屏幕可视区域的偏移量
 * @returns {{topOffset: number, leftOffset: number}}
 */
function getParentOffset() {
    let boundingClientRect = editorDiv.getBoundingClientRect();
    let computedStyle = getComputedStyle(editorDiv,null);
    return {
        leftOffset: boundingClientRect.left+parseFloat(computedStyle.paddingLeft)+parseFloat(computedStyle.borderLeftWidth),
        topOffset: boundingClientRect.top+parseFloat(computedStyle.paddingTop)+parseFloat(computedStyle.borderTopWidth)
    }
}

cloneFont(editorDiv,fakeContent);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值