textarea输入@跳出选择弹框,在光标处拼接选中的字符串

580 阅读2分钟

需求:

1、在文本框输入@符号,需要弹框进行字段选择,将选择的内容添加到textarea已有的内容里,并以@符号结尾,例如“@哈哈哈哈@”【前一个@是手动输入,后一个@需要自行拼接到选择内容后面】。

2、删除“@哈哈哈哈@”这种以@符号包裹的内容时,要将其全部删除,其他内容就是按照正常的一个字符一个字符删除。类似于微信群@人方式。

代码块:

<el-form-item label="逻辑代码" prop="ruleTextarea">  <el-input 
   id="ipt" 
   v-model="originObj.ruleTextarea" 
   :rows="5" 
   type="textarea" 
   placeholder="请输入" 
   @input="inputHandle" 
  />
</el-form-item> 


<el-dialog 
 v-model="dialogVisible" 
 title="字段列表" 
 append-to-body 
 width="400px" 
 :close-on-click-modal="false" 
 :show-close="false" 
 draggable
>   
   <ul v-for="item in typeList" :key="item.id" class="ul-list">
      <li @click="selectName(item.name)">{{item.name}}</li>
   </ul>
</el-dialog>

技术选型:element-plus + vue3

input:在 Input 值改变时触发,参数 (value: string | number)

准确定位当前字符位置,就需要获取光标位置,采用兼容方式

const getPosition=(element)=>{
   let cursorPos = 0;
   if (document.selection) {//IE
        let selectRange = document.selection.createRange();
        selectRange.moveStart('character', -element.value.length);
        cursorPos = selectRange.text.length;
    } else if (element.selectionStart || element.selectionStart == '0') {
        cursorPos = element.selectionStart;
    }
      return cursorPos;
}

textarea改变时调用该事件,整体思路就是先获取光标位置,然后判断输入的是否为@符号,如果输入的是@符号,则判断当前@符号是单数还是双数,双数不需要弹框进行选择字段,如果是单数,则弹框选择字段进行文本拼接,对于没有删除要求的话,到这里就完成了@选择功能了。

删除的时候,我是将所有的@符号的下标组成一个数组,它肯定是成对出现的。因为删除的时候,可能是删除前一个@,也可能删除的是后一个@,所以就需要判断当前删除的@在数组中的下标是单数还是偶数,如果是偶数,就截取的是当前位置及前一个位置之间的字符串,如果是奇数,截取的就是当前位置及后一个位置之间的字符串。使用字符串方法substring + replace

const inputHandle=(val)=>{
      let ipt = document.getElementById('ipt');
      state.textareaStart = getPosition(ipt); //获取光标位置
      getText()
      //出现@符号次数为偶数,则不出现弹框
      state.dialogVisible = state.textareaCount % 2 === 0 ? false : true;
      if(state.textareaArr.length>state.textareaAfter){
        state.textareaAfter=state.textareaArr
      }
     //当前光标位置在原@下标数组中的位置
     let index = state.textareaAfter.indexOf(state.textareaStart);
     if(index !== -1){
        if(index % 2 === 1 ){ //如果下标是奇数,则截取的开始位是它的前一位
          let text = originObj.ruleTextarea.substring(state.textareaAfter[index-1],state.textareaAfter[index]);
          originObj.ruleTextarea = originObj.ruleTextarea.replace(text,'')
        }else{
          //如果下标是偶数,则截取的结束位是它的后一位
          let text = originObj.ruleTextarea.substring(state.textareaAfter[index],state.textareaAfter[index+1]);
          originObj.ruleTextarea = originObj.ruleTextarea.replace(text,'')
        }
        state.dialogVisible = false
      }    
}

获取@符号出现的次数及下标组合数组

const getText = () =>{
   state.textareaAfter=state.textareaArr;
   state.textareaCount=0;
   state.textareaArr=[];
   for (let i = 0; i < originObj.ruleTextarea.length; i++) { //遍历字符串
        if (originObj.ruleTextarea[i] == '@') {
           state.textareaCount++;  //@出现次数
          state.textareaArr.push(i); //@下标组合
        }
    }
}

在光标指定的位置拼接字符串

const selectName = (val) =>{
  state.dialogVisible=false;
  const before = originObj.ruleTextarea.substring(0, state.textareaStart);
  const after = originObj.ruleTextarea.substring(state.textareaStart);
  originObj.ruleTextarea= before + val + '@' + after ;
  getText()
}