ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

可拖拽按钮吸附效果实现

可拖拽按钮吸附效果实现 可拖拽按钮吸附效果实现教程效果描述页面右下角有一个可拖拽的呼叫按钮用户可以按住按钮自由拖拽水平 垂直松开后按钮自动吸附到最近的屏幕边缘left: 0或right: 0吸附状态下只保留垂直位置top水平方向使用left: 0或right: 0核心思路吸附状态使用left: 0或right: 0定位按钮紧贴屏幕一侧拖拽状态使用left: Npx定位按钮跟随手指自由移动松手判定根据按钮中心点位于屏幕左半还是右半决定吸附到哪一侧通过computed动态生成 style 对象根据dragging状态切换定位方式。代码分解1. 定义状态constcallBtnSnapLeftref(false)// 吸附方向true靠左, false靠右constcallBtnTopref(0)// 垂直位置pxconstdraggingref(false)// 是否正在拖拽conststartXref(0)// 拖拽起始手指 XconststartYref(0)// 拖拽起始手指 YconststartTopref(0)// 拖拽起始 top 值conststartSnapLeftref(false)// 拖拽起始吸附方向constdragLeftref(0)// 拖拽过程中的临时水平位置pxconstcallBtnRefrefHTMLElement|null(null)// 按钮 DOM 引用2. 计算动态样式constcallBtnStylecomputed((){if(dragging.value){// 拖拽中使用 left top 自由定位return{left:dragLeft.valuepx,top:callBtnTop.valuepx}}// 吸附状态使用 left: 0 或 right: 0return{[callBtnSnapLeft.value?left:right]:0,top:callBtnTop.valuepx,}})关键点[callBtnSnapLeft.value ? left : right]是 ES6 计算属性名语法动态决定用left还是right作为 CSS 属性。3. 手指按下开始拖拽functiononCallPointerDown(e:PointerEvent){dragging.valuetruestartX.valuee.clientX startY.valuee.clientY startTop.valuecallBtnTop.value startSnapLeft.valuecallBtnSnapLeft.valueconstelcallBtnRef.valueif(!el)returnel.setPointerCapture(e.pointerId)// 捕获指针防止拖拽过程中丢失事件// 根据当前吸附方向计算等效的 left 值constpwel.parentElement!.clientWidth dragLeft.valuestartSnapLeft.value?0:pw-el.offsetWidth}setPointerCapture确保即使手指滑出按钮范围仍然能接收到指针事件。4. 手指移动拖拽中functiononCallPointerMove(e:PointerEvent){if(!dragging.value)returnconstdxe.clientX-startX.value// 水平偏移量constdye.clientY-startY.value// 垂直偏移量constelcallBtnRef.valueif(!el)returnconstpwel.parentElement!.clientWidthconstbaseLeftstartSnapLeft.value?0:pw-el.offsetWidth// 限制范围不让按钮拖出屏幕dragLeft.valueMath.max(0,Math.min(pw-el.offsetWidth,baseLeftdx))callBtnTop.valueMath.max(0,startTop.valuedy)}Math.max(0, Math.min(pw - el.offsetWidth, ...))确保按钮不会超出父容器左右边界。5. 手指松开吸附判定functiononCallPointerUp(e:PointerEvent){if(!dragging.value)returndragging.valuefalseconstelcallBtnRef.valueif(el)el.releasePointerCapture(e.pointerId)if(!el)returnconstparentel.parentElement!constpwparent.clientWidth// 按钮中心在屏幕左半 → 靠左否则靠右callBtnSnapLeft.valuedragLeft.valueel.offsetWidth/2pw/2}判定逻辑dragLeft 按钮宽度/2 父容器宽度/2→ 按钮中心在左半侧 → 吸附到左侧。模板绑定divrefcallBtnRefclasscall-btn:class{ dragging }:stylecallBtnStylepointerdownonCallPointerDownpointermoveonCallPointerMovepointeruponCallPointerUppointercancelonCallPointerUpimgsrc/home/call.pngclasscall-iconalt//div使用 Pointer Events API兼容触摸和鼠标。注意事项Pointer Events vs Touch/Mouse EventsPointer Events 统一了触摸和鼠标输入推荐在现代浏览器中使用。setPointerCapture是核心 API。为什么不直接用left: Npx吸附用left: 0/right: 0可以自适应容器宽度变化如屏幕旋转而left: 8px这样的像素值在屏幕翻转后会错位。边界限制Math.max(0, ...)防止按钮拖出顶部/左侧Math.min(pw - bw, ...)防止拖出右侧/底部。吸附动画当前实现是瞬间切换如果需要平滑过渡可以在.call-btn上添加transition: left 0.2s, right 0.2s。但要注意拖拽时不能有过渡否则按钮会延迟跟随手指所以只在非拖拽状态添加。
返回列表