Open missgentle opened 4 years ago
首先,输入区需要使用contenteditable="true"的div标签。
<div id="inputs" class="textarea fl" style="width:85%;height: 70px" contenteditable="true"></div>
<div id="atCheckDiv" class="atMenubox">
<select id="atMemberList" multiple="multiple" class="atMenu">
</select>
</div>
然后,代码中动态填充@弹框的人员列表。
let roomOnlineMember = [];
var frag = document.createDocumentFragment();
for(let y = 0; y<groupData.length; y++){
if(groupData[y].roomId == this.MRoomId){
for(let m = 0; m < onlineList.length; m++){
for(let n = 0; n < groupData[y].roomGroup.length; n++){
if(onlineList[m].id === groupData[y].roomGroup[n].id && onlineList[m].id !== UserInfo.userId){
roomOnlineMember.push({id:onlineList[m].id,name:onlineList[m].name});
if(!this.MAtPersonList.includes(onlineList[m].id)){
frag.appendChild(new Option(onlineList[m].name,onlineList[m].id));
}
}
}
}
this.MRoomOnlineMember = roomOnlineMember;
if(frag.children.length > 1){
frag.insertBefore(new Option("所有人","everyone"),frag.firstChild);
}
$("#atMemberList").empty().append(frag);
for(let i = 0; i < this.MAtPersonList.length; i++){
$("#atMemberList option[value='"+ this.MAtPersonList[i] +"']").hide();
}
}
}
然后,写一个input事件监听来弹框。
$('#inputs').on('input', (e) => { this.onInputChangeHandler(e); });
onInputChangeHandler(e:Event){
if($(e.target).text().endsWith('@') ){
if(!$("#atMemberList option").length) return;
for(let i = 0; i < this.MAtPersonList.length; i++){
if(this.MAtPersonList[i]=="everyone") return;
$("#atMemberList option[value='"+ this.MAtPersonList[i] +"']").hide();
}
// 保存选区以及光标信息,用于获取在光标焦点离开前,光标的位置
this.MSelection = window.getSelection();
this.MRange = document.createRange();
this.MRange.setStart(this.MSelection.anchorNode, this.MSelection.anchorOffset);
this.MRange.setEnd(this.MSelection.focusNode, this.MSelection.focusOffset);
// 设置弹出框位置
var offset = this.MRange.getBoundingClientRect();
$('#atCheckDiv').css('display','block')
.css('left',offset.left + 'px')
.css('top',offset.top-100 + 'px');
}else{
$('#atCheckDiv').hide();
}
}
再然后是选中@人员的逻辑,向输入区的div中插span标签。
$('#atMemberList').on('change', (e) => { this.onAtCheckListChangeHandler(e);});
onAtCheckListChangeHandler(e:Event){
this.MAtPersonList.push($('#atMemberList option:selected').val());
// 删除 @ 符号。
var textNode = this.MRange.startContainer;
this.MRange.setStart(textNode, this.MRange.startOffset - 1);
this.MRange.setEnd(textNode, this.MRange.endOffset);
this.MRange.deleteContents();
// 生成需要显示的内容,包括一个 span 和一个空格。
var spanNode1 = document.createElement('span');
var spanNode2 = document.createElement('span');
spanNode1.className = 'at-text';
spanNode1.setAttribute('id', $('#atMemberList option:selected').val());
spanNode1.innerHTML = '@' + $('#atMemberList option:selected').text();
spanNode2.innerHTML = ',';
// 将生成内容打包放在 Fragment 中,并获取生成内容的最后一个节点,也就是空格。
var frag = document.createDocumentFragment(),
node, lastNode;
frag.appendChild(spanNode1);
while ((node = spanNode2.firstChild)) {
lastNode = frag.appendChild(node);
}
// 将 Fragment 中的内容放入 range 中,并将光标放在空格之后。
this.MRange.insertNode(frag);
this.MSelection.extend(lastNode, 1);
this.MSelection.collapseToEnd();
$('#atMemberList').val('');
$('#atCheckDiv').hide();
}
最后是删除@某人的逻辑代码,我写了一个keydown事件监听。
$(document).on('keydown',(e) => { this.onKeydownHandler(e);});
onKeydownHandler(e){
if ($('#inputs').is(':focus') && e.keyCode == 8) {
var selection = window.getSelection();
var range = document.createRange();
range.setStart(selection.anchorNode, selection.anchorOffset);
range.setEnd(selection.focusNode, selection.focusOffset);
// 删除逻辑
// 1 :由于在创建时默认会在 @xxx 后添加一个空格,
// 所以当得知光标位于 @xxx 之后的一个第一个字符后并按下删除按钮时,
// 应该将光标前的 @xxx 给删除
// 2 :当光标位于 @xxx 中间时,按下删除按钮时应该将整个 @xxx 给删除。
var removeNode = null;
if (range.startOffset <= 1 && range.startContainer.parentElement.className != "at-text")
removeNode = range.startContainer.previousSibling;
if (range.startContainer.parentElement.className == "at-text")
removeNode = range.startContainer.parentElement;
if(removeNode && removeNode.id){
for(let i = 0; i < this.MAtPersonList.length; i++){
if(this.MAtPersonList[i] == removeNode.id){
this.MAtPersonList.splice(i,1);
$("#atMemberList option[value='" + removeNode.id +"']").show();
}
}
removeNode.remove();
}
}
}