这两天测试小哥哥小姐姐给我提的最多的就是div文本框里面的bug,别问我为什么要用div做文本输入框,非要回答的话我只能说我就是为了生产bug的(大佬就这么写的组件,咱太菜了写不出自己的呀 ε(┬┬﹏┬┬)3 )
先来看一下我要写东西和要实现的效果吧
这样的框我要写两个的,下面的框还有一个时间的标签
就是上面的这个输入框,包括前两天那个转义符也是在这个里面提的bug
之前写的一个特殊标签转义还是有bug存在的今天一块重新再来一次
富文本编辑器或div写的文本框转义字符不识别问题_hong0114的博客-CSDN博客
这篇里面写的是直接把所有的标签全部转换成文本了,导致我的插入人数的标签也给转了,然后后端小哥哥判断传入数据的规则就变成直接匹配 #人数#这个字段了,所以不管我复制我多次,都可以传入数据,所以上一篇博客里面的方法只适用于单纯的特殊标签转文本,然后今天大佬给我秀了另一套操作
<script>
var keys = Object.keys || function (obj) {
obj = Object(obj)
var arr = []
for (var a in obj) arr.push(a)
return arr
}
var invert = function (obj) {
obj = Object(obj)
var result = {}
for (var a in obj) result[obj[a]] = a
return result
}
var entityMap = {
escape: {
' ': ' ',
'<': '<',
'>': '>',
'&': '&',
'¢': '¢',
'©': '©',
'®': '®',
'™': '™',
'™': '×',
'÷': '÷',
}
}
export default {
entityMap.unescape = invert(entityMap.escape)
var entityReg = {
escape: RegExp('[' + keys(entityMap.escape).join('') + ']', 'g'),
unescape: RegExp('(' + keys(entityMap.unescape).join('|') + ')', 'g')
}
watch: {
divText(val) {
if (val) {
this.divText = JSON.parse(JSON.stringify(val))
let innerLen = val.replace(/<\/?.+?>/g, '\n')
innerLen = innerLen.replace(/( )/g, (_, str) => '\n')
this.textLen = innerLen.replace(/ /g, '\n').length
}
this.$emit('getTextData', this.textLen, this.unescape(this.divText), this.index) // 长度 文本内容
},
text(neval, olval) {
if (neval) {
this.divText = JSON.parse(JSON.stringify(neval))
if (neval) {
let innerLen = neval.replace(/<\/?.+?>/g, '\n')
innerLen = innerLen.replace(/( )/g, (_, str) => '\n')
this.textLen = innerLen.replace(/ /g, '\n').length
console.log(this.textLen, 33333333333333)
}
}
}
},
methods: {
// 将HTML转义为实体
escape(html) {
if (typeof html !== 'string') return ''
return html.replace(entityReg.escape, function (match) {
return entityMap.escape[match]
})
},
// 实体转html
unescape(str) {
if (typeof str !== 'string') return ''
return str.replace(entityReg.unescape, function (match) {
return entityMap.unescape[match]
})
},
}
}
大概就是这个样子的,把特殊的符号列出来以后,再定义个方法,引用到输入框里面,其实思维很简单,但是咱手残再加上太菜了就成这个样子了,这个是直接写在组件页面的哦
其实这个bug还好啦,上线前被一个连环bug差点搞炸掉,到现在还有个问题没有解决呢除了上面的代码,我把已经改好的组件发一下吧
<div class="greeting">
<!-- <p v-if="showTitle" class=" greeting_head">{{title}}</p> -->
<div class="greeting_main inp">
<div class="chaBut">
<el-button type="text" class="clickable no-select" :disabled="!contenteditable" @click="tagClick('peopleNum',$event)">[#人数#]</el-button>
<el-button v-if="isTime" type="text" class="clickable no-select" :disabled="!contenteditable" @click="tagClick('time',$event)">[#等待时间#]</el-button>
</div>
<div
ref="changeData"
:key="contentsave"
id="editDiv"
:class="['editDiv',isDetail ? 'nodeail':'']"
@paste='onPaste'
@input="changeText"
@keyup="!isDetail && myKeyUp()"
@blur="!isDetail && myBlur()"
v-html="divText"
:contenteditable="contenteditable"
show-word-limit
>
</div>
<div v-if="textLen > len" class="textSty">
文本内容不可超过{{ len }}字!
</div>
<div class="chaBut-limit-num">
{{textLen}}/{{len}}
</div>
</div>
</div>
这个是我的两个标签和标签下面的div文本框,还有右下角的字数,假装这是个textarea输入框;
const insertStrName = '<p class="editDiv_hintText" disabled="true" style="display: inline; pointer-events: none;" contentEditable="false"> #人数#</p> '
const insertStrNum = '<span class="editDiv_hintText" disabled="true" style="pointer-events: none;" contentEditable="false"> #等待时间#</span> '
export default {
props: {
contentsave:{
type: String,
default: ''
},
text: { // 赋值
type: String,
default: ''
},
index: { // 下标
type: Number
// default: 0
},
title: { // 标题
type: String,
default: '文本信息:'
},
len: { // 长度
type: Number,
default: 1000
},
placeHolder: {
type: String,
default: ''
},
showTitle: {
type: Boolean,
default: true
},
contenteditable: { // 是否可输入
type: Boolean,
default: true
},
isTime: {
type: Boolean,
default: false
}
},
data() {
return {
cNum:0,
isIE9: false,
pos: '',
isDetail: false,
participateWelMsg: '',
textLen: '', // 文本长度
divText: ''
}
},
watch: {
divText(val) {
if (val) {
this.divText = JSON.parse(JSON.stringify(val))
let innerLen = val.replace(/<\/?.+?>/g, '\n')
innerLen = innerLen.replace(/( )/g, (_, str) => '\n')
this.textLen = innerLen.replace(/ /g, '\n').length
}
this.$emit('getTextData', this.textLen, this.unescape(this.divText), this.index) // 长度 文本内容
},
text(neval, olval) {
if (neval) {
this.divText = JSON.parse(JSON.stringify(neval))
if (neval) {
let innerLen = neval.replace(/<\/?.+?>/g, '\n')
innerLen = innerLen.replace(/( )/g, (_, str) => '\n')
this.textLen = innerLen.replace(/ /g, '\n').length
console.log(this.textLen, 33333333333333)
}
}
}
},
created() {
},
mounted() {
this.divText = JSON.parse(JSON.stringify(this.text))
},
methods: {
// 将HTML转义为实体
escape(html) {
if (typeof html !== 'string') return ''
return html.replace(entityReg.escape, function (match) {
return entityMap.escape[match]
})
},
// 实体转html
unescape(str) {
if (typeof str !== 'string') return ''
return str.replace(entityReg.unescape, function (match) {
return entityMap.unescape[match]
})
},
// 清除默认格式 禁止粘贴
onPaste(evt) {
this.textInit(evt)
},
textInit(e) {
e.preventDefault()
var text
var clp = (e.originalEvent || e).clipboardData
if (clp === undefined || clp === null) {
text = window.clipboardData.getData('text') || ''
if (text !== '') {
if (window.getSelection) {
var newNode = document.createElement('span')
newNode.innerHTML = text
window.getSelection().getRangeAt(0).insertNode(newNode)
} else {
document.selection.createRange().pasteHTML(text)
}
}
} else {
text = clp.getData('text/plain') || ''
if (text !== '') {
document.execCommand('insertText', false, text)
}
}
},
tagClick(type, e) {
if(this.textLen<=512){
switch (type) {
case 'peopleNum':
let str1 = JSON.parse(JSON.stringify(this.$refs.changeData.innerHTML))
// this.$refs.changeData.innerHTML
let arr1 = str1.split('</p>').length - 1
if (arr1 > 4) {
this.$message.error('人数最多添加5个')
return false
}else{
this.insertContent(insertStrName)
}
break
case 'time':
let str2 = JSON.parse(JSON.stringify(this.$refs.changeData.innerHTML))
// this.$refs.changeData.innerHTML
let arr2 = str2.split('</span>').length - 1
if (arr2 > 4) {
this.$message.error('时间最多添加5个')
return
}else{
this.insertContent(insertStrNum)
}
break
default:
break
}
// }else{
// return
}
},
changeText() {
console.log(this.textLen)
if(this.textLen<=512){
let innerHTML = this.$refs.changeData.innerHTML
let innerLen = innerHTML.replace(/<\/?.+?>/g, "\n")
innerLen = innerLen.replace(/( )/g, (_, str) => '\n')
this.textLen = innerLen.replace(/ /g, "\n").length
this.$emit('getTextData', this.textLen, this.unescape(innerHTML), this.index) // 长度 文本内容
console.log(this.textLen, innerHTML, this.index,'lll')
}
},
// 键盘事件
myKeyUp() {
this.getPos()
this.assistChange()
},
myBlur() {
this.getPos()
this.assistChange()
},
assistChange() {
if (this.$refs.changeData) {
let inner = this.$refs.changeData.innerHTML
if (inner) {
let innerLen = inner.replace(/<\/?.+?>/g, "\n")
innerLen = innerLen.replace(/( )/g, (_, str) => '\n')
this.textLen = innerLen.replace(/ /g, "\n").length
} else {
this.textLen = 0
}
this.participateWelMsg = this.$refs.changeData.innerHTML
// console.log(this.$refs.changeData.innerHTML, 'this.$refs.changeData.innerHTML=>>')
this.$emit('getTextData', this.textLen, this.unescape(this.participateWelMsg), this.index) // 长度 文本内容
}
},
// 获取光标
getPos() {
const docSelection = document.selection // ie9以下
const winSelection = window.getSelection
if (!docSelection && winSelection) {
const sel = window.getSelection()
const hasRange = sel.getRangeAt && sel.rangeCount
if (hasRange) {
this.pos = sel.getRangeAt(0)
this.isIE9 = false
}
}
if (docSelection) {
this.pos = document.selection.createRange()
this.isIE9 = true
}
},
// 在光标位置插入内容
insertContent(content) {
if (!content) { // 如果插入的内容为空则返回
return false
}
// 不是指定选区则不进行插入
if (!this.pos) return false
let sel, range
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection()
if (sel.getRangeAt && sel.rangeCount) {
this.pos.deleteContents()
const el = document.createElement('div')
el.innerHTML = content
const frag = document.createDocumentFragment()
let node
let lastNode
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node)
}
this.pos.insertNode(frag)
if (lastNode) {
range = this.pos.cloneRange()
range.setStartAfter(lastNode)
range.collapse(true)
sel.removeAllRanges()
sel.addRange(range)
}
}
} else if (document.selection && document.selection.type !== 'Control') {
// IE < 9
this.pos.pasteHTML(content)
}
this.myBlur()
}
}
}
咱也不知道哪里写的还有毛病,这个里面的还有个bug就是会出现 #人#人数#数# 这种标签里面可以插入标签的情况,欢迎各位大佬来解决哦!
--------------------------------------------------------------------------------------------------------------------------------我是一只正在学飞的菜鸟,有什么写的不好不对的地方欢迎来指教