实现一个可以实时提示的textarea

Posted ฅ˙-˙ฅ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现一个可以实时提示的textarea相关的知识,希望对你有一定的参考价值。

该组件输入、换行、变换光标可以实时给出提示

效果: 

textarea.vue

<template>
  <div>
    <el-input
      id="user-input"
      type="textarea" 
      placeholder="请换行输入不同的通知用户" 
      :autosize="{minRows: 2, maxRows: 10}" 
      v-model="inputValue" 
      @blur="closeHint"
      @input="settingHint"
      @click.native="settingHint"
      @keyup.native="disposeKey">
    </el-input>
    <input-hint 
      :all-items="hintItems" 
      :position = \'hintPosition\'
      @select = "replaceStr"
    ></input-hint>
  </div>
</template>

<script lang="ts">
import { Vue, Component, Prop } from "vue-property-decorator";
import InputHint from "./inputHint.vue";
import $ from "jquery";

@Component({
  components: {
    InputHint
  }
})
export default class AdvancedTextarea extends Vue {
  inputValue: string = \'\';
  Seprator = "\\n";
  allUsers: string[] = [];
  hintItems: string[] = []; //传入提示框的项,可以是html字符串;为空则表示不显示提示框
  initPosition = { //输入框的信息,用于计算提示框位置
    left: 15,
    top: 5,
    rowHeight: 20,  //一行的高度
    fontSize: 7  //一个字的宽度
  }
  hintPosition = {
    left: this.initPosition.left,
    top: this.initPosition.top
  }

  //按上下左右键时,重置提示框
  disposeKey(e) {
    if (e.keyCode === 37 || e.keyCode === 38 || e.keyCode === 39 || e.keyCode === 40) {
      this.settingHint();
    }
  }

  settingHint(val?) {
    let cursorLocation = $(\'#user-input\').caret(); //光标位置
    let newStr = this.inputValue.slice(0, cursorLocation);  //输入框光标前的字符
    let newArr = newStr.split(this.Seprator);
    let searchKey = newArr.length === 0 ? "" : newArr[newArr.length - 1];
    let regExp = new RegExp(searchKey, \'ig\');
    this.hintItems = searchKey ?
      this.allUsers.filter(item => item.indexOf(searchKey) !== -1).map(item => item.replace(regExp, `<strong>${searchKey}</strong>`)) :
      this.allUsers;
    this.hintPosition.left = this.initPosition.left + this.initPosition.fontSize * (searchKey.length > 0 ? searchKey.length - 1 : 0);
    this.hintPosition.top = this.initPosition.top + this.initPosition.rowHeight * (newArr.length > 10 ? 10 : newArr.length);
  }

  closeHint() {
    //延后关闭是因为立即关闭的话,点击提示框内容就无法触发点击事件
    window.setTimeout(() => {
      this.hintItems = null;
      window.clearTimeout();
    }, 200);

  }

  //将光标当前值替换为选中值
  replaceStr(val) {
    let cursorLocation = $(\'#user-input\').caret(); //光标位置
    let newStr = this.inputValue.slice(0, cursorLocation);  //输入框光标前的字符
    let row = newStr.split(this.Seprator).length - 1;  //光标所在行
    let oriArr = this.inputValue.split(this.Seprator);
    oriArr[row] = val;
    this.inputValue = oriArr.join(this.Seprator);
    $(\'#user-input\').focus();
  }

  getAllUsers() {
    this.allUsers = [
      \'xiaoming@qq.com\',
      \'daming@163.com\',
      \'liuxioawei@gridsum.com\',
      \'432454354@qq.com\',
      \'zhangzheng@qq.com\',
      \'mostlove@163.com\',
      \'wangweihao@gridsum.com\',
      \'67900332@qq.com\',
      \'xiaosi@qq.com\',
      \'loveshuang@163.com\',
      \'liuxioawei@gridsum.com\',
      \'87456563@qq.com\',
      \'yaru@qq.com\',
      \'wuyuetian@163.com\',
      \'junjun@gridsum.com\',
      \'67576889@qq.com\',
      \'shuanger@qq.com\',
      \'she@163.com\',
      \'ruiji@gridsum.com\',
      \'45454334@qq.com\',
    ]
  }

  mounted() {
    if (this.allUsers.length === 0) {
      this.getAllUsers();
    }
  }
}

</script>
View Code

 

inputHint.vue

<template>
  <div v-show="allItems&&allItems.length!==0">
    <ul class="el-dropdown-menu el-popper max-height new-scoll-bar" :style="{left: position.left+\'px\', top: position.top+\'px\'}">
        <li class="el-dropdown-menu__item" v-for="(item,index) in allItems" :key="index" v-html="item" @click="selectItem(item)"></li>
    </ul>
  </div>
</template>

<style lang="postcss" scoped>
.max-height {
  max-height: 250px;
  overflow-y: auto;
}
</style>

<script lang="ts">
import { Vue, Component } from "vue-property-decorator";

@Component({
  props: {
    allItems: {
      type: Array,
      default: []
    },
    position: {
      type: Object,
      default: {
        left: 0,
        top: 0
      }
    }
  }
})

export default class InputHint extends Vue {
  allItems = this.allItems;
  selectItem(item: string) {
    let regExp = /<strong>|<\\/strong>/g;
    let str = item.replace(regExp, \'\');
    this.$emit(\'select\', str)
  }
}
</script>
View Code

 

以上是关于实现一个可以实时提示的textarea的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 实现textarea限制输入字数, 输入框字数实时统计更新,输入框实时字数计算移动端bug解决

将代码片段插入数据库并在 textarea 中以相同方式显示

代码片段如何使用CSS来快速定义多彩光标

前端页面实现报警器提示音效果

兼顾pc和移动端的textarea字数监控的实现方法

兼顾pc和移动端的textarea字数监控的实现方法