Vue病历写回功能:实现多输入框内容插入与焦点管理🚀

本文将介绍如何实现一个高效、用户友好的病历写回功能,支持多输入框内容插入与焦点管理。该解决方案已在医疗系统中广泛应用,可大幅提升医生书写病历的效率。

实现效果如下

痛点分析与解决方案

医疗系统常见痛点

  • 🚫 焦点迷失:在多个输入区域(主诉、现病史、体格检查等)间切换时容易失去位置
  • 🔁 重复输入:常见症状描述和诊断结论需要反复输入
  • 效率低下:医疗工作者需要花费大量的时间去完成病例写回工作

我们的创新解决方案

  • 智能焦点追踪:自动记录当前和最后激活的输入框
  • 模板快速插入:一键插入预设模板内容
  • 🎯 光标精确定位:确保插入内容后光标位置正确
  • 💡 可视化状态:实时显示当前激活区域

核心实现代码解析

一、关键变量解析 🧠

js 复制代码
const activeInput: Ref<InputElement | null> = ref(null)       // 当前获得焦点的输入框
const lastActiveInput: Ref<InputElement | null> = ref(null)   // 最后获得焦点的输入框(用于恢复)
const registerEls: Ref<InputElement[]> = ref([])              // 所有注册的输入框实例

二. 核心方法解析 ✨

1. registerInput(el: InputElement)

  • 功能:注册输入框并绑定事件监听

  • 绑定事件

    • mousedown/focus → 触发 handleFocus 记录活跃输入框
    • blur → 触发 handleBlur 清除当前焦点
  • 存储 :将元素添加到注册列表 registerEls

2. insertContent(content: string)

  • 插入逻辑

    1. 优先使用 activeInput,若不存在则使用 lastActiveInput
    2. 若无有效输入框 → 显示警告提示
    3. 尝试获取焦点 → 计算光标位置
    4. 在光标处插入内容 → 更新光标位置
    5. 触发 input 事件通知Vue更新数据
  • 关键技术点

    js 复制代码
    // 在光标位置插入内容
    target.value = 
      target.value.slice(0, start) + 
      content + 
      target.value.slice(end)
    
    // 设置新光标位置
    target.setSelectionRange(newPos, newPos)
    
    // 触发数据绑定更新
    target.dispatchEvent(new Event('input', { bubbles: true }))

3. cleanup()

  • 资源清理

    • 移除所有注册元素的事件监听
    • 重置所有响应式变量
  • 使用场景:组件卸载时调用防止内存泄漏

4. 事件处理函数

js 复制代码
function handleFocus(e: Event) {
  const target = e.target as InputElement
  activeInput.value = target       // 更新当前焦点
  lastActiveInput.value = target   // 更新最后焦点备份
}

function handleBlur() {
  activeInput.value = null         // 清除当前焦点
}

三、工作流程 🔧

四、设计特点 🌟

  1. 双重焦点备份activeInput + lastActiveInput 确保即使输入框失焦也能定位
  2. 自动数据同步 :通过派发 input 事件触发Vue数据绑定更新
  3. 安全恢复机制 :插入前尝试 target.focus() 恢复焦点
  4. 内存管理:提供显式清理接口避免内存泄漏

五、使用场景示例

js 复制代码
<script setup lang="ts">
import { cleanup, insertContent, registerInput } from '../hooks/useWriteBackHistory'

const dialogVisible = ref(false)

function onCancel() {
  dialogVisible.value = false
  cleanup()
}

const content = ref('你很好,你很优秀,你是最棒的!')
function onload() {
  insertContent(content.value)
}
const formInline = reactive({
  user: '',
  region: '',
})
/**
 * @description 写回病历-注册
 * @param el
 */
function setInputRef(el: any) {
  if (el && el.$el) {
    registerInput(el.$el)
  }
}
</script>

<template>
  <el-dialog
    v-model="dialogVisible"
    title="Tips"
    width="800"
  >
    <el-form :inline="true" :model="formInline" class="demo-form-inline">
      <el-form-item label="主诉">
        <el-input :ref="setInputRef" v-model="formInline.user" placeholder="主诉" clearable type="textarea" />
      </el-form-item>

      <el-form-item label="诊断">
        <el-input :ref="setInputRef" v-model="formInline.user" placeholder="诊断" clearable type="textarea" />
      </el-form-item>
    </el-form>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="onCancel">
          取消
        </el-button>
        <el-button type="primary" @click="onload">
          写回病例
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<style scoped lang="scss">

</style>

六、潜在问题及改进

  1. 移动端兼容性mousedown 事件在移动端可能需要替换为 touchstart
  2. 多实例冲突:全局变量在多个组件实例中使用时可能相互干扰
  3. 性能优化:大量输入框注册时考虑弱引用(WeakRef)管理
  4. 富文本支持:当前仅支持原生输入框,如需富文本编辑器需扩展

技术创造价值,代码改善生活 - 通过前端技术创新,我们可以为医疗行业带来真正的变革

欢迎在评论区交流你的想法和实践经验!

相关推荐
一斤代码2 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子2 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年2 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子2 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina2 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路3 小时前
React--Fiber 架构
前端·react.js·架构
伍哥的传说4 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409194 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app
我在北京coding4 小时前
element el-table渲染二维对象数组
前端·javascript·vue.js
布兰妮甜4 小时前
Vue+ElementUI聊天室开发指南
前端·javascript·vue.js·elementui