底层原理:拖拽、触摸与 CSS 层叠
构建一个可调整大小的 UI 面板比看起来要难。你必须同时管理布局、触摸事件和 CSS 规则。
以下是我最近在重新设计视觉差异对比 (visual-diff) UI 时总结出的三个技术教训。
- 不要使用窗口宽度来处理布局
不要使用 window.innerWidth 来判断布局是垂直还是水平的。如果用户调整了窗口大小,你的逻辑就会失效。
相反,应该使用实际的 CSS 状态。使用 getComputedStyle 来检查 flex-direction。这可以在所有媒体查询应用后读取到真实值,从而确保你的拖拽逻辑与用户实际看到的布局保持一致。
- 同时处理触摸和鼠标事件
为了让拖拽功能在桌面端和移动端都能正常工作,你需要一种统一的方法。
- 使用可选链 (optional chaining) 来提取坐标。这样就可以用一个函数同时处理鼠标和触摸事件。
- 为
touchmove设置{ passive: false }。浏览器默认将触摸事件设为被动 (passive) 以优化滚动性能。如果你不将其设为false,就无法调用e.preventDefault()。如果不调用该方法,当你尝试拖拽时,页面也会随之滚动。 - 将
move和end监听器绑定到document上。如果用户手指移动过快,可能会脱离分隔条。将其绑定到document可以确保即使指针发生偏移,拖拽操作也能继续进行。
- 避免与你的可见性系统“对抗”
我遇到了一个 CSS 特异性 (specificity) 的 Bug。我有一个类用于隐藏面板,另一个类用于设置布局方向。
问题所在:
.view-panel { display: none; }.diff-layout { display: flex; }
由于它们的特异性相同,文件中靠后的规则胜出了。这意味着即使面板应该被隐藏,它们仍然保持可见。
解决方案:
永远不要让布局辅助类去设置 display 属性。应该让可见性类来负责该属性。
不要这样写:
.diff-layout { display: flex; flex-direction: column; }
而要这样写:
.view-panel.diff-layout { flex-direction: column; }
这样做提高了特异性,并确保布局类只改变方向,而不影响可见性。
来源:https://dev.to/bonzai2carn/under-the-hood-drag-touch-and-css-cascade-in-a-real-diff-ui-1b66
