工作中遇到的一个需求,需要在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 ,纳尼?!为什么我在需求中不用这个插件?因为这个需求列表的样式长得很定制化啊,插件的样式满足不了需求,你懂的!(杀一个产品祭天)