最近接到一个需求(Vue2+elmentUI项目),要做一个如下图的公式input框。该input框需要支持插入文本,且只能出现图中红框圈出来的文本。

经过一番考量和商量,将上述需求分解为以下两大功能点实现。
一、input框做特殊处理:只允许插入,不允许输入,但支持键盘删除
支持键盘删除这点,就决定了不能用el-input组件自带的disabled和readonly属性来实现input不允许输入的需求。
那么怎么实现不允许输入但支持键盘删除这个需求呢?
方案一:
el-input组件绑定值用value写法,然后在input事件中进行判断,只有绑定值大于回调参数value时,才将回调参数value的值赋值给绑定值,具体代码如下:
js
<el-input
:value="item.indexFormulasDesc"
placeholder=""
clearable
@input="(value)=>{
if(item.indexFormulasDesc.length > value.length) {
item.indexFormulasDesc = value
}"
></el-input>
一开始,我用的就是这个方法,后来在测试过程中发现,用back键(退格键)进行删除时,只能从最后一个字符开始删,如果移动光标从文本中间删,则无法删除,光标自动跳到文本的结尾。
起初,以为是光标定位出了问题,然后各种排查解决,但问题依然存在,后来 经过一番探索,发现是back键删除时,el-input组件中的value属性绑定值item.indexFormulasDesc
与input方法中的回调参数value的值不能同步造成的。
于是,又开始尝试让value属性绑定值与input方法中的回调参数value的值同步,但多方尝试无果后,探索出了下面的方案二。
方案二:
将el-input组件的maxlength属性的值设置为0,其绑定值采用v-model的写法。具体代码如下:
js
<el-input
v-model="item.indexFormulasDesc"
placeholder=""
clearable
maxlength="0"
></el-input>
此方法可完美实现需求,而不会发生退格键删除问题。
二、根据光标进行定位,将文本插入到想要插入的地方
要实现这一点,需要经历两步。
第一步:定义一个变量inputIndex,在el-input组件blur事件中,将当前光标所在的input框的index赋值给变量inputIndex。
在后续插入操作中,我们可以根据变量inputIndex的值,知道我们当前要操作的是哪一个input框。
js
<div
v-for="(item,index) in indexFormulasListOne"
:key="index"
class="index-Formulas-item"
>
<div style="flex: 1;display: flex;align-items: center;">
<span>{{ index + 1 }}.</span>
<el-input
:id="`inputRef${index}`"
v-model="item.indexFormulasDesc"
placeholder=""
maxlength="0"
clearable
@blur="(e)=>{
// 关键代码
inputIndex = index
}"
></el-input>
</div>
<div class="del-icon" v-if="indexFormulasListOne&&indexFormulasListOne.length > 1">
<svg-icon icon-class="delete" class="del-ic" @click="handleDelFormulas('one',index)" />
</div>
</div>
第二步:封装插入文本的公共方法,在需要的地方调用,最终实现根据光标位置插入指定文本的需求,具体代码如下:
js
/** 在光标前插入文本
* id:input绑定的id,
* insertTxt:要插入的文本
*/
insertInputTxt(id, insertTxt) {
// 获取dom:此处用id的方法获取dom,也可用ref的方法获取dom
const elInput = document.getElementById(id);
// 获取光标开始位置
const startPos = elInput&&elInput.selectionStart;
// 获取光标结束位置
const endPos = elInput&&elInput.selectionEnd;
if ( !(startPos || startPos === 0) || !(endPos || endPos === 0)) return;
const txt = this.indexFormulasListOne[this.inputIndex].indexFormulasDesc;
//在光标前插入文本
const result = txt.substring(0, startPos) + insertTxt + txt.substring(endPos);
//对应input框出现插入的文本
this.indexFormulasListOne[this.inputIndex].indexFormulasDesc = result;
//文本插入后,光标重新聚焦
elInput.focus();
elInput.selectionStart = startPos + insertTxt.length;
elInput.selectionEnd = startPos + insertTxt.length;
},
至此,需求成功实现。