The demo diagram is as follows:
The overall floating ball component code
is as follows:
<!-- draggable ball package --> <template> <div class="backHome" ref="floatButton" @click="goCreatePage" :style="{ width: itemWidth + 'px', height: itemHeight + 'px', left: left + 'px', top: top + 'px', }" > <img src="" alt="" /> </div> </template> <script> export default { name: "BackHome", props: { itemWidth: { // floating button width type: Number, default: 40, }, itemHeight: { // The height of the floating button type: Number, default: 50, }, gapWidth: { // Distance from the left and right sides type: Number, default: 20, }, coefficientHeight: { // distance ratio from top to bottom type: Number, default: 0.72, }, }, data() { return { ssicId: "", clientWidth: 0, clientHeight: 0, timer: null, currentTop: 0, left: 0, top: 0, }; }, created() { // this.ssicId = sessionStorage.getItem("ssicId"); this.clientWidth = document.documentElement.clientWidth; this.clientHeight = document.documentElement.clientHeight; this.left = this.clientWidth - this.itemWidth - this.gapWidth; this.top = this.clientHeight * this.coefficientHeight; }, methods: { // return to home menu goCreatePage() { this.$emit("goManage"); // location.href = ``; }, handleScrollEnd() { let scrollTop = document.documentElement.scrollTop || document.body.scrollTop; if (scrollTop === this. currentTop) { if (this. left > this. clientWidth / 2) { this.left = this.clientWidth - this.itemWidth - this.gapWidth; } else { this.left = this.gapWidth; } } clearTimeout(this. timer); }, }, mounted() { this. $nextTick(() => { const floatButton = this. $refs. floatButton; floatButton. addEventListener("touchstart", () => { floatButton.style.transition = "none"; }); // During the dragging process, the component should move with the movement of the finger floatButton. addEventListener("touchmove", (e) => { if (e. targetTouches. length === 1) { // a finger let touch = e. targetTouches[0]; this.left = touch.clientX - 20; this.top = touch.clientY-25; } }); // After dragging, re-adjust the position of the component and reset the transition animation floatButton. addEventListener("touchend", () => { floatButton.style.transition = "all 0.3s"; if (this. left > document. documentElement. clientWidth / 2) { this.left = document.documentElement.clientWidth - 60; } else { this. left = 0; } }); }); }, beforeDestroy() { window. removeEventListener("scroll", this. handleScrollStart); }, }; </script> <style lang="scss" scoped> .backHome { position: fixed; bottom: 165px; right: 15px; z-index: 999; width: 61px; height: 61px; img { width: 61px; height: 61px; } } </style>
If you use , you can directly import it, such as this:
<template> <float-button></float-button> </template> <script> export default { components: { floatButton: () => import("../components/floatButton"), // asynchronous component loading method }, }; </script>
two,
JS part:
Vue.component('dragIcon', { template:` <transition> <div ref="dragIcon" class="dragIcon" @touchstart="handleTouchStart" @touchmove.prevent="handleTouchMove" @touchend="handleTouchEnd" :style="{left: left + 'px',top: top + 'px',width: itemWidth + 'px',height: itemHeight + 'px'}" v-text="text" v-if="isShow" > </div> </transition> `, props: { text: { type: String, default: 'Homepage' }, itemWidth: { type: Number, default: 40 }, itemHeight: { type: Number, default: 40 } }, data() { return { left: 0, top: 0, startToMove: false, isShow: true, timer: null, currentTop: null, clientW: document.documentElement.clientWidth, clientH: document.documentElement.clientHeight } }, created () { this.left = (this.clientW - this.itemWidth) this.top = (this.clientH/2 - this.itemHeight/2) }, mounted() { this. bindScrollEvent() }, beforeDestroy() { // Remember to destroy some global events this. removeScrollEvent() }, methods: { handleTouchStart() { this.startToMove = true this.$refs.dragIcon.style.transition = "none" }, handleTouchMove(e) { const clientX = e.targetTouches[0].clientX const clientY = e.targetTouches[0].clientY const isInScreen = clientX <= this.clientW & amp; & amp; clientX >= 0 & amp; & amp; clientY <= this.clientH & amp; & amp; clientY >=0 if(this.startToMove & amp; & amp; e.targetTouches.length === 1) { if(isInScreen) { this.left = clientX - this.itemWidth/2 this.top = clientY - this.itemHeight/2 } } }, handleTouchEnd() { if(this. left < (this. clientW / 2)) { this.left = 0 this. handleIconY() } else { this.left = this.clientW - this.itemWidth this. handleIconY() } this.$refs.dragIcon.style.transition = "all .3s" }, handleIconY() { if (this. top < 0) { this.top = 0 } else if(this.top + this.itemHeight > this.clientH) { this.top = this.clientH - this.itemHeight } }, bindScrollEvent() { window.addEventListener('scroll', this.handleScrollStart) }, removeScrollEvent() { window. removeEventListener('scroll', this. handleScrollStart) }, handleScrollStart() { this.isShow = false this.timer & amp; & amp; clearTimeout(this.timer) this.timer = setTimeout(() => { this. handleScrollEnd() },300) this.currentTop = document.documentElement.scrollTop || document.body.scrollTop }, handleScrollEnd() { this.scrollTop = document.documentElement.scrollTop || document.body.scrollTop // Conditions for judging whether to stop scrolling if(this. scrollTop == this. currentTop) { this.isShow = true } } } })
HTML section:
<div id="app"> <div class="content1">1111</div> <div class="content2">2222</div> <drag-icon></drag-icon> </div>
CSS section:
.dragIcon { position: fixed; width: 40px; height: 40px; border-radius: 50%; background-color: gray; line-height: 40px; text-align: center; color: #fff; } .content1 { height: 400px; background-color: rgb(230,180,80); } .content2 { height: 500px; background-color: rgb(227,230,195); } .v-enter { opacity: 1; } .v-leave-to { opacity: 0; } .v-enter-active, .v-leave-active { transition: opacity 0.3s; }
Function sublimation:
In Vue2, a floating ball can be clicked to expand/collect, and can be dragged to any position on the page
The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge