vue 实现 类似手机的悬浮球 【可缩进半隐藏】
悬浮球 效果
3种位置展示
悬浮球 组件代码
<template> <div class="ys-float-btn" :style="{'width':itemWidth+'px','height':itemHeight+'px','left':left+'px','top':top+'px'}" ref="div" @click ="onBtnClicked"> <slot name="icon"></slot> <SvgIcon :iconClass="'changjianwentijieda'" :style="{'width':itemWidth+'px','height':itemHeight+'px'}"/> </div> </template> <script> export default { name: "DragIcon", data() { return{ timer:null, currentTop:0, clientWidth:0, // 屏幕宽度 clientHeight:0, // 屏幕高度 left:0, top:0 } }, props:{ itemWidth:{ // 悬浮物的宽度 type:Number, default:40 }, itemHeight:{ // 悬浮物的高度 type:Number, default:40 }, gapWidth:{ // 距离边界距离 type:Number, default:10 }, gapWidthHide:{ // 距离边界多少时可以缩进 type:Number, default:20 }, hideWidth:{ // 边界缩进隐藏的长度 type:Number, default:20 }, coefficientHeight:{ // 计算 距离屏幕上边界高度的百分比 type:Number, default:0.8 } }, created(){ // 初始化 this.clientWidth = document.documentElement.clientWidth; // 屏幕宽度 this.clientHeight = document.documentElement.clientHeight; // 屏幕高度 // this.left = this.clientWidth - this.itemWidth - this.gapWidth; // 初始为靠右贴边界位置 this.left = this.clientWidth - this.hideWidth; // 初始为右侧缩进状态 this.top = this.clientHeight*this.coefficientHeight; // 距离屏幕上边界80%的高度 }, mounted(){ this.$nextTick(()=>{ const div = this.$refs.div; div.addEventListener("touchstart",(e)=>{ e.stopPropagation(); div.style.transition = 'none'; }); // 悬浮物移动的过程展示 div.addEventListener("touchmove",(e)=>{ e.stopPropagation(); if (e.targetTouches.length === 1) { let touch = event.targetTouches[0]; this.left = touch.clientX - this.itemWidth/2; this.top = touch.clientY - this.itemHeight/2; } }, false ); // 悬浮物最后被移动到的位置 div.addEventListener("touchend",(e)=>{ e.stopPropagation(); div.style.transition = 'all 0.3s'; if(this.left>this.clientWidth/2){ // 悬浮物最后位置在屏幕中间偏右 // 悬浮物最后位置超过边界外时,具体具体根据 gapWidthHide 大小 if (this.left > this.clientWidth - this.gapWidthHide) { this.left = this.clientWidth - this.hideWidth; } else { this.left = this.clientWidth - this.itemWidth - this.gapWidth; } } else { // 悬浮物最后位置在屏幕中间偏左 this.left = this.gapWidth; } if(this.top<=36) { this.top=36+this.gapWidth } else{ let bottom=this.clientHeight-50-this.itemHeight-this.gapWidth if(this.top>=bottom) { this.top=bottom } } }); }); }, methods:{ onBtnClicked(){ this.$emit("onFloatBtnClicked"); // 父组件用到的方法(点击球调用的方法) } } } </script> <style lang="scss" scoped> .ys-float-btn{ margin-bottom: 0.77rem; background: url('../../src/assets/img/button.png') no-repeat right; // 背景色或背景图 background-position: calc(100% - 0.15rem) center; // box-shadow:0 2px 10px 0 rgba(0,0,0,0.1); // 圆形球体图标的投影 // border-radius:50%; // 制作圆形图标 color: #666666; z-index: 20; transition: all 0.3s; display: flex; flex-direction: column; justify-content: center; align-items: center; position: fixed; bottom: 20vw; img{ width: 50%; height: 50%; object-fit: contain; margin-bottom: 3px; } } .su_img{ width: 40px; height: 40px; margin: 8px 0 0 0; } </style>
引入组件
<template>
<section class="wrap">
<drag-icon
:itemHeight='60'
:itemWidth='120'
:gapWidthHide='80'
:hideWidth='40'
@onFloatBtnClicked="toHistory">
</drag-icon>
</section>
</template>
const DragIcon = () => import('@/components/dragIcon') // 引入组件
export default {
components: {
DragIcon
},
methods: {
toHistory () { // 点击组件调用的方法
this.$router.push('/history')
}
}
}
smile
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通