文本域点击按钮在光标处追加文字

466 阅读3分钟

demo主要实现点击按钮在文本域中添加文字。通过 js 代码和 vue2 的两种方式分别实现。

简单分析一下

点击按钮在光标处追加文字,这就涉及到一个哲学问题了:把大象放入冰箱拢共要分几步:

  1. 点击按钮;
  2. 获取光标位置;
  3. 插入字符串。

点击按钮

Js 中使用 onclick="函数名(形式参数)" 的形式去绑定一个点击事件,或者获取到按钮的 dom节点,使用 addEventListener("click", 回调函数) 去绑定一个事件。

Vue 中就是 v-on:click="函数名(形式参数)" 或者 @click="函数名(形式参数)"

获取光标位置

Textarea 文本域对象中有两个属性,分别是 selectionStartselectionEnd

selectionStartselectionEnd 是HTMLInputElement接口的两个属性,分别表示所选文本的开始索引和结束索引。当没有选择文本时,也就是只有闪烁光标的时候,两个值会返回相同的数字表示当前文本输入光标位置的字符的偏移量。

image.png

在上面的文本框中,光标在第五个字符的后面,所以它的 selectionStartselectionEnd 的值都是 5

image.png

在第一个位置的时候,它的值就是 0

当我们选取一些字符的时候,selectionStartselectionEnd 表示选择范围的开始位置和结束位置:

image.png

选取部分开始于第2个字符的位置,结束于第5个字符的位置,即 selectionStart 的值是 2, selectionEnd 的值是 5

插入字符串

插入字符串通常(我知道的)有两种方法:

  1. 转换成数组插入
    function insertStr(str, index, insertStr) {
       const arr = str.split("");
       arr.splice(index, 0, insertStr)
       return arr.join("")
    }
    
    上面示例中,先将字符串拆分成由每个字符组成的数组,然后再使用 splice 方法在对应的位置插入相应的字符。但是如果想要满足两个参数 selectionStartselectionEnd,可能需要修改一下上面的代码:
    function insertStr(str, insertStr, textarea) {
       const arr = str.split('');
       arr.splice(
         textarea.selectionStart,
         textarea.selectionEnd - textarea.selectionStart,
         insertStr
       );
       return arr.join('');
    }
    
    上面示例中,textarea 表示文本域对象,我们只需要里面的 selectionStartselectionEnd 两个属性。
  2. 使用substring插入 substring 我们就直接使用需要的版本:
    function insertStr(str, insertStr, textarea) {
       const startStr = str.substring(0, textarea.selectionStart);
       const endStr = str.substring(textarea.selectionEnd);
       return `${startStr}${insertStr}${endStr}`;
    }
    

这样的两种方式都可以实现在选中或光标位置进行字符串插入。下面我们直接装大象:

JavaScript 版本

<div class="box">
  <div class="btnbox">
    <button onclick="clickAdd(event)" class="btn">a</button>
    <button onclick="clickAdd(event)" class="btn">b</button>
    <button onclick="clickAdd(event)" class="btn">c</button>
    <button onclick="clickAdd(event)" class="btn">d</button>
  </div>
  <br>
  <div>
    <input id="add" type="text"> <button onclick="inputAdd(event)">点击添加</button>
  </div>
  <br>
  <textarea name="" id="input" rows="10" cols="90"></textarea>
</div>
body {
  background: transparent; /* Make it white if you need */
  color: #fcbe24;
  padding: 0 24px;
  margin: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
const textarea = document.getElementById("input")
const input = document.getElementById("add")

function clickAdd(event) {
  let text = event.target.innerText
  const lastSelection = textarea.selectionStart
  textarea.value = insertStr(textarea.value, text, textarea)
  textarea.focus()
  textarea.selectionStart = lastSelection + text.length
  textarea.selectionEnd = textarea.selectionStart
}

function inputAdd() {
  let text = input.value
  const lastSelection = textarea.selectionStart
  textarea.value = insertStr(textarea.value, text, textarea)
  textarea.focus()
  textarea.selectionStart = lastSelection + text.length
  textarea.selectionEnd = textarea.selectionStart
}

function insertStr(str, insertStr, textarea) {
  const startStr = str.substring(0, textarea.selectionStart);
  const endStr = str.substring(textarea.selectionEnd);
  return `${startStr}${insertStr}${endStr}`;
}

Vue2.x 版本

<template>
  <div class="box">
    <div class="btnbox">
      <button @click="clickAdd($event)">a</button>
      <button @click="clickAdd($event)">b</button>
      <button @click="clickAdd($event)">c</button>
      <button @click="clickAdd($event)">d</button>
    </div>
    <br />
    <div>
      <input id="add" v-model="addStr" type="text" />
      <button @click="inputAdd()">点击添加</button>
    </div>
    <br />
    <textarea ref="textarea" v-model="message" rows="10" cols="90"></textarea>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: "",
      addStr: "",
    };
  },
  methods: {
    clickAdd(event) {
      let text = event.target.innerText;
      this.changeStr(text);
    },

    inputAdd() {
      let text = this.addStr;
      this.changeStr(text);
    },

    insertStr(str, insertStr, textarea) {
      const startStr = str.substring(0, textarea.selectionStart);
      const endStr = str.substring(textarea.selectionEnd);
      return `${startStr}${insertStr}${endStr}`;
    },

    changeStr(text) {
      const textarea = this.$refs["textarea"];
      const lastSelection = textarea.selectionStart;
      this.message = this.insertStr(this.message, text, textarea);
      textarea.focus();
      this.$nextTick(() => {
        textarea.selectionStart = lastSelection + text.length;
        textarea.selectionEnd = textarea.selectionStart;
      });
    },
  },
};
</script>

<style>
body {
  background: transparent; /* Make it white if you need */
  color: #fcbe24;
  padding: 0 24px;
  margin: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
</style>

效果展示

image.png 直接点击按钮在下方文本域中插入字符,以及在输入框中输入,点击添加按钮,讲字符添加到光标处。也可以选中一段文字进行替换添加。

本章最后

上述内容如果有任何问题和错误,希望大佬们可以指出。如果代码上有任何问题或可以优化的点也可以在评论区讨论。

希望可以帮到大家~~~