div文本框的坑(好像富文本编辑器也是这样的)

这两天测试小哥哥小姐姐给我提的最多的就是div文本框里面的bug,别问我为什么要用div做文本输入框,非要回答的话我只能说我就是为了生产bug的(大佬就这么写的组件,咱太菜了写不出自己的呀 ε(┬┬﹏┬┬)3     )

先来看一下我要写东西和要实现的效果吧

div文本框的坑(好像富文本编辑器也是这样的)

这样的框我要写两个的,下面的框还有一个时间的标签 

就是上面的这个输入框,包括前两天那个转义符也是在这个里面提的bug

div文本框的坑(好像富文本编辑器也是这样的)

之前写的一个特殊标签转义还是有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: {
    ' ': '&nbsp;',
    '<': '&lt;',
    '>': '&gt;',
    '&': '&amp;',
    '¢': '&cent;',
    '©': '&copy;',
    '®': '&reg;',
    '™': '&trade;',
    '™': '&times;',
    '÷': '&divide;',

  }
}
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(/(&nbsp;)/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(/(&nbsp;)/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">&nbsp;#人数#</p>&nbsp;'
const insertStrNum = '<span class="editDiv_hintText" disabled="true" style="pointer-events: none;" contentEditable="false">&nbsp;#等待时间#</span>&nbsp;'
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(/(&nbsp;)/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(/(&nbsp;)/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(/(&nbsp;)/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(/(&nbsp;)/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就是会出现  #人#人数#数#  这种标签里面可以插入标签的情况,欢迎各位大佬来解决哦!

 --------------------------------------------------------------------------------------------------------------------------------我是一只正在学飞的菜鸟,有什么写的不好不对的地方欢迎来指教

上一篇:el-input输入number,数字保留两位小数


下一篇:替换字符串中指定的字符的switch或replace的实现