food_wechat/pages/shop/list.vue
sszdot 5b6787aa49 【类 型】:docs
【原  因】:和main目录下 的order组件重名
【过  程】:shop目录下order组件更名为confirm
【影  响】:

# 类型 包含:
# feat:新功能(feature)
# fix:修补bug
# docs:文档(documentation)
# style: 格式(不影响代码运行的变动)
# refactor:重构(即不是新增功能,也不是修改bug的代码变动)
# test:增加测试
# chore:构建过程或辅助工具的变动
2024-12-18 17:59:59 +08:00

368 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="vh100 flex column">
<!-- topbar -->
<u-navbar title="开始点餐" bgColor="#d43030" :titleStyle="{ color: '#FFF'}" :autoBack="true" placeholder>
<view class="u-nav-slot" slot="left">
<u-icon name="arrow-left" color="#fff" size="19"></u-icon>
</view>
</u-navbar>
<!-- 地址框 -->
<view class="flex column p-24 borderB bg-w">
<view class="flex md">
<view class="fz36 siteBox l-h-18">{{siteCon.sitename}}</view>
<u--image src="/static/icons/pulldown-40.svg" width="40rpx" height="40rpx"></u--image>
</view>
<view class="fcb l-h-12">{{siteCon.describe}}</view>
<view class="fcb l-h-12">营业时间{{shopCon.opening_time | formatTime}}{{shopCon.closeing_time | formatTime}}
</view>
</view>
<!-- 列表框 -->
<view class="flex1 flex ofh">
<!-- 左侧导航 -->
<scroll-view class="u-tab-view menu-scroll-view" scroll-y scroll-with-animation :scroll-top="scrollTop"
:scroll-into-view="itemId">
<!-- 导航项目 -->
<view class="u-tab-item" v-for="(item,index) in menuList" :key="index" @tap.stop="swichMenu(index)"
:class="current==index?'borderno':'borderB'">
<!-- 当前选中显示 -->
<view class="p-l-24 menuImg" :class="current==index?'menuImgH':''">
<u--image :src="item.photo[0]" :width="current==index?'80rpx':'0rpx'"
:height="current==index?'80rpx':'0rpx'"></u--image>
</view>
<!-- 项 -->
<view class="radRT16 p-l-24 menuItem fz32" :class="current==index?'menuItemH fci fb':''">
<view class="tc">{{item.name}}</view>
</view>
</view>
<!-- 底部空白占位 -->
<view class="extra-space1"></view>
</scroll-view>
<!-- 右侧列表内容 -->
<scroll-view class="flex1 right-box" scroll-y="true" scroll-with-animation @scroll="rightScroll"
:scroll-top="scrollRightTop">
<!-- 列表项目组 -->
<view class="class-item p-l-24 p-r-24" v-for="(item , index) in menuList" :key="index"
:id="'item+1' + index">
<!-- 项目标题 -->
<view class="flex m-t-24 m-b-12">
<u--image :src="item.photo[0]" width="48rpx" height="48rpx"></u--image>
<view style="margin-left:8rpx;line-height: 48rpx;">{{item.name}}</view>
</view>
<!-- 项目列表 -->
<view>
<listItem v-for="spuItem in spuList" :key="spuItem.id" :spu="spuItem"
v-if="item.path === spuItem.path">
</listItem>
</view>
</view>
<!-- 底部空白占位 -->
<u-divider text="没有更多了" :hairline="true"></u-divider>
<view class="extra-space2"></view>
</scroll-view>
</view>
<!-- 购物车按钮 -->
<view class="p-l-24 p-r-24 cartBox">
<view v-if="total === 0" class="rad16 bg-g flex ofh" style="height: 108rpx;">
<view class="bg-b" style="width: 152rpx;"></view>
<view class="flex1 flex mac p-l-24">
<u--image src="/static/icons/cafe-48.svg" width="96rpx" height="96rpx" />
<view class="m-l-12 fz36 fb">未选购餐品</view>
</view>
</view>
<view v-else class="bg-m rad16 flex" style="height: 108rpx;">
<view class="flex md p-b-12">
<u--image src="/static/icons/planeBox-100.svg" width="136rpx" height="136rpx"
@click="$store.commit('setCartShow',!$store.state.cartShow)" />
</view>
<view class="fci fz36 flex1 flex msb">
<view class="flex1 p-l-12 flex column mc"
@click="$store.commit('setCartShow',!$store.state.cartShow)">
<view class="fz36 fb">¥{{total | formatPrice}}</view>
<view class="fz24" v-if="minimumOrderDifference>0">还差¥{{minimumOrderDifference | formatPrice}}起送
</view>
</view>
<view class="flex column mac mc" style="width: 180rpx;" @click="handleSeled">
<view class="fz36">选好了</view>
<view class="fz24">Order</view>
</view>
</view>
</view>
</view>
<!-- 购物车折叠层 -->
<cartFold></cartFold>
</view>
</template>
<script>
import {
formatTime,
formatPrice,
totalPrice
} from '@/utils/index.js'
export default {
data() {
return {
//列表导航 列表容联动 相关
scrollTop: 0, //tab标题的滚动条位置
oldScrollTop: 0,
current: 0, // 预设当前项的值
menuHeight: 0, // 左边菜单的高度
menuItemHeight: 0, // 左边菜单item的高度
itemId: '', // 栏目右边scroll-view用于滚动的id
menuItemPos: [],
arr: [], //记录 右边菜单每个item到顶部的距离
scrollRightTop: 0, // 右边栏目scroll-view的滚动条高度
timer: null, // 定时器
isScrollingByClick: false, // 添加这个标志 解决点击左侧导航栏点击 右侧内容滚动之后 反过来影响左侧导致跳变
scrollingTiemout: null, //timeout对象
}
},
onReady() {
this.getMenuItemTop()
},
onShow() {
// 当页面显示时设置tabber的激活项
this.$store.commit('setTabbarCurrent', 1)
},
watch: {
// 'spuList': {
// handler(newVal, oldVal) {
// console.log("spuList 发生变化")
// console.log("新值:", newVal)
// console.log("旧值:", oldVal)
// // 更新其他状态或执行其他操作
// // this.someOtherFunction()
// },
// deep: true // 如果需要深度监视对象或数组的变化则需要设置为true
// }
},
computed: {
//站点信息
siteCon() {
return this.$store.state.siteList.find(item => item.id === this.$store.state.site_id.toString())
},
//商品信息
shopCon() {
return this.$store.state.shopCon
},
//起送差价
minimumOrderDifference() {
return Number(this.shopCon.price_min) - Number(this.total)
},
//分类列表
menuList() {
return this.$store.state.menuList
},
//spu列表
spuList() {
return this.$store.state.spuList
},
//购物车总价
total() {
return this.totalPrice(this.$store.state.cartList)
}
},
methods: {
// 购物车价格总和
totalPrice,
// 点击左边的栏目切换
async swichMenu(index) {
clearTimeout(this.scrollingTiemout) //每次点击导航栏重置timeout延时
this.isScrollingByClick = true
if (this.arr.length == 0) {
await this.getMenuItemTop()
}
if (index == this.current) return
this.scrollRightTop = this.oldScrollTop
this.$nextTick(function() {
this.scrollRightTop = this.arr[index]
this.current = index
this.leftMenuStatus(index)
})
this.scrollingTiemout = setTimeout(() => {
this.isScrollingByClick = false
}, 800)
},
// 获取一个目标元素的高度
getElRect(elClass, dataVal) {
new Promise((resolve, reject) => {
const query = uni.createSelectorQuery().in(this)
query.select('.' + elClass).fields({
size: true
}, res => {
// 如果节点尚未生成res值为null循环调用执行
if (!res) {
setTimeout(() => {
this.getElRect(elClass)
}, 10)
return
}
this[dataVal] = res.height
resolve()
}).exec()
})
},
// 观测元素相交状态
async observer() {
this.listData.map((val, index) => {
let observer = uni.createIntersectionObserver(this);
// 检测右边scroll-view的id为itemxx的元素与right-box的相交状态
// 如果跟.right-box底部相交就动态设置左边栏目的活动状态
observer.relativeTo('.right-box', {
top: 0
}).observe('#item' + index, res => {
if (res.intersectionRatio > 0) {
let id = res.id.substring(4)
this.leftMenuStatus(id)
}
})
})
},
// 设置左边菜单的滚动状态
async leftMenuStatus(index) {
this.current = index;
// 如果为0意味着尚未初始化
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
await this.getElRect('menu-scroll-view', 'menuHeight')
await this.getElRect('u-tab-item', 'menuItemHeight')
}
// 将菜单活动item垂直居中
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2
},
// 获取右边菜单每个item到顶部的距离
getMenuItemTop() {
new Promise(resolve => {
let selectorQuery = uni.createSelectorQuery()
selectorQuery.selectAll('.class-item').boundingClientRect((rects) => {
// 如果节点尚未生成rects值为[](因为用selectAll所以返回的是数组),循环调用执行
if (!rects.length) {
setTimeout(() => {
this.getMenuItemTop()
}, 10)
return
}
rects.forEach((rect) => {
// 这里减去rects[0].top是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
this.arr.push(rect.top - rects[0].top)
resolve()
})
}).exec()
})
},
// 右边菜单滚动
async rightScroll(e) {
this.oldScrollTop = e.detail.scrollTop
if (this.arr.length == 0) {
await this.getMenuItemTop()
}
if (this.timer) return
if (!this.menuHeight) {
await this.getElRect('menu-scroll-view', 'menuHeight')
}
setTimeout(() => { // 节流
this.timer = null
// scrollHeight为右边菜单垂直中点位置
let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
for (let i = 0; i < this.arr.length; i++) {
let height1 = this.arr[i]
let height2 = this.arr[i + 1]
// 如果不存在height2意味着数据循环已经到了最后一个设置左边菜单为最后一项即可
if (!height2 || scrollHeight >= height1 && scrollHeight < height2) {
if (!this.isScrollingByClick) {
this.leftMenuStatus(i)
}
return
}
}
}, 10)
},
//"选好了"执行
handleSeled() {
const regex = /^(\+?\d{1,4}[\s-]?)?\d{3}\*{4}\d{4}$/
if (regex.test(this.$store.state.userInfo.tel)) { //手机号合法
uni.navigateTo({ //跳转到订单页面
url: '/pages/shop/confirm'
})
} else { //手机号不合法 获取为空
uni.navigateTo({ //跳转到获取手机号页面
url: '/pages/main/getTel'
})
}
}
},
filters: {
formatTime, //格式化时间
formatPrice //格式化价格
}
}
</script>
<style lang="scss" scoped>
.topbar {
background-color: $uni-color-error;
height: 176rpx;
}
.backBut {
margin-left: 32rpx;
}
.topTit {
margin-right: 104rpx;
margin-bottom: 24rpx;
}
.siteBox {
height: 54rpx;
line-height: 54rpx;
}
.u-tab-view {
width: 160rpx;
}
.menuImg {
height: 0rpx;
padding-right: 8rpx;
transform: rotate(90deg);
opacity: 0;
transition: all 0.25s ease;
}
.menuImgH {
height: 48rpx;
opacity: 1;
transform: rotate(0deg);
}
.menuItem {
padding-right: 8rpx;
}
.menuItem view {
line-height: 88rpx;
}
.menuItemH {
background-color: $uni-color-error;
}
.extra-space1 {
height: 400rpx;
}
.extra-space2 {
height: 200rpx;
}
.cartBox {
z-index: 10071;
width: calc(100vw - 48rpx);
height: 156rpx;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.7) 70%, rgba(255, 255, 255, 1) 100%);
position: absolute;
bottom: 0rpx;
}
</style>