基于vue3实现一个简单的输入框效果

 更新时间:2024年03月01日 11:28:51   作者:赵小川  
这篇文章主要为大家详细介绍了如何使用Vue3实现一个简单的输入框,可以实现输入文字,添加表情等功能,感兴趣的小伙伴可以跟随小编一起学习一下

需求背景

需要一个输入框,可以输入文字,添加表情,一开始用了富文本编辑器,有点大材小用,所以自己封装一个输入框组件。支持输入文字,选择表情/插入表情,支持组合键换行,使用enter 进行提交

效果图

技术实现

  • 通过原生textarea实现
  • 通过 v-model 来实现 父子组件的数据传递,子组件监听数据的变化,向外emit('update:modelValue', inputValue),保证父组件能更新绑定的值
  • 每次插入时,需要重新聚焦,更新光标位置
  • 通过向外 暴露的 (__insertText),来实现插入表情/文字
  • 通过向外暴露的(_clear) 输入完毕发送后,需要clear 掉输入框的内容
  • 通过向外暴露的(__isEmpty) 来判断是否有内容,如果没内容,做按钮的禁用状态(当然也可以直接用父组件绑定的值)
  • 父组件通过ref 就可以调用以上方法,来做操作。比如发送完数据,调clear清空内容,如果输入框没有内容,则调用isEmpty,做按钮的一些状态

代码实现(子组件)

/**
 * 自定义文本输入框组件
 */

import { ref, watch } from 'vue'
import { ElInput } from 'element-plus'

export default defineComponent({
  props: {
    modelValue: {
      type: String,
      default: ''
    }
  },
  emits: ['update:modelValue', 'chatSend'],
  setup(props, { emit, expose }) {
    const { t } = useI18n()
    const editorRef = ref()
    const disabled = ref(false)
    const valueHtml = ref(props.modelValue)
    const currentEvent = ref()
    watch(
      () => valueHtml.value,
      () => {
        emit('update:modelValue', valueHtml.value)
      }
    )

    // 插入元素
    const _insertText = async (msg: string) => {
      const msgLength = msg.length
      const editor = currentEvent.value
      if (editor) {
        const startPos = editor.selectionStart
        valueHtml.value = `${valueHtml.value.substring(0, startPos)}${'' + msg}${valueHtml.value.substring(startPos)}`
        _focus()
        nextTick(() => {
        // 此处是 根据元素的长度,来设置光标位置
          editor.setSelectionRange(startPos + msgLength, startPos + msgLength)
        })
      }
    }

    // focus
    const _focus = () => {
      editorRef.value && editorRef.value.focus()
    }

    // 清空编辑器
    const _clear = () => {
      editorRef.value && editorRef.value.clear()
    }

    // 是否内容为空
    const _isEmpty = () => {
      const str = valueHtml.value.trim().replace(/\n/g, '')
      return str === '' || str.length == 0 || typeof str === 'undefined'
    }

    // 禁用编辑器
    const _disable = () => {
      disabled.value = true
    }

    // 解除禁用编辑器
    const _enable = () => {
      disabled.value = false
    }

    const handleKeyDown = (event: KeyboardEvent) => {
      currentEvent.value = event.target as HTMLInputElement
      // 定义组合键 Map
      const shortCutKeys: (keyof KeyboardEvent)[] = ['metaKey', 'altKey', 'ctrlKey', 'shiftKey']
      const isEnterKey = event.code === 'Enter'
      const isShortcutKeys = shortCutKeys.some((item) => event[item])
      if (isEnterKey && isShortcutKeys) {
        // 获取光标位置
        const cursorPosition = currentEvent.value.selectionStart

        // 拆分成两段文本
        const textBeforeCursor = valueHtml.value.slice(0, cursorPosition)
        const textAfterCursor = valueHtml.value.slice(cursorPosition)

        // 合并为带有换行符的新文本
        const newText = textBeforeCursor + '\n' + textAfterCursor

        // 更新输入框的值
        valueHtml.value = newText
        // 文本编辑器的高度发生变化后
        nextTick(() => {
          // 高度变化 自动滚动到底部
          const editor = editorRef.value.textarea
          editorRef.value.textarea.scrollTop = editor.scrollHeight
          // 设置光标位置为: start 和 end 相同,光标会移动到换行符后面的新行首
          currentEvent.value.setSelectionRange(cursorPosition + 1, cursorPosition + 1)
        })
      } else if (event.code === 'Enter') {
        // 阻止掉 Enter 的默认换行行为
        event.preventDefault()
        emit('chatSend')
      }
    }
    // 向外暴露方法
    expose({
      _insertText,
      _clear,
      _disable,
      _isEmpty,
      _enable,
      _focus
    })
    return () => (
      <div class="chatEditor">
        <ElInput
          ref={editorRef}
          v-model={valueHtml.value}
          type="textarea"
          disabled={disabled.value}
          onKeydown={handleKeyDown}
        />
      </div>
    )
  }
})

代码实现(父组件调用)

输入框组件

<base-editor
        ref="chatEditorRef"
        v-model="inputText"
        @chat-send="sendText"
 ></base-editor>

工具栏组件

<ChatTools :chat-tools-list="newChatToolsList" @get-emoji="getToolsMsg" />

当我们点击工具栏组件,就会获取到工具栏的文字/表情/或者插入的xxx ,此时根据引用,调用输入框的暴露出的_insertText方法,直接就插入进去

const getToolsMsg = async (msg: string) => {
  chatEditorRef.value._insertText(msg)
}

其他方法调用

_isEmpty(): 未输入,按钮是禁用状态

 <el-button :disabled="chatEditorRef?._isEmpty()" type="primary" @click="sendText">

当然你也可以直接使用绑定的输入框的变量去判断

<el-button :disabled="!inputText" @click="sendText">

_clear(): 提交完请求,清空输入框

chatEditorRef.value._clear()

关于插入的问题

光标位置的获取,根据元素插入位置,光标换行,支持快捷键等。可以参考上一篇文章:vue3通过组合键实现换行操作的示例详解

总结

  • 原生其实也可以实现,没必要用一个很重的富文本编辑器
  • 做表情插入,或者其他插入,都是工具栏,和输入框组件的关系是兄弟组件的关系,兄弟组件之间,怎么做数据传递,事件传递,怎么设计?

(1) 父组件作为中介

(2)事件总线通过订阅/发布做消息通知

(3)仓库vuex/pina

事件总线还是能不用就不用,因为全局性的东西,用着爽,后面复杂了,就乱了。而且 事件总线是发布订阅,你还得注意销毁,存仓库 又不太合适,子组件自己暴露出方法,让其他组件调用,感觉目前是最简单的方式了。

到此这篇关于基于vue3实现一个简单的输入框效果的文章就介绍到这了,更多相关vue3输入框内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • npm安装vue@cli报错的简单处理方式

    npm安装vue@cli报错的简单处理方式

    最近工作中遇到了报错,现在将解决的办法分享给大家,下面这篇文章主要给大家介绍了关于npm安装vue@cli报错的简单处理方式,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • Vue2 响应式系统之分支切换

    Vue2 响应式系统之分支切换

    这篇文章主要介绍了Vue2 响应式系统之分支切换,文章围绕Vue2的相关资料展开主题详细内容,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-04-04
  • vue3 setup点击跳转页面的实现示例

    vue3 setup点击跳转页面的实现示例

    本文主要介绍了vue3 setup点击跳转页面的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-10-10
  • vue非父子组件通信问题及解决方法

    vue非父子组件通信问题及解决方法

    这篇文章主要介绍了vue非父子组件通信问题及解决方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-06-06
  • Vue实现动态圆环百分比进度条

    Vue实现动态圆环百分比进度条

    这篇文章主要为大家详细介绍了Vue实现动态圆环百分比进度条,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • vue组件三大核心概念图文详解

    vue组件三大核心概念图文详解

    本文主要介绍属性、事件和插槽这三个vue基础概念、使用方法及其容易被忽略的一些重要细节,感兴趣的朋友跟随小编一起看看吧
    2019-05-05
  • 浅析vue cli3 封装Svgicon组件正确姿势(推荐)

    浅析vue cli3 封装Svgicon组件正确姿势(推荐)

    这篇文章主要介绍了vue cli3 封装Svgicon组件正确姿势,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • 使用Karma做vue组件单元测试的实现

    使用Karma做vue组件单元测试的实现

    这篇文章主要介绍了使用Karma做vue组件单元测试的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • element ui表格实现下拉筛选功能

    element ui表格实现下拉筛选功能

    这篇文章主要为大家详细介绍了element ui表格实现下拉筛选功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • vue实现PC端录音功能的实例代码

    vue实现PC端录音功能的实例代码

    这篇文章主要介绍了vue实现PC端录音功能的实例代码,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-06-06

最新评论