效果
需求
我们这个页面顶部有tabs 栏 而且可以滑动到底部 进行分页
实现这样的页面我们应该怎么做 你应该会想到scroll-view 这个组件吧
下面我们来详情介绍一下这个页面的实现和功能开发
首先展示一下代码
item 循环项
<template>
<div class="wechat-order-item-container">
<div class="box">
<div class="header">
<div class="cinema-name">金逸影城(安庆星光荟店)</div>
<div class="status">订单超时</div>
</div>
<div class="content">
<div class="movie-img">
<image
src="https://gw.alicdn.com/tfscom/i3/O1CN01s4djbH29FutyK4fzY_!!6000000008039-0-alipicbeacon.jpg_300x300.jpg"
style="width: 90px; border-radius: 5px"
mode="widthFix"
></image>
</div>
<div class="movie-data">
<div class="name marginTop">我们一起摇太阳</div>
<div class="time marginTop">2024-04-15 21:30:00</div>
<div class="hall marginTop color858a99">4号激光厅</div>
<div class="address marginTop color858a99">
宜秀区独秀大道安庆星光荟第四层
</div>
<div class="seat marginTop color858a99">4排六座</div>
</div>
<div class="right">
<div class="city">安庆市</div>
<div class="num">共1张</div>
<div class="price">¥45.00</div>
</div>
</div>
<div class="footer">
<div class="timer">创建时间:2024-04-15 17:34</div>
<div class="btn">
<nut-button
plain
type="default"
size="small"
style="border: 1px solid #eee"
>订单详情</nut-button
>
</div>
</div>
</div>
</div>
</template>
<script setup></script>
<style lang="scss">
.wechat-order-item-container {
background-color: #fff;
padding: 20px 25px;
font-size: 26px;
border-radius: 15px;
.box {
.header {
color: #858a99;
padding-bottom: 20px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #f7f8f9;
.cinema-name {
}
.status {
font-size: 24px;
}
}
.content {
padding: 20px 0;
border-bottom: 1px solid #f7f8f9;
display: flex;
.right {
flex: 1;
margin-left: 20px;
display: flex;
flex-direction: column;
align-items: center;
.city {
color: #15181d;
font-weight: 700;
}
.num {
}
.price {
color: #028fd4;
}
}
.movie-data {
margin-left: 20px;
.marginTop {
margin-top: 5px;
}
.color858a99 {
color: #858a99;
}
.name {
font-size: 26px;
color: #15181d;
font-weight: 700;
}
.time {
color: #028fd4;
}
}
}
.footer {
margin-top: 15px;
display: flex;
justify-content: space-between;
align-items: center;
.timer {
color: #858a99;
font-size: 24px;
}
}
}
}
</style>
这个算是 每一个item的代码 我把他封装成了一个组件
tabs 栏
<template>
<div class="filter-container">
<nut-tabs v-model="selected" title-scroll type="smile" title-gutter="10">
<nut-tab-pane v-for="item in tabList" :title="item.name"></nut-tab-pane>
</nut-tabs>
</div>
</template>
<script setup>
import { ref, watch, toRefs } from "vue";
const props = defineProps({
tabList: Array,
});
const emit = defineEmits(["onChange"]);
const { tabList } = toRefs(props);
const selected = ref(0);
//监听当前的tabs选中 变化出发自定一函数 子传父组件数据
watch(selected, (index) => {
emit("onChange", tabList.value[index]);
});
</script>
<style lang="less">
.filter-container {
.nut-tabs__content {
display: none !important;
}
.nut-tabs__list {
background-color: #fff;
}
.nut-tabs__titles {
// background: #ffffff !important;
.nut-tabs__titles-item {
.nut-tabs__titles-item__smile {
display: none;
}
.nut-tabs__titles-item__text {
color: #858a99;
font-size: 24px;
}
.nut-tabs__titles-item__line {
background: linear-gradient(to right, #028fd4, #028fd6) !important;
}
.nut-tabs__titles-item__smile .nut-icon {
color: #028fd4 !important;
}
}
.nut-tabs__titles-item.active {
.nut-tabs__titles-item__smile {
display: block;
margin-top: 10px !important;
}
.nut-tabs__titles-item__text {
color: #15181d;
}
}
}
}
</style>
我也把他封装成了一个组件 都是经过二次封装的
这个做法 巧妙的将每一项的item 的上下距离页拉开了
<template>
<div class="wechat-order-container">
<Tabbar></Tabbar>
<div class="wechat-list" :style="{ marginTop: `${tabbarHeight}` + 'px' }">
<Filter :tab-list="tabList" @onChange="handleClickTabs"></Filter>
<div
class="flex-list"
:style="{ height: `${listContainerHeight}` + 'px' }"
>
<template
v-if="list.length > 0 && listContainerHeight > 0"
:style="{ height: `${listContainerHeight}px` }"
>
<scroll-view
:scroll-y="true"
scrollAnchoring
@scrolltolower="onScrollBottom"
:scroll-top="scrollTop"
:style="{ height: `${listContainerHeight}` + 'px' }"
>
<div class="flex-item">
<Item></Item>
</div>
<div class="flex-item">
<Item></Item>
</div>
<div class="flex-item">
<Item></Item>
</div>
<div class="flex-item">
<Item></Item>
</div>
<div class="flex-item">
<Item></Item>
</div>
<div class="flex-item">
<Item></Item>
</div>
<div class="flex-item">
<Item></Item>
</div>
<div class="flex-item">
<Item></Item>
</div>
<div class="flex-item">
<Item></Item>
</div>
<div class="flex-item">
<Item></Item>
</div>
<!-- <Loading
:page="pageinfo.currentPage"
:total="totalpage"
:loadingFlag="loadingFlag"
:tipFlag="tipFlag"
>
</Loading> -->
</scroll-view>
</template>
<template v-else>
<nut-empty description="无数据"></nut-empty>
</template>
</div>
</div>
</div>
</template>
<script>
import { needLogin } from "../../../utils/needLoginHook";
export default {
mixins: [needLogin],
};
</script>
<script setup>
import { onMounted, ref, computed } from "vue";
import Taro, { useDidShow } from "@tarojs/taro";
import { storeToRefs } from "pinia";
import Tabbar from "../../../components/wx-tabbar/index.vue";
import Filter from "./filter.vue";
import { useTabbarStore } from "../../../store";
import Item from "./item.vue";
const tabbarStore = useTabbarStore();
const { selected, tabbarHeight } = storeToRefs(tabbarStore);
onMounted(() => {
tabbarStore.setSelected(1);
});
useDidShow(() => {
getListContainerHeight();
});
const list = ref([1, 2, 3]);
const scrollTop = ref(0);
const listContainerHeight = ref(0);
const tabList = ref([
{
id: 0,
name: "全部",
},
{
id: 1,
name: "已创建",
},
{
id: 2,
name: "已支付",
},
{
id: 3,
name: "已出票",
},
{
id: 4,
name: "已退票",
},
]);
//计算当前页面的高度
const getListContainerHeight = () => {
const query = Taro.createSelectorQuery()
.select(".flex-list")
.boundingClientRect();
query.selectViewport();
query.exec(function (res) {
if (res[0]) {
listContainerHeight.value = res[0].height;
}
});
};
//滑动到底部的执行方法
const onScrollBottom = () => {
console.log("到底了");
};
const handleClickTabs = () => {};
</script>
<style lang="scss">
.wechat-order-container {
height: 100%;
.wechat-list {
position: fixed;
left: 0;
right: 0;
bottom: 0;
top: 0;
display: flex;
flex-direction: column;
.flex-list {
flex: 1;
.flex-item {
padding: 10px 20px;
}
}
}
}
</style>
主页面的代码
详细介绍
scroll-view 是需要 高度的 这个高度 就是外面盒子的高度
高度计算
const getListContainerHeight = () => {
const query = Taro.createSelectorQuery()
.select(".flex-list")
.boundingClientRect();
query.selectViewport();
query.exec(function (res) {
if (res[0]) {
listContainerHeight.value = res[0].height;
}
});
};
这个外面的盒子需要去计算 我们计算scroll-view 的高度是和父组件的高度一致得
最后一个注意点
.wechat-list 这个盒子 是需要我们将他变为fixed 的定位 相当于操作就是 属于wechat-list 的了 摆脱了 最外面的大盒子的滑动