ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-12-07 17:30:00  阅读:231  来源: 互联网

标签:文本编辑 return textLen text 文本框 replace innerLen unescape div


这两天测试小哥哥小姐姐给我提的最多的就是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: {
    ' ': '&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就是会出现  #人#人数#数#  这种标签里面可以插入标签的情况,欢迎各位大佬来解决哦!

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

标签:文本编辑,return,textLen,text,文本框,replace,innerLen,unescape,div
来源: https://blog.csdn.net/hong0114/article/details/121670373

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有