直接上组件,可拖动

1.在components新建suspend组件
<template>
<view>
<movable-area class="movable-area">
<movable-view class="movable-view" :x="x" :y="y" direction="all">
<view class="newProblem" @click="xxx">
<image src="https://xxx/minapp/static/icon.png"></image>
<text>反馈</text>
</view>
</movable-view>
</movable-area>
</view>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {
x: 1000,
y: 1000
};
},
computed: {
...mapState(['hasUserInfo'])
},
methods: {
newProblem() {
if (!this.hasUserInfo) {
uni.reLaunch({
url: '/pages/authorization/index'
});
return;
}
uni.navigateTo({
url: '/mineInfo/problemFeedback/problemFeedback'
});
}
}
};
</script>
<style lang="less">
.movable-area {
// 保持在右下角
margin-top: 200rpx;
margin-left: 100rpx;
height: calc(100vh - 300rpx);
width: calc(100vw - 150rpx);
top: 0;
left: 0;
right: 0;
bottom: 0;
position: fixed;
z-index: 99999999;
pointer-events: none; //此处要加,鼠标事件可以渗透
.movable-view {
width: 100rpx;
height: 100rpx;
pointer-events: auto; //恢复鼠标事件
.newProblem {
width: 100rpx;
height: 100rpx;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
background: #ffffff;
border-radius: 50%;
border: 1px solid #a6a6a6;
image {
width: 30rpx;
height: 30rpx;
}
text {
margin-top: 10rpx;
font-size: 24rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #000000;
}
}
}
}
</style>
2.在main.js中进行挂载,之后每个页面不需要引入
默认有easycom机制,可跳过
import App from './App'
import Vue from 'vue'
import suspend from '@/components/suspend.vue'
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
Vue.component('suspend',suspend)
app.$mount()
3.使用组件(需要的页面添加即可)
<template>
<view class="content">
<suspend></suspend>
</view>
</template>
4.记录拖拽位置同步vuex
每个页面保持一致
<template>
<view>
<movable-area class="movable-area">
<movable-view
class="movable-view"
:x="moveX"
:y="moveY"
direction="all"
@change="handleMove"
>
<view class="box">
<view class="newProblem" @click="service">
<image src="https://dl.essmall.cn/minapp/static/kf.png"></image>
<text>客服</text>
</view>
</view>
</movable-view>
</movable-area>
</view>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {
x: 1000,
y: 1000,
timer: null,
};
},
computed: {
...mapState(["hasUserInfo", "moveX", "moveY"]),
},
methods: {
service() {
if (!this.hasUserInfo) {
uni.reLaunch({
url: "/pages/authorization/index",
});
return;
}
uni.navigateTo({
url: "/mineInfo/service/service",
});
},
handleMove(event) {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
const { x, y } = event.detail;
this.$store.commit("changeMoveXY", { x, y });
}, 200);
},
},
};
</script>
<style lang="less">
.movable-area {
height: 100vh;
width: 100vw;
top: 0;
left: 0;
right: 0;
bottom: 0;
position: fixed;
z-index: 99999999;
pointer-events: none;
.movable-view {
width: 200rpx;
height: 200rpx;
pointer-events: auto;
.box {
width: 200rpx;
height: 200rpx;
display: flex;
justify-content: center;
align-items: center;
.newProblem {
width: 100rpx;
height: 100rpx;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
background: #ffffff;
border-radius: 50%;
border: 1px solid #a6a6a6;
image {
width: 30rpx;
height: 30rpx;
}
text {
margin-top: 10rpx;
font-size: 24rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #000000;
}
}
}
}
}
</style>
5.有自定义导航栏的特殊处理
<template>
<view>
<movable-area class="movable-area" :style="{'margin-top': isCustom ? 'calc(88rpx + ' + statusBarHeight + 'rpx)' : '0px', 'height' : isCustom ? 'calc(100vh - 90rpx - '+ statusBarHeight + 'rpx' +')': 'calc(100vh - 2rpx)' }">
<movable-view
class="movable-view"
:x="moveX"
:y="moveY"
direction="all"
@change="handleMove"
>
<view class="box">
<view class="newProblem" @click="service">
<image src="https://dl.essmall.cn/minapp/static/kf.png"></image>
<text>客服</text>
</view>
</view>
</movable-view>
</movable-area>
</view>
</template>
<script>
import { mapState } from "vuex";
export default {
props: {
isCustom: {
type: Boolean,
default: false,
},
statusBarHeight: {
type: Number,
default: 0,
},
},
data() {
return {
x: 1000,
y: 1000,
timer: null,
};
},
computed: {
...mapState(["hasUserInfo", "moveX", "moveY"]),
},
methods: {
service() {
if (!this.hasUserInfo) {
uni.reLaunch({
url: "/pages/authorization/index",
});
return;
}
uni.navigateTo({
url: "/mineInfo/service/service",
});
},
handleMove(event) {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
const { x, y } = event.detail;
this.$store.commit("changeMoveXY", { x, y });
}, 200);
},
},
};
</script>
<style lang="less">
.movable-area {
background-color: red;
height: 100vh;
width: 100vw;
top: 0;
left: 0;
right: 0;
bottom: 0;
position: fixed;
z-index: 99999999;
pointer-events: none;
.movable-view {
width: 200rpx;
height: 200rpx;
pointer-events: auto;
.box {
width: 200rpx;
height: 200rpx;
display: flex;
justify-content: center;
align-items: center;
.newProblem {
width: 100rpx;
height: 100rpx;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
background: #ffffff;
border-radius: 50%;
border: 1px solid #a6a6a6;
image {
width: 30rpx;
height: 30rpx;
}
text {
margin-top: 10rpx;
font-size: 24rpx;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #000000;
}
}
}
}
}
</style>