contenteditable及对应光标的获取方法

工作中遇到的一个需求,需要在textarea中艾特成员,还要带样式,我尼玛?!淡定的将原来的textarea改成了div,并且contenteditabl=”true”了一下,因为textarea只能输入纯文本啊!上代码,附注释:

<div contenteditable="true" id="editdiv" placeholder="一个可以编辑的DIV"></div>
<style>
#editdiv{ padding: 5px 10px; height: 100px; width:100%;}
/* 为空时显示,模拟placeholder属性 */
#editdiv:empty:before{content: attr(placeholder);color: #999999;}
/* 焦点时内容为空 */
#editdiv:focus:before{content:none;}
</style>

还有代码中用到了jQuery,当然是要先引入啊~,都后退!我要开始装逼了!!贴出核心代码:

// 自动聚焦,这招很6,找了很多方法没用,最后在Stack Overflow找到的
var div = document.getElementById('editdiv');
setTimeout(function() {
    div.focus();
}, 0);

// 失去焦点
$("#editdiv").blur(function(){
    console.log("blur");
});
// 获取焦点
$("#editdiv").focus(function () {
    console.log("focus");
});

// 监听keyup
$("#editdiv").keyup(function(){
    console.log($(this).html());
});

/* 
手动敲代码会默认转义成< > 
<span style="color:#ffffff">红色字体~</span>
如果需要插入带有样式的代码,可以通过JS来实现:
$("#editdiv").append('<span style="color:#ffffff">红色字体~</span>');
这个时候就需要获取光标的位置了,再往下看~~!!!
*/

// 定义最后光标对象
var lastEditRange;
// 编辑框点击事件
document.getElementById('editdiv').onclick = function() {
    // 获取选定对象
    var selection = getSelection();
    // 设置最后光标对象
    lastEditRange = selection.getRangeAt(0);
}

// 按键弹起事件
document.getElementById('editdiv').onkeyup = function() {
    // 获取选定对象
    var selection = getSelection();
    // 设置最后光标对象
    lastEditRange = selection.getRangeAt(0);
    console.log(lastEditRange);
    console.log(startOffset);
    console.log(endOffset);
    // 获取光标在当前DIV内距离顶部的距离
    console.log(lastEditRange.commonAncestorContainer.parentNode.offsetTop);
    // 获取光标之前的元素
    console.log(window.getSelection().anchorNode.textContent.substring(window.getSelection().anchorOffset - 1,window.getSelection().anchorOffset));
    // 获取光标之前所有的元素
    console.log(window.getSelection().anchorNode.textContent.substring(0,window.getSelection().anchorOffset));
}

// 监听粘贴图片
document.querySelector("#editdiv").addEventListener("paste", function (event) {
    var event = event || window.event;
    var clipboardData = event.clipboardData, items, item, ite, itee;                    
    if (clipboardData) {
        items = clipboardData.items;
        item = items[0];
        itee = items[1];
        if (items[2]) {
            ite = items[2];
            //判断是否是从QQ粘贴的图片,只有从qq粘过来的图片有三条item、文字一条、截图一条、企业微信图片二条
            if (ite != undefined && ite.type.match(/^image\//i)) {
                alert("操作失败,暂不支持此类贴图方式");
                return;
            }
        }
        // 判断是否为图片数据
        if (item && item.kind === 'file' && item.type.match(/^image\//i)) {
            var blob = item.getAsFile();
            //  下面执行上传图片
            if (blob.name == undefined) {
                blob.name = 'image.png';
            }

            // 上传图片的接口、顺便回显在页面上 code...

        } else if (itee && itee.kind === 'file' && itee.type.match(/^image\//i)) {
            var blob = itee.getAsFile();
            //  从企业微信上粘贴的图片下面执行上传图片
            if (blob.name == undefined) {
                blob.name = 'image.png';
            }

            // 上传图片的接口、顺便回显在页面上 code...
        }
    }

    event.stopPropagation(); // 可能父级有可编辑的元素
});

参考文档:

https://segmentfault.com/a/1190000005869372
https://segmentfault.com/q/1010000016262959

最后再推荐一个叼大的插件,实现DIV中 @成员 的功能 https://github.com/ichord/At.js ,纳尼?!为什么我在需求中不用这个插件?因为这个需求列表的样式长得很定制化啊,插件的样式满足不了需求,你懂的!(杀一个产品祭天)

猜你喜欢

发表评论

最新发布