各参数说明

## 属性dragableRange: 拖动范围。parent 父级 window 可视窗口dragable: 是否可拖动。默认 trueposition:初始位置。[object Object] top、left、right、bottomindent:是否需要缩进。默认 falseindentDelayTime:延时缩进。单位:ms, 为 0 则不缩进indentDistance:缩进距离。单位:pxneedNearEdge:拖动悬浮球后是否需要贴边。默认:falsenearEdgeTransition: 贴边过渡动画,transition 属性值。默认:'all ease 0.3s'nearEdgeDirection:拖动悬浮球后贴边方向。默认贴边方向为距离最近的方向。indentNearEdge:悬浮球贴边后是否需要缩进(此时缩进方向为贴边的方向)。默认 falseindentNearEdgeDelay: 悬浮球贴边后延时缩进。单位:ms,默认 1000,为 0 则不延时## 事件clickFunc:点击悬浮球后回调事件## slotsslotsDirection:插槽内容方向,默认置于悬浮球右边(如不设置且已开启 needNearEdge,则自动根据贴边情况来改变方向)

组件实现

<template><divclass="suspend_ball_wrapper":style="{position: dragableRange === 'window' ? 'fixed' : 'absolute',...position,}"><divv-if="dragable"class="suspend_ball"@touchstart="touchstart"@touchmove="touchmove"@touchend="touchend"><div class="slots" :class="[slotsDirectionData]"><slot /></div></div><div v-else class="suspend_ball"><div class="slots" :class="[slotsDirectionData]"><slot /></div></div></div>
</template>
<script>
export default {data() {return {left: 0,top: 0,touchType: 0, //触摸类型 1拖动悬浮球 0点击悬浮球indentTimer: null,indentNearEdgeTimer: null,slotsDirectionData: "right",};},props: {dragable: {type: Boolean,default: true,},dragableRange: {type: String,default: "parent",},position: {type: Object,default: function () {return {left: 0,top: 0,};},},indent: {type: Boolean,default: false,},indentDelayTime: {type: Number,default: 1000,},indentDistance: {type: Number,default: 30,},indentNearEdge: {type: Boolean,default: false,},needNearEdge: {type: Boolean,default: false,},nearEdgeTransition: {type: String,default: "all ease 0.3s",},nearEdgeDirection: String,indentNearEdgeDelay: {type: Number,default: 1000,},slotsDirection: {type: String,default: "right",},},created() {this.slotsDirection && (this.slotsDirectionData = this.slotsDirection);},mounted() {if (this.indent && this.indentDelayTime) {this.setIndent();}},methods: {touchstart(e) {const el = this.$el;e.preventDefault();//触摸类型 1拖动悬浮球 0点击悬浮球this.touchType = 0;this.$el.style.transition = "none";this.clearAllTimeout();//手指按下时的坐标const starX = e.touches[0].clientX;const starY = e.touches[0].clientY;this.starX = starX;this.starY = starY;//手指相对元素本身位置this.distanceX = starX - el.offsetLeft;this.distanceY = starY - el.offsetTop;},touchmove(e) {//手指移动到的坐标const moveX = e.touches[0].clientX;const moveY = e.touches[0].clientY;//手指移动距离const moveXDistance = moveX - this.starX;const moveYDistance = moveY - this.starY;//设置位置let left = moveX - this.distanceX;let top = moveY - this.distanceY;//处理点击产生的细微移动if (Math.abs(moveXDistance) > 15 || Math.abs(moveYDistance) > 15) {this.touchType = 1;}this.validMove(left, top);},touchend() {if (this.touchType === 0) {this.$emit("touchFunc");}//是否需要缩进if (this.needNearEdge) {const {self_offsetWidth,self_offsetHeight,parent_offsetWidth,parent_offsetHeight,} = this.getSelfAndParentOffset();const obj = {left: parseFloat(this.$el.style.left),top: parseFloat(this.$el.style.top),};obj.right = parent_offsetWidth - obj.left - self_offsetWidth;obj.bottom = parent_offsetHeight - obj.top - self_offsetHeight;//各方向中最小值let minKey = "";//计算贴边方向if (this.nearEdgeDirection) {minKey = this.nearEdgeDirection;} else {let min = Math.min();for (const key in obj) {const val = parseFloat(obj[key]);if (val < min) {min = val;minKey = key;}}}//设置贴边过渡if (this.nearEdgeTransition) {this.$el.style.transition = this.nearEdgeTransition;}//设置贴边this.$el.style[minKey] = 0;//设置贴边后缩进if (this.indentNearEdge) {if (this.indentNearEdgeDelay !== 0) {clearTimeout(this.indentNearEdgeTimer);this.indentNearEdgeTimer = setTimeout(() => {this.$el.style[minKey] = -this.indentDistance + "px";this.setOtherDirectionVal(minKey, this.indentDistance);}, this.indentNearEdgeDelay);} else {this.$el.style[minKey] = -this.indentDistance + "px";}}this.setOtherDirectionVal(minKey);}},//移动validMove(left, top) {const {self_offsetWidth,self_offsetHeight,parent_offsetWidth,parent_offsetHeight,} = this.getSelfAndParentOffset();if (left + self_offsetWidth > parent_offsetWidth) {left = parent_offsetWidth - self_offsetWidth;}if (top + self_offsetHeight > parent_offsetHeight) {top = parent_offsetHeight - self_offsetHeight;}if (left <= 0) {left = 0;}if (top <= 0) {top = 0;}this.$el.style.left = left + "px";this.$el.style.top = top + "px";this.left = left;this.top = top;this.right = "auto";this.bottom = "auto";},//设置缩进setIndent(delayTime) {clearTimeout(this.indentTimer);this.indentTimer = setTimeout(() => {let direction;let el = this.$el;const positionObj = this.getPositionComputedStyle();for (const key in positionObj) {if (parseFloat(positionObj[key]) === 0) {direction = key;}}el.style[direction] = el.style[direction] - this.indentDistance + "px";}, delayTime || this.indentDelayTime);},//设置其他方向position值setOtherDirectionVal(minKey, indentDistance = 0) {const {parent_offsetWidth,parent_offsetHeight,self_offsetWidth,self_offsetHeight,} = this.getSelfAndParentOffset();let slotsDirection = "";switch (minKey) {case "left":this.$el.style["right"] =parent_offsetWidth - self_offsetWidth + indentDistance + "px";slotsDirection = "right";break;case "right":this.$el.style["left"] =parent_offsetWidth - self_offsetWidth + indentDistance + "px";slotsDirection = "left";break;case "top":this.$el.style["bottom"] =parent_offsetHeight - self_offsetHeight + indentDistance + "px";slotsDirection = "bottom";break;case "bottom":this.$el.style["top"] =parent_offsetHeight - self_offsetHeight + indentDistance + "px";slotsDirection = "top";break;}//设置插槽方向(未设置slotsDirection则自动判断)if (!this.slotsDirection) {this.slotsDirectionData = slotsDirection;}},//计算offset值getSelfAndParentOffset() {const ifwindowRange = this.dragableRange === "window";const parent_offsetWidth = !ifwindowRange? this.$el.parentNode.offsetWidth: window.innerWidth;const parent_offsetHeight = !ifwindowRange? this.$el.parentNode.offsetHeight: window.innerHeight;const self_offsetWidth = this.$el.offsetWidth;const self_offsetHeight = this.$el.offsetHeight;return {parent_offsetWidth,parent_offsetHeight,self_offsetWidth,self_offsetHeight,};},getPositionComputedStyle() {let el = this.$el;let style = getComputedStyle(el);const positionObj = {top: style.top,bottom: style.bottom,left: style.left,right: style.right,};return positionObj;},clearAllTimeout() {clearTimeout(this.indentTimer);clearTimeout(this.indentNearEdgeTimer);},},
};
</script>
<style lang="less" scoped>
.suspend_ball_wrapper {position: absolute;// top: 0;// left: 0;width: 60px;height: 60px;z-index: 1000;.suspend_ball {width: 100%;height: 100%;border-radius: 50%;background-size: cover;background-image: url("https://img0.baidu.com/it/u=272572278,3446974957&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500");.slots {position: absolute;width: fit-content;height: 100%;&.right {left: calc(100% + 10px);}&.left {right: calc(100% + 10px);}&.top {bottom: calc(100% + 10px);}&.bottom {top: calc(100% + 10px);}}}
}
</style>

效果

动手吧,vue移动端悬浮球组件相关推荐

  1. Angular实现悬浮球组件

    Angular实现悬浮球组件 在手机 App 上,我们经常会看到悬浮球的东东,用着可能很舒服,但是 web 网页上却很少见,今天我们就通过 Angular 来实现,当然使用其他框架也是可以的. 功能要 ...

  2. vue 移动端顶部导航组件

    废话不多说,下面是我自己写的vue移动端顶部导航组件给大家分享一下 ,动态绑定背景颜色,字体颜色,以及回退图标.需要的直接拿去放项目里用吧- 示例图: HTML <template>< ...

  3. 手机html端悬浮球,手机移动端网站触屏可拖动悬浮球

    手机移动端网站触屏可拖动悬浮球 touch { width: 60px; height: 60px; position: absolute; left: 600px; top: 300px; marg ...

  4. vue移动端项目日历组件,月周切换,点击进入上/下一个月

    项目场景: Vue移动端项目的日历组件,移动端如果没有别的特别要求,一般用vant中的日历组件就OK,这里用的另一个.组件是网上找的,原网址:vue-hash-calendar,需要的请自行去看. 我 ...

  5. 手机html端悬浮球,大屏手机绝配!一款轻巧强大的悬浮球App

    很多智能手机用户,特别是iPhone用户,很喜欢使用悬浮球.不过和iPhone相比,安卓上的悬浮球可丰富多彩得多.安卓原生并不自带悬浮球的功能,但诸多悬浮球App,却提供了丰富多彩的方案.加之安卓机的 ...

  6. 自己动手写一个移动端日期选择器组件

    文章目录 背景 效果演示 思路 实现 1. picker-view 实现基础交互 2. 年月日动态配置以及支持最大最小日期 3. 支持不同日期模式 背景 本文写的组件是基于 uni-app 框架下的, ...

  7. vue移动端弹框组件

    这里说一下 vue-layer-mobile插件的使用 一.npm 安装 // 当前最新版本 1.2.0 npm install vue-layer-mobile // 如新版遇到问题可回退旧版本 n ...

  8. Vue移动端五星好评组件封装(精确到0.1)

    我说的五星好评是大家平时很常见的,类似于美团评价那些,不过要精确到0.1的效果展现,的确项目中遇到了,当时也没太注意,很快写了一个,但是最后项目经理又要求不能是全星的评价,要精确到小数点后一位,相对来 ...

  9. vue当中实现悬浮球可拖拽

    touch.vue <template><transition><divref="breathing_lamp"class="breathi ...

最新文章

  1. 快速修剪技巧_三角梅花后修剪有讲究,轻剪还是重剪?品种和养殖环境来决定...
  2. 官方数据:5次SDN大会的背后
  3. 家里路由器如何共享同一个ip
  4. 给大家几个不花钱看书的办法【人人都是产品经理】
  5. 单元测试 | 如何Mock IHttpClientFactory
  6. Oracle查询今天、昨天、本周、上周、本月、上月数据
  7. 为什么说在国内考CISP比CISSP要好?
  8. HDU 6166 2017 多校训练:Senior Pan(最短路)
  9. CNware存储管理功能介绍
  10. MySQL数据库建立数据库和表(命令行方式)
  11. MyApps接口引擎,打破跨系统间的壁垒
  12. 3DGIS产品层次结构
  13. idea切换工作空间_IDEA在一个工作空间中管理多个项目的详细步骤
  14. phpcms图库_love.php
  15. 项目实战之物联网智能鱼缸
  16. Mac解压缩rar文件
  17. 中国前10名的休闲服品牌企业信息化漫谈--S公司
  18. Java基础: contains方法的用法
  19. 伦敦银开盘时间知多少
  20. Windows遇到的图片查看问题。

热门文章

  1. 集合及集合的交,并与差
  2. python pexpect安装
  3. Python:安装 psycopg2
  4. 经典卷积神经网络(CNN)图像分类算法详解
  5. 转载:关于 PHP 5.4 你所需要知道的
  6. Mybatis原理——执行原理详解
  7. 管理后台-前端-AngularJS
  8. 选择框,单选框,组合框,列表框
  9. python中列表(list)的基本定义和用法
  10. marked.js简易手册