实现一个可以实时提示的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 = [
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
      '[email protected]',
    ]
  }

  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

猜你喜欢

转载自www.cnblogs.com/XHappyness/p/9264574.html