美文网首页
用于写描述信息的支持选择无序列表、有序列表的文本框组件

用于写描述信息的支持选择无序列表、有序列表的文本框组件

作者: kaimen_0ca9 | 来源:发表于2020-12-28 22:14 被阅读0次

    项目上要用到类似于boss上填简历的工作经历的描述的文本框,文本框上要有选择无序列表、有序列表的功能,直接引入一个富文本编辑器感觉不划算,最终还是决定自己动手写一个:


    image.png

    以下是组件内代码

    上次经测试有bug,主要在有序文本,反复测试修改后的应该是够用了的

    <!-- 无序、有序文本框 -->
    <template>
      <div class="serial-selecter">
        <div class="serial-toolbar">
          <el-tooltip effect="dark" content="无序列表" placement="top">
            <i class="iconfont icon-list" @click="changeType('li')"></i>
          </el-tooltip>
          <el-tooltip effect="dark" content="有序列表" placement="top">
            <i class="iconfont icon-ol" @click="changeType('ol')"></i>
          </el-tooltip>
        </div>
        <div class="ipt-box">
          <el-input type="textarea" ref="txtatea" v-model="serialtxt" :maxlength="maxlength" show-word-limit :placeholder="placeholder" :disabled="disabled" @keyup.native.enter="enterHandle" @input="inputHandle" :autosize="{ minRows: 3, maxRows: 6}"></el-input>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        value: { default: ''},  // 必须要使用value
        maxlength: { default: 100 },
        placeholder: { default: '请输入' },
        disabled: { default: false },
      },
      data () {
        return {
          liststr: '●',
          type: '',
          serialtxt: '',
        }
      },
      watch: {
        value: {
          immediate: true,
          handler(val) {
            this.serialtxt = val;
          }
        }
    
      },
      methods: {
        changeType(type) {
          if(this.disabled) return
          this.type = type;
          this.enterHandle();
        },
        enterHandle() {
        //   console.log(this.$refs.txtatea.$el.firstChild.selectionStart);
          let mousePos = this.$refs.txtatea.$el.firstChild.selectionStart;      // 光标职位
          let txtBeforeAll = this.serialtxt.slice(0, mousePos);  // 光标之前的所有文本
          let txtAfterAll = this.serialtxt.slice(mousePos);      // 光标之后的所有文本
          let lastIndex = txtBeforeAll.lastIndexOf('\n');        // 文本最后一个换行符位置
          let curtxt = txtBeforeAll.slice(lastIndex+1);            // 文本最后一个换行符位置到光标之间的文本(光标当前行的文本)
          if(this.type == 'li') {
    
            if(txtBeforeAll.slice(lastIndex+1,lastIndex+2) == this.liststr) {  // 如果已有排序,则是取消排序
              if(txtBeforeAll.slice(lastIndex+2,lastIndex+3) == ' ') {
                this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + txtBeforeAll.slice(lastIndex+3) + txtAfterAll;
              }else {
                this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + txtBeforeAll.slice(lastIndex+2) + txtAfterAll;
              }
              this.type = '';
    
            } else {     // 否则,添加排序
    
              // 如果已存在有序排序,则替换为无序
              if((parseInt(curtxt) > 0) && (txtBeforeAll.slice(lastIndex+parseInt(curtxt).toString().length+1,lastIndex+parseInt(curtxt).toString().length+2) == '.')) {  // 如果已有排序,则是取消排序
                let numLength = parseInt(curtxt).toString().length;
                if(txtBeforeAll.slice(lastIndex+numLength+2,lastIndex+numLength+3) == ' ') {
                  this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + this.liststr+' ' + txtBeforeAll.slice(lastIndex+numLength+3) + txtAfterAll;
                }else {
                  this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + this.liststr+' ' + txtBeforeAll.slice(lastIndex+numLength+2) + txtAfterAll;
                }
    
              } else {
    
                this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + this.liststr+' ' + txtBeforeAll.slice(lastIndex+1) + txtAfterAll;
    
              }
    
            }
    
          }else if (this.type == 'ol') {    // 有序
            if((parseInt(curtxt) > 0) && (txtBeforeAll.slice(lastIndex+parseInt(curtxt).toString().length+1,lastIndex+parseInt(curtxt).toString().length+2) == '.')) {  // 如果已有排序,则是取消排序
              // console.log(parseInt(curtxt).toString());
              let numLength = parseInt(curtxt).toString().length;
              if(txtBeforeAll.slice(lastIndex+numLength+2,lastIndex+numLength+3) == ' ') {
                this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + txtBeforeAll.slice(lastIndex+numLength+3) + txtAfterAll;
              }else {
                this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + txtBeforeAll.slice(lastIndex+numLength+2) + txtAfterAll;
              }
              this.type = '';
    
            } else {     // 否则,添加排序
    
              // 如果已存在无序排序,则替换为有序
              if(txtBeforeAll.slice(lastIndex+1,lastIndex+2) == this.liststr) {
                if(txtBeforeAll.slice(lastIndex+2,lastIndex+3) == ' ') {
                    this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + '1.'+' ' + txtBeforeAll.slice(lastIndex+3) + txtAfterAll;
                }else {
                    this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + '1.'+' ' + txtBeforeAll.slice(lastIndex+2) + txtAfterAll;
                }
    
              }else {
    
                // 根据上一行数字得出本行排序数字
                let seIndex = txtBeforeAll.slice(0, lastIndex).lastIndexOf('\n')  // 上一个换行符出现的位置
                
                if(seIndex < 0 && !(parseInt(txtBeforeAll.slice(seIndex+1,seIndex+2)) > 0 && (txtBeforeAll.slice(seIndex+2,seIndex+3) == '.'))) { // 上一行未出现换行符且第一个未出现数字,则是第一个
                  this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + '1.'+' ' + txtBeforeAll.slice(lastIndex+1) + txtAfterAll;
                } else {
                  // 获取第一出现‘.’的位置
                  let dotIndex = txtBeforeAll.slice(seIndex).indexOf('.');
                  // console.log(dotIndex);
                  this.serialtxt = txtBeforeAll.slice(0, lastIndex+1) + (parseInt(txtBeforeAll.slice(seIndex+1,seIndex+dotIndex))+1)+'. ' + txtBeforeAll.slice(lastIndex+1) + txtAfterAll;
                }
    
              }
            }
          }
    
          this.$emit('input', this.serialtxt);
        },
        inputHandle() {
          this.$emit('input', this.serialtxt);
        }
      }
    }
    </script>
    
    <style lang='less' scoped>
    .serial-selecter {
      .serial-toolbar {
        height: 39px;
        border: 1px solid @color-border;
        border-bottom: none;
        border-top-right-radius: 4px;
        border-top-left-radius: 4px;
        background-color: #f8f9fb;
        padding-left: 20px;
        .iconfont {
          margin: 0 5px;
          font-size: 16px;
          cursor: pointer;
        }
      }
      .ipt-box {
        /deep/ .el-textarea__inner{
          border-top-right-radius: 0;
          border-top-left-radius: 0;
        }
      }
    }
    </style>
    
    

    引用

    由于实现了组件的双向绑定,可以直接在父组件这样用

    <serial-text v-model="postInfo.description" :placeholder="'请输入不少于15个字的职位描述;\n您可以选择输入岗位职责、任职要求、岗位发展规划、晋升通道等岗位相关内容;\n同时应避免发布违法违规、含有歧视性、虚假、夸张以及不文明的信息。'" :maxlength="5000"></serial-text>
    

    相关文章

      网友评论

          本文标题:用于写描述信息的支持选择无序列表、有序列表的文本框组件

          本文链接:https://www.haomeiwen.com/subject/srcxoktx.html