技术方案,场景问题

📅 发布时间:2026/8/31 7:37:34
技术方案,场景问题
“场景 -猜测 - 解法 - 原理”目录技术方案便捷/条件/连续运行 命令脚本文件预览嵌入任意页面富文本编辑嵌入式控件自由文本”混排组件填空 vs dom contenteditablesdk与业务分工登录场景问题快速消失的需要录屏如闪动滚动卡住、穿透、冲突等504安装卡住频繁崩溃闪退初始无响应时序竞态「多端链路 无业务代码变更」怀疑版本/App 包打包发布不生效线上样式覆盖UI闪动消失transtion【待补充 思考链】宽高auto -具体值低版本IOS持久化iframe或第三方嵌入网页keep-alive只缓存 Vue 组件实例和其虚拟 DOM 树不是浏览器里 iframe 的“运行进程”选区可见溢出、布局不溢出下载进度条完成但下载失败可能就是路径无效window专属转义js强行换行打断输入法乱码若刚更新了mac系统重启应用时间不对控制台new Date快捷键1.是点击图标 还是 快捷键2.单个有效预览图片窗口打不开多次点击只剩下预览窗口防抖移动端并发请求 只有尾请求生效JSbridgeAndroid JSbridge无效url透传参数只适合参数内容/形式可控window.open打开链接没反应系统没有设置默认浏览器技术方案便捷/条件/连续运行 命令脚本文件预览嵌入任意页面背景文件预览需安全渲染任意HTML方案Shadow DOM非iframe必须显式建立通道开销也大联系video、input等元素内部结构不可见代价调试困难、字体不继承、SSR不支持验证CSS隔离✅ / 脚本安全✅ / 跨框架✅复用适用于任何需要渲染不可信html的场景方案选择iframeShadow DOM样式控制完全隔离但笨重原生隔离且灵活性能独立进程开销大同一进程开销小集成度明显的“框内框”无缝融入页面通信必须显式建立通道可通过事件冒泡composed: true隔离的实现机制选择器重写浏览器会自动重写 Shadow DOM 内的选择器使其作用域化样式表隔离每个 Shadow DOM 有独立的样式表集合渲染边界形成独立的渲染树分支富文本编辑嵌入式控件自由文本”混排组件填空 vs dom contenteditableDOM 操作是一个开放的编辑器。模板文字生成后本质上还是文本节点用户可以在“请假事由”这几个字中间插入光标、修改文字、回车换行操作非常自由。现在的InputItem组件方式是一个结构化的表单。通过 v-for 渲染出的文字是固定的 span 或 div默认不可编辑。用户只能在指定的输入框坑位里填空无法修改周边的模板文字。sdk与业务分工点说明职责分离SDK 负责监听、定位、空白面板、插入不可编辑「芯片」、蓝色样式、关闭/插入 API业务负责调自己的接口、渲染列表、选中后调用insert与现有能力一致类似fillInput的contentEditablefalse原子块interactive-slot/file-placeholder影响面可控用sdkConfig.enableAtMention开关默认不开启不影响现有接入SDK 不应调业务方接口CORS业务 API 通常只允许业务域名SDK 嵌入页域名不同会被拦。鉴权Token/Cookie 在业务侧SDK 拿不到或不该拿。契约接口 URL、参数、数据结构各业务不同SDK 不应写死。正确做法就是你提的mention-open回调 → 业务方自己fetch→ 往panelEl里填 UI → 选中后调insert()。登录如果页面挂了xml等攻击不要有登录页不然输入密码被攻击丢了走sso登录即用公司的统一等路面本地调试粘cookie登录即可“不要在有潜在风险的页面/域名上提供高价值的输入框如密码而是通过隔离和信任域转移SSO来保护核心凭证。思考密码输入框是一个极度消耗安全防御成本的组件。你需要防钓鱼、防键盘记录、防 XSS 偷取、防暴力破解。学到了什么“最安全的组件就是不存在的组件。”既然这个页面可能有 XML 攻击风险那就把密码输入框彻底砍掉把认证转交给专门做安全的 SSO 系统。让专业的人做专业的事主业务只负责承接认证结果Token/Ticket。学到了什么安全和效率需要平衡。线上要筑起高墙SSO而本地研发只需要一条快捷通道“贴 Cookie” 或白名单 Mock。只要确保本地通道不会向外暴露这种非对称设计就是最优雅的解法。场景问题快速消失的需要录屏如闪动[触发条件]向下滚动超过3屏后快速回滚滚动卡住、穿透、冲突等504ping命令‌不能直接 ping 完整 URL含协议和路径‌只能 ping ‌域名‌或‌IP 地址ping www.example.com # 测试域名连通性ping 8.8.8.8 # 测试 IP 连通性安装卡住1.开梯子没有网没空间磁盘够不2.电脑自带的还是从官网安装可能不兼容3.Cache 删除拉的版本不对【极小概率】频繁崩溃闪退存储空间/运行内存小或者突然换电脑会有大量消息推送进程扛不住初始无响应时序竞态跳转 共享服务中心 发消息「多端链路 无业务代码变更」怀疑版本/App包打包发布不生效node build-dist检查改动的代码-publish安装-本地项目检查线上样式覆盖线上压缩拆包后顺序变化就会出现“线上被覆盖本地正常”UI闪动表现内容不变高速的视觉变化位置偏移/内容闪现/样式突变和网络请求相关闪动一般为瞬时的网络请求是稳定的不会改变内容从而改变渲染内容表现维度可能指向内容不变位置跳动布局重排Reflow内容闪现如内容→空白→内容异步加载/状态重置位置反向移动滚动冲突代码逻辑与浏览器原生滚动样式突变如颜色闪烁CSS Transition/Animation 冲突消失/* 1. 触发重排的属性 */ width|height|top|left|margin|padding /* 变化时会重排 *//* 2. 触发重绘的属性 */ background|color|box-shadow|outline /* 变化时会重绘 */录屏element 和 表现 暂停细看htmltranstion【待补充 思考链】宽高auto -具体值- auto 不是一个可计算的数值- 浏览器不知道如何从 auto 过渡到具体像素值- 所以 Transition 会直接跳过动画导致闪一下- 动画前 将 auto 转换为具体像素值- 动画后 清理样式恢复为 auto 状态低版本IOSiOS 14.x及以下版本的WebKit引擎在处理复杂的CSS Transition时存在性能瓶颈- 渲染管线不流畅 动画帧率不稳定- 重绘重排优化差 频繁的布局计算导致卡顿- 硬件加速支持不完善 无法充分利用GPU加速/** * 检测是否为 iOS 14.x 及以下版本 */ detectLowIOS() { const ua navigator.userAgent; const isIOS /iPhone|iPad|iPod/i.test(ua); if (!isIOS) return false; // 提取 iOS 版本号例如 iPhone OS 14_0 或 CPU iPhone OS 13_7 const match ua.match(/OS (\d)_(\d)/); if (match) { const majorVersion parseInt(match[1], 10); return majorVersion 14; } return false; },持久化keep-alive的能力范围是 Vue 层保留组件的 data、computed、watcher、虚拟节点等。iframe里的页面是独立文档上下文独立 Window/JS 环境/网络连接属于浏览器层不归 Vue 管。一旦 iframe 对应真实 DOM 被移除组件被卸载、节点被替换、key 变化导致重建浏览器会销毁该上下文再创建时就会重新加载 URL状态丢失。路由切换时发生了什么router-view 本质是动态组件出口。路由从 A - B 时router-view 的渲染目标从 AComponent 变成 BComponent。对 Vue 来说这是一次 vnode diff 的“类型变化”默认策略就是卸载 Aunmount挂载 Bmount这一步如果没有被缓存机制拦住就会真实移除 A 的 DOM包括 A 里的 iframe。那 keep-alive 不是拦了吗keep-alive 拦的是“组件实例销毁”但有边界条件。以下情况都会让你感觉“我只是切路由怎么重建了”include/exclude 不匹配组件没被缓存max 达到上限旧实例被 LRU 淘汰router-view 或子组件带了变化的 key如 $route.fullPath强制重建外层有 v-if 把 router-view 或 keep-alive 本身卸载了路由记录对应的组件定义变了动态 import 切换、条件渲染分支变化为什么 iframe 尤其明显普通 Vue 页面重建后data 还能从 store 回填看起来“像没丢”。iframe 是浏览器独立文档一旦节点被卸载就等于标签页被关掉再开状态滚动、输入、内部页面栈、WebSocket上下文自然重来。iframe或第三方嵌入网页keep-alive includeorganization,meet,miracast,imTime,workbench,conversation,todoTask router-view v-if!showServiceCenterAi/router-view /keep-alive ServiceCenterAi v-ifserviceCenterAiMounted v-showshowServiceCenterAi / showServiceCenterAi() { return this.$route.name serviceCenter; }, created watcg route: ensureServiceCenterAiMounted() { if (this.$route.name serviceCenter) { this.serviceCenterAiMounted true; } },keep-alive只缓存 Vue 组件实例和其虚拟 DOM 树不是浏览器里 iframe 的“运行进程”对内部iframe或第三方嵌入网页而言只要组件被卸载/重新挂载就必然重新加载。选区可见溢出、布局不溢出场景聊天气泡文本使用 white-space: pre-wrap消息里含有大量空格鼠标拖选时高亮区域看起来超出 .message-entry 边界。痛点视觉上像“选区溢出/布局异常”但气泡宽度又没被撑开容易误判成宽度计算 bug。解法在对应消息容器尽量局部加裁剪overflow: hidden;例如 .textMessage .message-entry。原理pre-wrap 会保留尾随空白这些空白常以“悬挂空白”参与选区绘制但不参与盒子宽度计算所以会出现“选区可见溢出、布局不溢出”。overflow: hidden 只裁剪绘制结果不改变文本换行/宽度语义属于影响最小修复。下载进度条完成但下载失败可能就是路径无效window专属转义这其实是个 Windows 专属的问题根因有三层每一层 Mac 都不踩坑。下面按症状由表及里来对比1. 路径分隔符 → JSON 转义陷阱Windows 路径里是\在 JSON 字符串里\是转义字符必须双写成\\。所以一旦渲染端某段代码不小心做了两次JSON.stringify或者拼字符串拼错了路径就会层层变多阶段WindowsMac原始字符串D:\IM\test.zip/Users/me/Downloads/test.zip一次 JSON.stringify 后D:\\IM\\test.zip/Users/me/Downloads/test.zip再一次 JSON.stringify 后D:\\\\IM\\\\test.zip/Users/me/Downloads/test.zip一次 JSON.parse 反序列化后D:\\IM\\test.zip双反斜杠 ←错的/Users/me/Downloads/test.zip仍然正确Mac 路径里的/不是 JSON 转义字符无论被多少次JSON.stringify/parse都不会变形。这就是为什么你会看到那个奇怪的c:\\\\test.zip现象 —— 它是 Windows 平台叠加 IPC 序列化才会暴露的。2.\\在 Windows 是 UNC 路径前缀退一步说就算路径里出现c:\\test.zip这种双反斜杠理论上 Windows API 经常会自动归一化掉。但 Chromium 在解析路径时遇到\\开头会按 UNC网络共享路径规则去理解\\server\share\path是网络共享\\?\C:\path是 NT 命名空间\\.\是设备命名空间当你传进去c:\\test.zip注意c:后面的\\Chromium 内部规范化会走形似 UNC的分支做的事情和你以为的写到 C 盘根目录不一样。结果是临时文件c:\\test.zip.crdownload居然能写成功落到了某个被规整化后的位置所以你能看到进度条到 100%最后一步 rename 到c:\\test.zip时目标路径校验失败 →done事件state interruptedPOSIXMac/Linux路径没有 UNC 概念。//在 POSIX 里只是多余的连续分隔符被当作单个/处理/Users//me/x等价于/Users/me/x。所以即便 Mac 路径里出现重复斜杠也不会被误解析到别处。js强行换行打断输入法cmdenter或ctrlenter换行后,中文输入法第一个字母被强制enter上屏的bughandleWrap() { let dom: any document.getElementById(testAt); let str1 dom.innerHTML; this.rangeInsert(\n, text); let str2 dom.innerHTML; if (str1.substring(str1.length - 1) ! \n str2.substring(str2.length - 1) \n) { this.rangeInsert(\n, text); } }改之后handleWrap(e?: KeyboardEvent) { /** * Electron(Chromium) 下IME 对 contenteditable 的“手动 DOM 插入换行”非常敏感 * 容易导致 composition 被打断出现“候选框闪一下就被提交首字母直接上屏”的现象。 * 这里改用浏览器原生的 insertLineBreak/insertText让内核自己维护 selection/composition。 */ if (e) e.preventDefault(); const el: any this.$refs.messageContent; if (!el) return; el.focus(); // 确保 recoderange/selection 是最新的 this.getRange(); const beforeLen (el.innerText || ).length; let ok false; try { // 更接近用户真实按 Enter 的路径通常对 IME 兼容更好 ok document.execCommand document.execCommand(insertLineBreak); if (!ok) { ok document.execCommand document.execCommand(insertText, false, \n); } } catch (err) { ok false; } // 兜底如果 execCommand 不生效再退回到原逻辑但不再插入 span/scrollIntoView if (!ok) { const textNode document.createTextNode(\n); this.recoderange.insertNode(textNode); this.recoderange.collapse(false); } // 某些情况下尤其是光标在末尾第一次 insertLineBreak 不会让 innerText 变长补一次 const afterLen (el.innerText || ).length; if (afterLen beforeLen) { try { document.execCommand document.execCommand(insertLineBreak); } catch (err) {} } this.getRange(); },修复原理1. 使用浏览器原生命令 document.execCommand(insertLineBreak) 让浏览器内核自己处理换行保持输入法状态2. 输入法友好 浏览器内核知道如何正确处理composition状态不会打断中文输入3. 优雅降级 如果 insertLineBreak 不支持使用 insertText 最后才用DOM操作兜底4. 长度检查 确保换行确实生效必要时补一次换行技术要点- insertLineBreak 浏览器原生换行命令对IME兼容性最好- insertText 次优选择也是浏览器原生命令- DOM操作兜底 只在必要情况下使用避免打断输入法乱码若刚更新了mac系统重启应用时间不对控制台new Date快捷键1.是点击图标 还是 快捷键安装杀死后台进程的优化软件/升级系统截图是后台进程先启动但隐藏然后保存baseurl飞书也是独立截图进程微信是原生的2.单个有效快捷键不生效单个有效应该是某个软件热键冲突可以看看哪个软件的生效如ctrlf预览图片窗口打不开Electron 窗口的 bounds宽高、坐标必须是整数像素多次点击只剩下预览窗口防抖当前sdk应用在一个electron开发PC应用里当快速多次点击a href下载链接>窗口就是url第一次点击触发的window.open还没被主进程完全拦截或处理第二次点击又进来了导致 Electron 的默认浏览器行为被唤醒。移动端并发请求 只有尾请求生效iOS在各方面都会存在优化如 对并发请求严格当ios和Android 表现不同可以往优化方面考虑JSbridgeAndroidJSbridge无效Android 4.2 默认开启useJavascriptInterface: true性能更好更安全开发更简单url透传参数只适合参数内容/形式可控复杂/不可控参数不适合 URL 传递特殊字符可能截断url可以用jsbridge​window.open打开链接没反应系统没有设置默认浏览器系统拦截如果系统没有关联默认浏览器OS 无法识别 http/https 协议的处理程序会静默失败或在控制台报错。