基于vue3实现一个简单的输入框效果
作者:赵小川
这篇文章主要为大家详细介绍了如何使用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输入框内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!