web-base-h5/components/cartBall.vue

212 lines
4.5 KiB
Vue

<template>
<view>
<movable-area class="movable-area">
<movable-view
class="quan"
:x="ballPosition.x"
:y="ballPosition.y"
direction="all"
:out-of-bounds="false"
:inertia="false"
:scale="false"
:disabled="false"
@change="onMovableChange"
@touchend="onMovableEnd"
@click.stop="handleClick"
>
<img :src="smallCarLength > 0 ? cart : cartEmpty" alt="" />
<view class="qiu" v-show="smallCarLength > 0">{{
smallCarLength
}}</view>
</movable-view>
</movable-area>
<u-popup
:show="downShow"
mode="bottom"
closeOnClickOverlay
closeable
round="10"
@close="close"
>
<view class="title">{{ '购物车' }}</view>
<cartBtmList
ref="cartBtmList"
@orderCallBack="orderCallBack"
></cartBtmList>
</u-popup>
</view>
</template>
<script>
import { mapGetters, mapActions } from 'vuex'
import cartBtmList from '@/components/cartBtmList.vue'
export default {
props: {
carLength: {
type: Number | String,
default: 0,
},
specialArea: {
type: Number | String,
default: 1,
},
},
components: {
cartBtmList,
},
data() {
return {
downShow: false,
cart: require('@/static/images/cart-not-empty.png'),
cartEmpty: require('@/static/images/cart-empty.png'),
// 拖动相关数据
ballPosition: {
x: 0,
y: 0,
},
isDragging: false,
screenInfo: {
width: 375,
height: 667,
},
}
},
computed: {
...mapGetters(['smallCarLength']),
},
created() {
this.getCar()
this.initPosition()
},
mounted() {
this.initPosition()
},
methods: {
// 初始化小球位置
initPosition() {
try {
// 获取屏幕信息
const systemInfo = uni.getSystemInfoSync()
this.screenInfo.width = systemInfo.windowWidth
this.screenInfo.height = systemInfo.windowHeight
// 设置初始位置为右下角 (使用rpx适配)
// movable-view 的坐标系统是基于父容器的
this.ballPosition.x = this.screenInfo.width - uni.upx2px(150) // 转换rpx到px
this.ballPosition.y = this.screenInfo.height * 0.6
} catch (error) {
console.error('获取屏幕信息失败:', error)
// fallback 位置
this.ballPosition.x = 250
this.ballPosition.y = 400
}
},
// movable-view 位置改变事件
onMovableChange(e) {
this.isDragging = true
// movable-view 会自动处理边界检测
this.ballPosition.x = e.detail.x
this.ballPosition.y = e.detail.y
},
// movable-view 触摸结束事件
onMovableEnd(e) {
// 延迟重置拖动状态,避免立即触发点击
setTimeout(() => {
this.isDragging = false
}, 100)
},
// 处理点击事件
handleClick() {
// 如果正在拖动,不触发点击事件
if (this.isDragging) {
return
}
this.goCart()
},
close() {
this.downShow = false
this.getCar()
},
getCar() {
this.$store.dispatch('getCarLength', this.specialArea)
},
goCart() {
this.downShow = true
this.$nextTick(() => {
this.$refs.cartBtmList.getCarList(this.specialArea)
})
// uni.switchTab({ url: '/pages/shoppingCar/index' })
},
orderCallBack() {
this.close()
},
},
}
</script>
<style lang="scss" scoped>
.title {
font-size: 40rpx;
text-align: center;
margin: 20rpx auto;
color: #333;
font-weight: bold;
}
.movable-area {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 10;
pointer-events: none; /* 让区域本身不阻挡其他元素的交互 */
}
.quan {
background: #fff;
border-radius: 50%;
box-shadow: 0px 2px 20px 0px rgba(204, 204, 204, 1);
width: 100rpx;
height: 100rpx;
display: flex;
justify-content: center;
align-items: center;
pointer-events: auto; /* 让小球本身可以交互 */
img {
width: 60rpx;
height: 60rpx;
position: relative;
pointer-events: none; /* 防止图片阻止触摸事件 */
}
.qiu {
position: absolute;
width: 30rpx;
height: 30rpx;
background: #e03030;
border-radius: 50%;
color: #fff;
text-align: center;
line-height: 30rpx;
right: 0;
top: -10rpx;
font-size: 20rpx;
pointer-events: none; /* 防止数字阻止触摸事件 */
}
}
::v-deep .u-popup__content {
overflow: hidden;
}
</style>