uni-app卖座电影多端开发纪实(四):用户交互

223 阅读2分钟

@Tabs切换 + 分页加载

Tabs切换效果图

image.png

正在加载效果图

image.png

没有更多效果图

image.png

@uView组件使用

uView/Tabs的使用

uView/Tabs文档 先搂一眼!

uView/loadMore的使用

uView/loadMore文档先搂一眼!

@准备工作

电影条目组件封装

components/FilmItem.vue

<template>
   <!-- 点击跳转详情页 -->
   <view
      class="item"
      @click="toDetail(item.filmId)">
      <view class="left">
         <image
            :src="item.poster"
            alt=""
            mode="widthFix" />
      </view>

      <view class="middle">
         <view>
            <text class="name">{{ item.name }}</text>
            <text class="dimension">{{ item.filmType.name }}</text>
         </view>
         <view>
            观众评分
            <text class="grade">{{ item.grade }}</text>
         </view>
         <view class="actors"> 主演:{{ item.actors.map(({ name }) => name).join(" ") }} </view>
         <view>{{ item.nation }} | {{ item.runtime }}分钟</view>
      </view>

      <view class="right">
         <button
            class="ticket"
            v-show="isOnShow || item.isPresale">
            {{ isOnShow ? "购票" : "预购" }}
         </button>
      </view>
   </view>
</template>

<script>
export default {
   props: ["item", "isOnShow"],
   methods: {
      /* 跳转详情页 */
      toDetail(filmId) {
         console.log("toDetail", filmId);

         // 跳转页面
         uni.navigateTo({
            url: `/pages/sub/detail/detail?filmid=${filmId}`,
         });
      },
   },
};
</script>

<style lang="scss">...</style>

没有更多组件封装

components/NoMoreItem.vue

<template>
   <view class="wrapper"> -无更多电影- </view>
</template>

<script></script>

<style>
.wrapper {
   background-color: #eee;
   color: #bdc0c5;
   height: 100rpx;
   line-height: 100rpx;
   text-align: center;
   font-size: 0.8rem;
}
</style>

电影列表组件封装

  • 这个组件符合 easy-com 规范,页面模板可以直接使用!

components/my-film-list/my-film-list.vue

<template>
   <view class="wrapper">
      <!-- <text>正在热映</text> -->
      <!-- <text>{{text}}</text> -->

      <FilmItem
         v-for="item in films"
         :key="item.filmId"
         :item="item"
         :is-on-show="true" />

      <!-- 数据加载完毕时显示没有更多组件 -->
      <NoMoreItem v-if="films.length >= total"></NoMoreItem>

      <!-- 否则显示【Loadmore组件】 -->
      <!-- API请参考:http://v1.uviewui.com/components/loadMore.html -->
      <u-loadmore
         v-else
         bg-color="#eee"
         style="height: 50px; line-height: 50px"
         :status="status" />
   </view>
</template>

<script>
/* 不符合easy-com规范的组件要引入+声明 */
import FilmItem from "../FilmItem.vue";
import NoMoreItem from "../NoMoreItem.vue";

export default {
   /* 不符合easy-com规范的组件要引入+声明 */
   components: {
      FilmItem,
      NoMoreItem,
   },

   // 没什么卵用,只是测试,好使!
   expose: ["sayHello"],

   props: {
      // 要展示的电影数据
      films: {
         type: Array,
         default() {
            return [];
         },
      },

      // 当前列表中的影片是否在映,在映就显示一个购票按钮,否则不显示
      isOnShow: {
         type: Boolean,
         default: true,
      },

      // 当前列表的数据总量
      total: {
         type: Number,
         default: 0,
      },

      // LoadMore组件的状态,默认可以加载更多
      // API请参考:http://v1.uviewui.com/components/loadMore.html
      status: {
         type: String,
         default: "loadmore",
      },
   },

   methods: {
      sayHello() {
         console.log("hello from my-film-list");
      },
   },
};
</script>

<style>
.wrapper {
   /* margin-bottom: 150px; */
   height: 100%;
}
</style>

@主业务逻辑

  • 代码全部来自 pages/film/film.vue

页面部署Tabs

  <my-navbar
     v-show="showNavbar"
     :title="title">
  </my-navbar>

  <!-- Tabs吸顶时覆盖Navbar -->
  <u-sticky z-index="100">
     <!-- 这个元素用于撑开Tabs的高度,以完全覆盖Navbar -->
     <view style="height: 50rpx; background-color: white"></view>

     <!-- 具体属性含义请参考:http://v1.uviewui.com/components/tabs.html -->
     <u-tabs
        :height="100"
        :bold="false"
        :offset="[0, 0]"
        bar-height="3"
        bar-width="120"
        active-color="#FF5F16"
        :list="list"
        :is-scroll="false"
        :current="current"
        @change="change"></u-tabs>
  </u-sticky>
  
  <view
     class="page"
     style="margin-top: 5rpx">

     <!-- <playings v-if="current===0"></playings> -->
     <!-- <comings v-else></comings> -->

     <!-- 数据展示组件 -->
     <my-film-list
        ref="refMFL"
        :films="list[current].films"
        :total="list[current].total"
        :status="list[current].status"
        :isOnShow="list[current].isOnShow">
     </my-film-list>
  </view>

Tabs的配置

   data() {
      return {
         title: "电影",
         showNavbar: true,

         /* tabs的相关配置 */
         list: [
            {
               name: "正在热映",
               type: 1, //服务端接口参数 1=正在热映 2=即将上映
               isOnShow: true,
               films: [], //当前tab子页面对应的数据
               total: 1, //总数据量,至少会有一条数据
               page: 0, //分页加载
               status: "loadmore", //u-loadmore组件的状态
            },
            {
               name: "即将上映",
               type: 2,
               isOnShow: false,
               films: [],
               total: 1,
               page: 0,
               status: "loadmore",
            },
         ],

         // 默认选中第0个tab
         current: 0,
      };
   },

Tabs切换回调

   methods: {
      /* tabs切换时的回调 */
      change(index) {
         console.log("tab change", index);
         this.current = index;
         this.loadData(this.current);
      },
      ...
   }

加载数据方法

   methods: {
      /* tabs切换时的回调 */
      change(index) {...},

      /* 根据tabs序号加载数据 */
      loadData(current) {
         console.log("loadData:current=", current);

         /* 如果u-loadmore组件正在加载 或者当前tab的所有数据均已加载完毕 就什么都不做 直接返回 */
         if (
            this.list[current].status === "loading" ||
            this.list[current].films.length >= this.list[current].total
         ) {
            console.log("this.list[current].films.length", this.list[current].films.length);
            console.log("this.list[current].total", this.list[current].total);
            console.log("loadData RETURNED!");
            return;
         }

         /* 当前tab页码加加 u-loadmore组件标记正在加载 */
         this.list[current].page++;
         this.list[current].status = "loading";

         /* 调用服务端接口获取数据 */
         /*cityId=310100&pageNum=1&pageSize=10&type=1&k=9105116*/
         uni.request({
            url: "https://m.maizuo.com/gateway",

            // GET参数
            data: {
               cityId: "310100",
               pageNum: this.list[current].page, //页码
               pageSize: 10,
               type: this.list[current].type, //1=正在热映 2=即将上映
               k: 9105116,
            },

            //自定义请求头信息
            header: {
               "X-Host": "mall.film-ticket.film.list",
            },

            // 加载数据成功
            success: res => {
               /* 留多点时间看每秒的loading动画 */
               setTimeout(() => {
                  // console.log(res);
                  // this.text = 'request success';

                  /* 同步数据给当前tab */
                  this.list[current].films.push(...res.data.data.films);
                  this.list[current].total = res.data.data.total;

                  /* 数据全部加载完毕时 u-loadmore组件标记状态为加载完毕 否则标记为仍可继续加载 */
                  if (this.list[current].films.length >= this.list[current].total) {
                     this.list[current].status = "nomore";
                  } else {
                     this.list[current].status = "loadmore";
                  }

                  console.log("success", this.list);
               }, 500);
            },

            // 失败回调
            fail(err) {
               console.log("fail:err=", err);
               this.status = "nomore";
            },
         });
      },
   },

用户触发Tabs切换

methods: {
  /* tabs切换时的回调 */
  change(index) {
     console.log("tab change", index);
     this.current = index;

     //  为当前tab加载数据
     this.loadData(this.current);
  },
  ...
}

用户上拉见底时加载下一页

/* 上拉见底时为当前tab加载下一页数据 */
/* onReachBottom为页面级组件独有的一个“生命周期” */
onReachBottom() {
  console.log("onReachBottom");
  this.loadData(this.current);
},

@源码地址

😈 点赞收藏加关注了吗??

image.png

本项目源码 watch,follow,fork!!!

祝大家撸码愉快~