uniapp textarea 多行输入严格限制实践:空行、尾换行、最大行数、光标错位全解决

2026-05-02 49 浏览 0 评论

在 uniapp 日常开发中,textarea 多行文本输入是表单场景高频使用的组件。实际业务里,往往会对文本换行格式、整体行数做出强约束,同时还要解决格式化内容后光标强制跳转的痛点问题。本文完整记录 uniapp textarea 从基础格式限制到综合规则落地的全流程开发实践,覆盖开发中遇到的全部问题与完整解决方案。

一、基础需求:文本末尾仅允许 2 个换行

初始需求为文本 末尾仅允许存在 2 个换行符 ,避免用户大量回车输入过多空白尾部内容,保证文本排版整洁。

实现思路:通过 @input 事件监听输入,正则匹配末尾连续换行,超出 2 个则自动截断。

<template>
  <textarea
    v-model="content"
    placeholder="请输入内容"
    @input="handleInput"
  />
</template>

<script>
export default {
  data() {
    return {
      content: ''
    }
  },
  methods: {
    handleInput(val) {
      // 匹配末尾所有连续换行
      const tailNL = val.match(/\n*$/)?.[0] || ''
      if (tailNL.length > 2) {
        // 保留最多 2 个换行
        this.content = val.slice(0, val.length - tailNL.length) + '\n\n'
      } else {
        this.content = val
      }
    }
  }
}
</script>

二、需求升级:中间不允许多余空行

业务要求 文本中间不允许存在多余空行 ,连续多次回车产生的空行需合并为 1 个。

新增规则:中间连续换行符统一替换为单个,结合尾部双换行限制。

handleInput(val) {
  let value = val
  // 中间连续换行 → 只保留 1 个
  value = value.replace(/\n+/g, '\n')
  // 末尾最多保留 2 个换行
  const tail = value.match(/\n*$/)?.[0] || ''
  if (tail.length > 2) {
    value = value.replace(/\n*$/, '\n\n')
  }
  this.content = value
}

三、关键问题:编辑时光标始终跳转到末尾

两套规则叠加后,出现严重交互问题:动态修改内容后, 光标自动跳至文本末尾 ,中间编辑体验极差。

解决方案:记录光标位置 → 格式化文本 → 异步还原光标。

<template>
  <textarea
    ref="textareaRef"
    v-model="content"
    @input="handleInput"
  />
</template>

<script>
export default {
  methods: {
    handleInput() {
      // 记录光标
      const textarea = this.$refs.textareaRef
      const cursorIndex = textarea.cursor

      // 格式化逻辑...
      let formatted = this.content.replace(/\n{2,}/g, '\n')
      formatted = formatted.replace(/\n*$/, '\n\n')

      // 更新内容
      this.content = formatted

      // nextTick 还原光标
      this.$nextTick(() => {
        textarea.cursor = Math.min(cursorIndex, this.content.length)
      })
    }
  }
}
</script>

四、进阶限制:最大行数限制(最多 7 行)

新增需求:文本总行数 限制 7 行 ,超出则恢复上一次合法内容。

实现:缓存历史合法内容,输入时校验行数,超行直接回滚。

data() {
  return {
    content: '',
    lastContent: '', // 上一次合法内容
    maxLine: 7
  }
},
methods: {
  handleInput() {
    const textarea = this.$refs.textareaRef
    const oldCursor = textarea.cursor
    let currentVal = this.content

    // 格式校验
    let formatted = currentVal.replace(/\n{2,}/g, '\n')
    const tail = formatted.match(/\n*$/)?.[0] || ''
    if (tail.length > 2) formatted = formatted.replace(/\n*$/, '\n\n')

    // 行数判断
    const lineCount = formatted.split('\n').length
    if (lineCount > this.maxLine) {
      // 超行 → 恢复历史内容
      this.content = this.lastContent
      this.$nextTick(() => {
        textarea.cursor = Math.min(oldCursor, this.lastContent.length)
      })
      return
    }

    // 正常更新并缓存
    this.lastContent = formatted
    this.content = formatted
    this.$nextTick(() => {
      textarea.cursor = Math.min(oldCursor, this.content.length)
    })
  }
}

五、业务适配:form 表单内的 content 字段

实际项目中,文本字段嵌套在 form 表单内,通过 this.form.content 访问,对方案做最终适配。

最终完整可落地代码

<template>
  <view>
    <textarea
      ref="textareaRef"
      v-model="form.content"
      placeholder="最多 7 行,中间无空行,末尾 2 个换行"
      @input="handleInput"
      style="height: 400rpx; width: 100%;"
    />
  </view>
</template>

<script>
export default {
  data() {
    return {
      form: {
        content: '' // form 内字段
      },
      lastContent: '',
      maxLine: 7
    }
  },
  methods: {
    handleInput() {
      const textarea = this.$refs.textareaRef
      const oldCursor = textarea.cursor
      let currentVal = this.form.content

      // 1. 中间连续空行合并
      let formatted = currentVal.replace(/\n{2,}/g, '\n')
      // 2. 末尾最多 2 个换行
      const tailMatch = formatted.match(/\n*$/)
      const tailLen = tailMatch ? tailMatch[0].length : 0
      if (tailLen > 2) formatted = formatted.replace(/\n*$/, '\n\n')

      // 3. 行数校验
      const lineCount = formatted.split('\n').length
      if (lineCount > this.maxLine) {
        this.form.content = this.lastContent
        this.$nextTick(() => {
          textarea.cursor = Math.min(oldCursor, this.lastContent.length)
        })
        return
      }

      // 4. 更新合法内容
      if (formatted === this.form.content) return
      this.lastContent = formatted
      this.form.content = formatted

      // 5. 还原光标
      this.$nextTick(() => {
        textarea.cursor = Math.min(oldCursor, this.form.content.length)
      })
    }
  }
}
</script>

六、方案总结

最终实现全部业务规则与交互优化:

  1. 中间文本:禁止连续空行,仅保留单行换行
  2. 文本尾部:最多保留 2 个换行符
  3. 总行数:严格限制 7 行,超行自动回滚
  4. 交互体验:任意位置编辑,光标不跳转
  5. 场景适配:完美兼容 form 表单数据结构
  6. 多端支持:小程序、H5、App 全端稳定运行

整套方案从基础格式约束,到交互问题修复,再到业务场景适配,完整覆盖 uniapp textarea 多行输入的全部开发痛点,可直接用于生产环境表单开发。


发布评论

发布评论前请先 登录
取消
0 评论
点赞
收藏

评论列表 0

暂无评论