PC端

- html
<link rel="stylesheet" href="/atwho/jquery.atwho.css" />
<script type="text/javascript" src="/atwho/jquery.caret.js"></script>
<script type="text/javascript" src="/atwho/jquery.atwho.js"></script>
<div id="editable" contentEditable="true"></div>
<div id="editable1" style="display: none" contentEditable="true"></div> // 避免用户看见转化过程,所以隐藏转化
- js
//初始化
var at_config = {
at: "@",
insertTpl: '${atwho-at}${name}',
displayTpl: "<li data-id='${id}'>${name} / ${role} </li>",
callbacks: {
remoteFilter: function(query, callback) {
var ll = new Array();
$.ajax({
type:"get",
url: "",
success: function (data){
$.each(res.data, function(index, element) {
ll.push({ name: element.employeeName, id: element.id, role: element.roleName });
});
callback(ll);
}
})
}
}
}
//提交时
if (!$("#editable").text() || $("#editable").text().length > 300) {
return alert("请填写审批意见不得超过300字符")
}
let atList = []//@列表
for (var i = 0; i < $("#editable span").length; i++) {
atList.push({
targetUserId: $("#editable span").eq(i).attr("id"),
targetUserName: $("#editable span").eq(i).attr("name"),
})
}
$("#editable1").html($("#editable").html())
$("#editable1 span").replaceWith(function(data) { // 转化规则`@id;`
if ($(this).attr("id")) {
return "@" + $(this).attr("id") + ";"
}
});
$.ajax({
type: "post",
url: ""
data: JSON.stringify({
"opinion": $.trim($("#editable1").text()),
"atList": atList
}),
})
- 回显
var {atList, opinion} = result;
for (var m = 0; m < atList.length; m++) {
var { targetUserId, employeeName } = atList[m]
opinion = opinion.replace(new RegExp("@" + targetUserId + ";", "g"), "<span>@" + employeeName + "</span>")
}
`<p>${opinion}</p>`
- 注意360安全浏览器 兼容模式下无法读取 contentEditable,需在
html
加入下列代码
<!-- saved from url=(0014)about:internet -->
移动端

- html
<div id="editable" contentEditable="true" placeholder="请填写意见(必填)"></div>
<div id="editable1" style="display: none" contentEditable="true" placeholder="请填写意见(必填)"></div>
- js
var lastEditRange;
$("#editable").on("input", function(e) {//触发弹窗
// 获取选定对象
var selection = getSelection()
// 设置最后光标对象
lastEditRange = selection.getRangeAt(0)
if (selection.anchorOffset > 0 && selection.focusNode.nodeValue) {
if (selection.focusNode.nodeValue[selection.anchorOffset - 1] == "@") {
$(this).blur();
$(".dialog").show();
$(".dialog input").val("");
getPeopleList();
}
}
});
$(".dialog input").on("input", function() {
getPeopleList($(this).val())
});
function getPeopleList(val=""){ //加载人员列表
$.ajax({
type: "get?searchName="+val,
url: ""
},
success: function(){
$(".dialog ul").html("");
for (var i = 0; i < res.data.list.length; i++) {
var { name, departmentName,id } = res.data.list[i]
$(`<li onclick="saveRelay(name,id)">
<h3>${name}</h3>
<p>${departmentName}</p>
</li>`).appendTo(".dialog ul")
}
})
}
function saveRelay( name, id ){ // 选中事件
$(".dialog").hide();
var { name, id } = item;
let str = `<span id="${id}" name="${name}" contenteditable="false">@${name}</span>`
$("#editable").focus()
// 获取选定对象
var selection = getSelection()
// 判断是否有最后光标对象存在
if (lastEditRange) {
// 存在最后光标对象,选定对象清除所有光标并添加最后光标还原之前的状态
selection.removeAllRanges()
selection.addRange(lastEditRange)
}
// 如果是文本节点则先获取光标对象
var range = selection.getRangeAt(0)
// 获取光标对象的范围界定对象,一般就是textNode对象
var textNode = range.startContainer;
var thisP = textNode.parentNode;
var num = 0;
for (var i = 0; i < thisP.childNodes.length; i++) {
if (thisP.childNodes[i] == textNode) {
var inDex = selection.anchorOffset
var arr = thisP.childNodes[i].nodeValue.split("");
arr.splice(inDex - 1, 1);
thisP.childNodes[i].nodeValue = arr.join("")
var liTextNode = document.createTextNode(" "); // 处理光标显示bug
num = i + 2
if (thisP.childNodes[i + 1]) {
thisP.insertBefore($(str)[0], thisP.childNodes[i + 1])
} else {
thisP.appendChild($(str)[0])
thisP.appendChild(liTextNode)
}
break
}
}
// 光标移动到到原来的位置加上新内容的长度
range.setStart(thisP, num)
// 光标开始和光标结束重叠
range.collapse(true)
// 清除选定对象的所有光标对象
selection.removeAllRanges()
// 插入新的光标对象
selection.addRange(range)
// 无论如何都要记录最后光标对象
lastEditRange = selection.getRangeAt(0)
}