共计 3579 个字符,预计需要花费 9 分钟才能阅读完成。
这两天实现了一个仿樊登 H5 的音乐播放悬浮球成果,这个成果跟微信音乐播放悬浮球的成果也很类似,明天总结一下实现的思路过程(基于 Vue 实现)。
先来看看樊登 H5 的成果。
再来看看我的实现,挺完满的,哈哈。
实现起来也不简单,次要是一步步想分明上面的实现步骤:
第一步:小球被限度在固定范畴内滑动
第二步:进行滑动时,小球吸边成果
第三步:点击吸边状态下的小球,变换为音频播放控制面板,点击毛玻璃,复原成小球
第四步:背景毛玻璃成果
一步步来说。
第一步:小球被限度在固定范畴内滑动
touchmove 能够取得小球的滑动事件,所以能够应用 touchmove来限度小球的滑动范畴。
先给小球的 touchmove 传入 handleTouchMove 函数,在 handleTouchMove 中获取到滑动事件 e,应用 e.targetTouches[0]能够取得手指滑动的坐标 clientX 和 clientY,来计算小球 left、top 值,从而来管制小球随手指滑动。
<div
class="circle"
v-if="!showCircleContent"
@click="handleClickCircle"
@touchend="handleTouchEnd"
@touchmove.prevent="handleTouchMove"
></div>
当手指或鼠标滑动到超过屏幕的左边界时,就将小球的 left 重置为 0,不让小球超出左边界。当滑动超过右边界时,就将小球的 left 重置为视口的宽度减去小球的宽度,不让小球超出右边界。
顶部和底部边界也一样,当手指或鼠标滑动到超过顶部边界时,将小球的 top 重置为 0,超过底部边界时,将 top 重置为视口的高度减去小球的高度。
当然滑动范畴能够本人来管制,具体管制小球滑动的代码如下:
// 限度悬浮球一个范畴内滑动
handleTouchMove(e) {
this.isAnimated = false; // 手指拖动小球滑动的时候不须要动画,滑动进行的时候增加动画
this.$refs.circle.style.borderRadius = "50%";
let offsetX = e.targetTouches[0].clientX - this.circleWidth / 2; // 减去 this.circleWidth / 2 目标是让手指按在悬浮球正中
let offsetY = e.targetTouches[0].clientY - this.circleHeight / 2; // 减去 this.circleHeight / 2 目标是让手指按在悬浮球正中
if (offsetX <= 0 + this.placeholderWidth) {offsetX = 0 + this.placeholderWidth; // 不让悬浮球齐全贴边} else if (
offsetX >=
document.documentElement.clientWidth -
this.circleWidth -
this.placeholderWidth // 微信悬浮球不是齐全贴边,离屏幕边缘有一段距离
) {
offsetX =
document.documentElement.clientWidth -
this.circleWidth -
this.placeholderWidth;
}
if (offsetY <= 0 + this.placeholderWidth) {offsetY = 0 + this.placeholderWidth;} else if (
offsetY >=
document.documentElement.clientHeight -
this.circleHeight -
this.placeholderWidth
) {
offsetY =
document.documentElement.clientHeight -
this.circleHeight -
this.placeholderWidth;
}
this.$refs.circle.style.left = offsetX + "px";
this.$refs.circle.style.top = offsetY + "px";
},
第二步:进行滑动,悬浮球吸边成果
滑动小球,当手指松开时,小球须要吸附到屏幕边缘。依据小球核心的 x 坐标判断,如果 x 坐标小于屏幕宽度的一半,就吸附到屏幕右边,如果大于等于屏幕宽的一半则吸附到屏幕左边,实现代码走一波:
//touchend 的时候,悬浮球吸边显示
handleTouchEnd(e) {
this.isAnimated = true; // 手指拖动小球滑动的时候不须要动画,滑动进行的时候增加动画
let circleCenterX =
parseInt(this.$refs.circle.style.left.replace("px", "")) +
this.circleWidth / 2; // 悬浮球核心的 x 坐标
let circleCenterY =
parseInt(this.$refs.circle.style.top.replace("px", "")) +
this.circleHeight / 2; // 悬浮球核心的 y 坐标
if (circleCenterX < this.clientWidth / 2) {
// 吸附左侧
this.$refs.circle.style.left = 0;
this.$refs.circle.style.borderRadius = "0 50% 50% 0";
} else {
// 吸附在右侧
this.$refs.circle.style.left =
this.clientWidth - this.circleWidth + "px";
this.$refs.circle.style.borderRadius = "50% 0 0 50%";
}
if (circleCenterY >= this.clientHeight - this.placeholderBottom) {
this.$refs.circle.style.top =
this.clientHeight - this.placeholderBottom + "px";
}
},
第三步:点击吸边小球,变换为音频播放控制面板
当小球吸附到屏幕边缘时,点击小球,小球开展成音频控制面板,点击毛玻璃背景,小球膨胀恢复原状。
在实现时我将小球 circle 跟音频控制面板 content 离开布局,大略是这个样子。
<div
class="circle-box"
:class="{
opened: showCircleContent,
animation: isAnimated
}"ref="circle"
>
<div class="content" v-if="showCircleContent">
<!-- 音频控制面板,显示歌曲名字、播放时长,同时还能管制播放暂停音频 -->
</div>
<div class="circle" v-if="!showCircleContent">
<!-- 小球悬浮状态 -->
</div>
</div>
应用 circle-box 包裹悬浮小球 circle 和音频控制面板 content,应用变量 showCircleContent 来判断以后应该显示悬浮球还是音频播放控制面板。
当点击悬浮球时 showCircleContent 为 true,小球伸长变换为音频播放控制面板。
点击毛玻璃背景,设置 showCircleContent 为 false,音频播放控制面板膨胀复原成悬浮小球。
伸缩动画
小球从悬浮球变为音频控制面板,或者从控制面板变为悬浮球时是有动画的,这个动画应该在 touchend 的时候才增加,在 touchmove 的时候去掉。因为小球滑动时如果有动画的话,会有卡顿的景象。
应用 isAnimated 来管制动画的增加和删除,在 touchend 的时候为 true,在 touchmove 改为 false。
第四步:背景毛玻璃成果
backdrop-filter 属性实现毛玻璃理解一下,filter 只能让以后元素有含糊成果,以后元素之下的元素还是清晰的。而 backdrop-filter 能够让以后元素及以下的元素都含糊,从而实现毛玻璃的成果。
backdrop-filter: blur(10px); // 毛玻璃成果,ios 无效
-webkit-backdrop-filter: blur(10px);
然而目前 backdrop-filter 的兼容性不是太好,在 IOS 平台能看到毛玻璃成果,Android 平台看不到。
OK,以上就是实现音乐播放悬浮球的思路总结,其实在实现过程中还有很多细节上的解决,如果想理解更多细节,能够关注我的公众号 「程序员张晴天」,并在后盾回复「悬浮球」 即可取得 demo 残缺源码。
如果对你有帮忙的话,点赞、评论、赞叹都是对我的激励,也是反对我写下去的能源,谢谢!
本文原创公布于微信公众号「程序员张晴天」,欢送关注第一工夫获取最新分享,一起提高。