uni-app卖座电影多端开发纪实(三):MVC

194 阅读1分钟

@引子

  • 这一部分就与纯Vue开发毫无二致了!
  • 这里分别用mock数据和真实后台数据举例

@数据层开发(mock)

准备一个mock数据

mock/cinemas.json

{
   "status": 0,
   "data": {
      "cinemas": [
         {
            "cinemaId": 4592,
            "name": "广州中影火山湖电影城东山口店",
            "address": "广州市越秀区农林下路4-6号锦轩现代城四楼",
            "longitude": 113.30225398514183,
            "latitude": 23.131955910292614,
            "gpsAddress": "113.30225398514183:23.131955910292614",
            "cityId": 440100,
            "cityName": "广州市",
            "districtId": 440104,
            "districtName": "越秀区",
            "district": {
               "districtId": 440104,
               "name": "越秀区"
            },
            "phone": "020-87623898/020-87623868",
            "telephones": ["020-87623898/020-87623868"],
            "logoUrl": "https://pic.maizuo.comusr/4592/d9c024195d4b26dae7ad7226082d8d74.jpg",
            "businessTime": "09:30-10:30",
            "notice": "",
            "isVisited": 0,
            "lowPrice": 4900,
            "Distance": 0.79734212896387,
            "eTicketFlag": 1,
            "seatFlag": 1,
            "ticketTypes": null
         },
         ...
      ]
   },
   "msg": "ok"
}

接口开发

api/location.js

export async function getCinemas() {
   // 从本地json读入数据并解构出影院列表
   const {
      data: { cinemas },
   } = await import("../mock/cinemas.json");

   // 返回影院列表
   return cinemas;
}

@组件开发(mock)

调度层

pages/cinema/cinema.vue

<script>
// 引入api
import { getCinemas } from "../../api/location";

export default {
   data() {
      return {
         current: 1,
         title: "影院",
         showNavbar: true,
         cinemas: null,
      };
   },

   /* 组件挂载完毕后获取数据并交给视图 */
   async mounted() {
      // 调用API获取影院数据
      const cinemas = await getCinemas();

      // 丢给组件实例去“数据驱动视图”
      this.cinemas = cinemas;
      console.log("cinemas[0]=", cinemas[0]);
   },
};
</script>

视图层

pages/cinema/cinema.vue

<template>
   <view class="wrapper">
      <!-- 导航栏 -->
      <my-navbar
         v-show="showNavbar"
         :title="title"></my-navbar>

      <!-- 主内容区:支持HTML原生标签 -->
      <view
         class="page"
         style="margin-top: 50rpx">
         <!-- 数据内容 -->
         <ul v-if="cinemas">
            <li
               class="li-cinema"
               v-for="item in cinemas"
               :key="item.cinemaId">
               <div class="div-left">
                  <p class="p-name">{{ item.name }}</p>
                  <p class="p-address">{{ item.address }}</p>
               </div>

               <div class="div-right">
                  <p class="p p-price">
                     <span class="span"></span>
                     {{ item.lowPrice / 100 + "起" }}
                  </p>
                  <p class="p p-distance">{{ item.Distance.toFixed(2) + "km" }}</p>
               </div>
            </li>
         </ul>
      </view>

      <!-- Tabbar -->
      <tabbar></tabbar>
   </view>
</template>
<style lang="scss">
@import "../../static/variable.scss";

.wrapper {
   display: flex;
   flex-direction: column;
   height: 100vh;
   // background-color: #eee;

   .page {
      flex-grow: 1;
   }

   .li-cinema {
      display: flex;
      align-items: center;
      height: 70px;
      border-bottom: 1px solid #eee;
      padding: 0 1rem;

      .div-left {
         flex-grow: 4;

         .p-name,
         .p-address {
            @include singleLineElipsis(18rem);
         }

         .p-name {
            font-size: 1rem;
            margin-bottom: 0.5rem;
         }

         .p-address {
            font-size: 0.7rem;
            color: #999;
            font-style: italic;
         }
      }

      .div-right {
         flex-grow: 1;

         .p {
            text-align: center;
         }

         .p-price {
            margin-bottom: 0.5rem;
            color: $myOrange;
            font-size: 0.8rem;

            .span {
               font-size: 0.75rem;
               font-style: italic;
               font-weight: 400;
            }
         }

         .p-distance {
            font-size: 0.75rem;
            color: #999;
         }
      }
   }
}
</style>

运行效果

image.png

@使用网络数据的MVC

  • 本例的M层没有剥离,大家明白意思就好!

调度层

pages/news/news.vue

<script>
export default {
   data() {
      return {
         title: "资讯", //导航栏标题
         showNavbar: true, //显示导航栏
         content: "",
      };
   },

   /* 组件挂载完毕时从网络获取数据 */
   mounted() {
      console.log("news mounted");

      /* 使用uni的网络API获取数据 */
      uni.request({
         // 接口地址
         url: "https://m.maizuo.com/gateway",

         // GET查询参数
         data: {
            actId: "ElzMZU125260",
         },

         // 服务端要求配置的请求头
         header: {
            "X-Host": "mall.act.static-page.info",
         },

         // 成功回调
         success: res => {
            console.log("success", res);
            // let content = res.data.data.data.content;
            // this.content = this.handleContent(content);

            // 数据驱动视图
            this.content = res.data.data.data.content;
         },

         // 失败回调
         fail: err => {
            console.log("fail", err);
         },
      });
   },
};
</script>

视图层

pages/news/news.vue

<template>
   <!-- 页面须有唯一根布局 -->
   <view class="wrapper">
      <!-- 这里是自己封装过的导航栏 -->
      <my-navbar
         v-show="showNavbar"
         :title="title"></my-navbar>

      <!-- 这里是内容区 -->
      <div
         style="margin-top: 50rpx"
         class="content"
         v-html="content"></div>

      <!-- 这里是自己封装过的Tabbar -->
      <!-- 已经注册为全局组件了,无需引入拿来直接用 -->
      <tabbar></tabbar>
   </view>
</template>

<style lang="scss">
.wrapper {
   display: flex;
   flex-direction: column;
   height: 100vh;
   background-color: #eee;

   .page {
      flex-grow: 1;
   }
}
</style>

运行效果

image.png


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

image.png

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

祝大家撸码愉快~