| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- <template>
- <view>
- <view
- class="serve"
- :style="{ left: left + 'rpx', top: top + 'rpx' }"
- @touchstart="onTouchStart"
- @touchmove="onTouchMove"
- @touchend="onTouchEnd"
- >
- <view class="serve-content">
- <image class="w130 h130"
- src="/static/images/server.png"
- mode="aspectFit"></image>
- <text class="text">官方客服</text>
- <button class="contact-btn" open-type="contact"></button>
- </view>
- </view>
- </view>
- </template>
- <script>
- export default {
- name:"Server",
- data() {
- return {
- left: 0,
- top: 0,
- startX: 0,
- startY: 0,
- isDragging: false,
- screenWidth: 0,
- screenHeight: 0
- };
- },
- mounted() {
- this.getSystemInfo();
- this.initPosition();
- },
- methods: {
- // 初始化位置
- initPosition() {
- // 从本地存储加载位置
- const position = uni.getStorageSync('server_position');
- if (position) {
- this.left = position.left;
- this.top = position.top;
- } else {
- // 默认位置:右侧80%高度
- this.left = 750 - 150 - 20; // 屏幕宽度 - 容器宽度 - 右边距
- this.top = this.px2rpx(this.screenHeight * 0.8 - 75); // 80%高度,居中偏移
- }
- },
-
- // 获取系统信息
- getSystemInfo() {
- uni.getSystemInfo({
- success: (res) => {
- this.screenWidth = res.windowWidth;
- this.screenHeight = res.windowHeight;
- }
- });
- },
-
- // 触摸开始
- onTouchStart(e) {
- // 阻止事件冒泡,不影响其他元素
- e.stopPropagation();
- e.preventDefault();
-
- this.startX = e.touches[0].clientX;
- this.startY = e.touches[0].clientY;
- this.isDragging = false;
- },
-
- // 触摸移动
- onTouchMove(e) {
- // 阻止事件冒泡和默认行为
- e.stopPropagation();
- e.preventDefault();
-
- if (!this.startX || !this.startY) return;
-
- const currentX = e.touches[0].clientX;
- const currentY = e.touches[0].clientY;
-
- const diffX = currentX - this.startX;
- const diffY = currentY - this.startY;
-
- // 判断是否开始拖拽(移动超过5px)
- if (!this.isDragging && (Math.abs(diffX) > 5 || Math.abs(diffY) > 5)) {
- this.isDragging = true;
- }
-
- if (this.isDragging) {
- // 计算新的位置(rpx)
- const newLeft = this.rpx2px(this.left) + diffX;
- const newTop = this.rpx2px(this.top) + diffY;
-
- // 边界检查
- const boundedLeft = Math.max(10, Math.min(newLeft, this.screenWidth - this.rpx2px(150)));
- const boundedTop = Math.max(10, Math.min(newTop, this.screenHeight - this.rpx2px(150)));
-
- // 转换回rpx
- this.left = this.px2rpx(boundedLeft);
- this.top = this.px2rpx(boundedTop);
-
- // 更新起始位置
- this.startX = currentX;
- this.startY = currentY;
- }
- },
-
- // 触摸结束
- onTouchEnd(e) {
- // 阻止事件冒泡
- e.stopPropagation();
- e.preventDefault();
-
- if (this.isDragging) {
- // 吸边效果
- this.attachToEdge();
- // 保存位置
- this.savePosition();
- }
- this.startX = 0;
- this.startY = 0;
- this.isDragging = false;
- },
-
- // 吸边效果
- attachToEdge() {
- const containerWidth = 150; // 容器宽度
- const screenWidthRpx = 750;
- const centerX = screenWidthRpx / 2;
-
- // 根据当前位置决定吸附到左边还是右边
- if (this.left < centerX) {
- this.left = 20; // 吸附到左边
- } else {
- this.left = screenWidthRpx - containerWidth - 20; // 吸附到右边
- }
- },
-
- // 保存位置到本地存储
- savePosition() {
- uni.setStorageSync('server_position', {
- left: this.left,
- top: this.top
- });
- },
-
- // rpx转px
- rpx2px(rpx) {
- return rpx / 750 * this.screenWidth;
- },
-
- // px转rpx
- px2rpx(px) {
- return px * 750 / this.screenWidth;
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .serve{
- position: fixed;
- z-index: 9999;
- width: 150rpx;
- height: 150rpx;
-
- // 确保拖拽时不影响其他元素
- touch-action: none;
- user-select: none;
- -webkit-user-select: none;
-
- .serve-content {
- width: 100%;
- height: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- position: relative;
-
- // 拖拽时的视觉反馈
- &:active {
- opacity: 0.9;
- transition: opacity 0.2s ease;
- }
- }
-
- .w130 {
- width: 130rpx !important;
- height: 130rpx !important;
- flex-shrink: 0; // 防止图片变形
- }
-
- .h130 {
- width: 130rpx !important;
- height: 130rpx !important;
- flex-shrink: 0; // 防止图片变形
- }
-
- .text{
- margin-top: 8rpx;
- font-weight: 500;
- font-size: 24rpx;
- color: #333;
- background: rgba(255, 255, 255, 0.9);
- padding: 6rpx 12rpx;
- border-radius: 20rpx;
- white-space: nowrap;
- flex-shrink: 0; // 防止文字变形
- border: 1rpx solid rgba(0, 0, 0, 0.1);
- backdrop-filter: blur(10rpx);
- }
-
- .contact-btn {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- opacity: 0;
- z-index: 10;
- // 确保按钮不变形
- border: none;
- border-radius: 0;
- background: transparent;
- padding: 0;
- margin: 0;
-
- &::after {
- border: none;
- }
- }
- }
- // 防止拖拽时页面滚动
- page {
- overflow: hidden;
- height: 100%;
- }
- </style>
|