vue 开发 滑动页面中出现tabs 并且需要分页的

本文介绍了如何在Vue应用中使用`scroll-view`组件构建一个具有tabs栏和分页功能的电影订单列表,展示了组件的代码实现,包括高度计算和列表布局的注意事项。
摘要由CSDN通过智能技术生成

效果

需求

我们这个页面顶部有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 的了 摆脱了 最外面的大盒子的滑动

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值