来源于:Web前端开发之@ 功能 JS 实现原理详解 http://www.javashuo.com/article/p-bcfyqyay-y.html
监听是否选中@对象,重置编辑框内容
1.取以前保留先来的信息
2.删除 @ 符号
3.生成需要显示的内容,一个 span
4.将生成内容打包放在 Fragment 中
5.将 Fragment 中的内容放入 range 中,并将光标放在空格之后
6.成功选人后让输入框获取焦点
setEditor: {
handler: function (newVal, oldVal) {
if (newVal) {
this.paramsFlag = false
// 获取以前保留先来的信息。
this.editor.cmd.do('insertHTML', ' ') //在选中@对象后生成一个空格,wangeditor组件内功能,若用其他组件,可参考注释内容
var selection = this.selection
var range = this.range
var textNode = range.startContainer
var paramsLen = this.params.length // 获取@参数的长度
// 删除 @ 符号。
range.setStart(textNode, range.endOffset - 1)
range.setEnd(textNode, range.endOffset + paramsLen)
range.deleteContents()
// 生成需要显示的内容,一个 span
var spanNode1 = document.createElement('span')
spanNode1.className = 'at-text'
spanNode1.innerHTML = this.setEditorCon.data
// var spanNode2 = document.createElement('span') // 在@回乡后生成一个空格
// spanNode2.innerHTML = ' '
// 将生成内容打包放在 Fragment 中
var frag = document.createDocumentFragment()
frag.appendChild(spanNode1)
// 并获取生成内容的最后一个节点,也就是空格。
// var node, lastNode
// while ((node = spanNode2.firstChild)) {
// lastNode = frag.appendChild(node)
// }
// 将 Fragment 中的内容放入 range 中,并将光标放在空格之后。
range.insertNode(frag)
// selection.extend(lastNode, 1)
// 成功选人后让输入框获取焦点
selection.collapseToEnd()
}
},
deep: true
}
获取@参数,显示@列表,在onchange里执行
1.按下了@键,保存按下@时的光标信息
2.获取当前文本。 有@时,获取@参数,展示@列表;没有有@时,纯文本展示。
var params
if (this.isKeySelect) {
// 按下了@键,保存按下@时的光标信息
var selection = window.getSelection()
this.selection = selection
this.range = selection.getRangeAt(0)
// 是否有@参数
this.count = 1
this.paramsFlag = true
}
if (this.paramsFlag) {
// 获取当前文本
var textNode = this.range.startContainer
var text = textNode.data
if (text.lastIndexOf('@') !== -1) {
// 有@时,获取@参数,展示@列表
var newIndex = text.lastIndexOf('@')
var textLen = text.length
var difference
if (this.count) {
if (this.count === 1) {
this.lastTextLen = 0
}
if (this.lastTextLen) {
difference = Math.abs(textLen - this.lastTextLen)
if (textLen > this.lastTextLen) {
if (difference > 1) {
this.count = this.count + difference
} else {
this.count++
}
} else {
this.count--
}
} else {
this.count++
}
this.lastTextLen = textLen
if (this.count === 2) {
params = ''
} else {
params = text.slice(newIndex + 1, newIndex + this.count - 1)
}
}
this.params = params // 存储@参数
this.setSecelct(editorContentObj, params) // 获取@列表
} else {
this.paramsFlag = false
// 没有有@时,纯文本展示
editorContentObj.editorContent = this.html
editorContentObj.isSetId = this.isSelectId
// 更新@列表为空,未被选中,发送消息
this.getSelNull(editorContentObj)
}
}
执行鼠标点击事件,键盘事件
1.光标点击时,@列表不展示
2.按下键盘时触发,
mounted () {
// 光标点击时,@列表不展示
var wEtext = document.querySelector('.w-e-text') //获取包含内容的div
var obj = this
wEtext.onclick = function (e) {
obj.$emit('getSelMember', false) // 不展示@列表
}
// 按下键盘时触发
this.keyHand()
},
键盘事件
1.按下enter键发送
2.按下@键保存变量为true,执行后续操作;
3.按下删除键,删除@xx整体
删除逻辑
a :因为在建立时默认会在 @xxx 后添加一个空格,
因此当得知光标位于 @xxx 以后的一个第一个字符后并按下删除按钮时,
应该将光标前的 @xxx 给删除
b :当光标位于 @xxx 中间时,按下删除按钮时应该将整个 @xxx 给删除。
// 按下enter键后的处理
keyHand () {
var obj = this
var wText = document.querySelector('.w-e-text')
this.$nextTick(() => {
wText.onkeydown = function (e) {
// 按下了enter键发送消息,阻止浏览器默认换行操作
if (e.keyCode === 13) {
obj.$emit('getKeySend')
e.preventDefault() // 阻止浏览器默认换行操作
return false
}
// 按下了@键
if (e.code === 'Digit2' && e.shiftKey) {
obj.isKeySelect = true
} else {
obj.isKeySelect = false
// 按下了删除键
if (e.code === 'Backspace') {
var wTextP = document.querySelector('.w-e-text p')
var range = obj.selection.getRangeAt(0)
var removeNode = null
// 删除为光标前@xx的空格时
if (range.startOffset <= 1 && range.startContainer.parentElement.className !== 'at-text') {
removeNode = range.startContainer.previousElementSibling
}
// 删除为光标前@xxx 中间时
if (range.startContainer.parentElement.className === 'at-text') {
removeNode = range.startContainer.parentElement
}
if (removeNode) {
// 删除子span@标签
var removeCon = removeNode.innerText
wTextP.removeChild(removeNode)
// 更新@id
obj.isSelectList.forEach((item, index) => {
if (item.data === removeCon) {
obj.isSelectList.splice(index, 1)
obj.isSelectId.splice(index, 1)
}
})
}
}
}
}
})
}
网友评论