Vue中使用contenteditable属性撸一个可以自动手动换行的输入框

写在前面

有时候页面上需要一个类似于微信中发送消息的输入框,即可以实现:默认只有一行文字高度,用户输入超过自动换行,用户也可以点击Enter键盘换行,当输入的内容清空后,输入框又恢复成一行的高度,原生的输入框input和文本框textarea无法实现以上功能,所以就自己写了一个,采用HTML5的contenteditable属性,可以完美实现:
1、自动换行及手动换行;
2、双向绑定;
3、类似于textarea中的rows属性;
4、maxlength属性;
5、placeholder属性

复制代码到Vue项目中即可预览

效果图

Vue中使用contenteditable属性撸一个可以自动手动换行的输入框_第1张图片

子组件代码

<template>
  <div class="textarea-wrap">
    <div
      class="mTextarea"
      ref='mTextarea'
      @input="input"
      :style="style"
      contenteditable="true"
      :placeholder="placeholder"
    ></div>
  </div>
</template>
<script>
  export default {
    props: {
      // 输入提示,非必传
      placeholder: String,
      // 最大字数,非必传
      maxlength: {
        type: Number,
        default: 99999
      },
      // 行数,非必传
      rows: {
        type: Number,
        default: 6
      },
      // 字体大小,非必传
      fontSize: {
        type: Number,
        default: 28
      },
      // 行高,非必传
      lineHeight: {
        type: Number,
        default: 1.4
      },
      // 值,必传
      value: String
    },
    computed: {
      style () {
        return {
          fontSize: this.fontSize / 75 + 'rem',
          lineHeight: this.lineHeight,
          maxHeight: this.rows * this.fontSize / 75 * this.lineHeight + 'rem'
        }
      }
    },
    data () {
      return {
        mTextarea: null
      }
    },
    watch: {
      value () {
        // 清空
        if (!this.value) {
          this.mTextarea.innerText = ''
        }
      }
    },
    mounted () {
      this.$nextTick(() => {
        this.mTextarea = this.$refs.mTextarea
        // 回显
        this.mTextarea.innerText = this.value
      })
    },
    methods: {
      input (event) {
        let innerText = this.mTextarea.innerText
        // 限制输入
        if (innerText.length >= this.maxlength) {
          innerText = innerText.substring(0, this.maxlength)
          this.mTextarea.innerText = innerText
          // 设置光标到最后
          this.setFocus()
        }
        if (this.mTextarea.innerText.length === 1 && this.mTextarea.innerHTML.includes('br')) {
          this.mTextarea.innerText = ''
          innerText = ''
        }
        this.$emit('input', innerText)
      },
      // 设置光标到最后
      setFocus () {
        var selection = window.getSelection()
        var range = document.createRange()
        range.selectNodeContents(this.mTextarea)
        range.collapse(false)
        selection.removeAllRanges()
        selection.addRange(range)
      }
    }
  }
</script>
<style lang="less" scoped>
  .textarea-wrap{
    background: #f8f8f8;;
    padding: 24/75rem;
    border-radius: 2px;
    font-size: 0;
    &:active{
      background: #eee;
    }
    .mTextarea{
      width: 100%;
      display: inline-block;
      outline: none;
      overflow: auto;
      // 加了可实现纯textarea功能,不加则像富文本一样可以写入css样式和HTML标签
      user-modify: read-write-plaintext-only;   
      -webkit-user-modify: read-write-plaintext-only;
      // 必须加,不然移动端有些浏览器无光标
      user-select: auto;
      -webkit-user-select: auto;
      // placeholder属性
      &:empty:before{
        content:attr(placeholder);
        font-size: 28/75rem;
        color: #999;
      }
    }
  }
</style>


父组件调用代码

<template>
  <div class="wrap">
    <m-textarea v-model="value" placeholder='请输入评论' :rows='6' :maxlength='200'/>
    <p>输入的内容:{{value}}</p>
    <button @click="value = ''">清空</button>
  </div>
</template>
<script>
  import MTextarea from './MTextarea'
  export default {
    components: {
      MTextarea
    },
    data () {
      return {
        value: ''
      }
    }
  }
</script>
<style lang="less" scoped>
	// 可删除
  .wrap{
    background: #fff;
    padding: 30/75rem;
    p{
      padding: 30/75rem 0;
      font-size: 30/75rem;;
      line-height: 1.4;
    }
    button{
      padding:12/75rem 20/75rem;
      background: #ff6633;
      color: #fff;
      font-size: 26/75rem;
      border-radius: 4px;
    }
  }
</style>


觉得有用就给我点个赞吧,蟹蟹,(●ˇ∀ˇ●)
个人联系方式(添加请备注):
QQ:332983810
微信:hu_jiliang

你可能感兴趣的:(Vue组件分享,CSS样式)