【生活美好】youya-vue

这是一个比较大的项目哦
先放上作者的github地址
https://github.com/z8985561/youya-vue
然后我们来大体看看有什么效果

接下来我们一起来分析项目啦
首先是main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import Axios from "axios";
import VueAxios from "vue-axios";
// 适配方案
import 'lib-flexible/flexible.js';

// 公共样式
import './assets/css/common.css';

import VueLazyload from 'vue-lazyload'

Vue.use(VueLazyload)

// 引入 vant-ui
import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);

Vue.config.productionTip = false

const IS_TEST = true;

// Axios 请求
Axios.defaults.timeout = 30000;
Axios.defaults.withCredentials = true;
Axios.interceptors.response.use(response => {
  if (response.status === 200) {
    if (!IS_TEST && response.data.code == 401) {
      window.console.log(response.data.code);
      window.location.href = `http://youya.chuncom.com/user/authorization?url=${encodeURIComponent(
              window.location.href
            )}`;
      return;
    }
    return Promise.resolve(response.data);
  } else {
    return Promise.reject(response.data);
  }
}, error => {
  if (error.response.status) {
    console.log(error)
    // switch (error.response.status) {
    //   case 401:
    //     router.replace({
    //       path: '/',
    //       query: {
    //         redirect: router.currentRoute.fullPath
    //       }
    //     });
    //     break;
    //   default:
    //     console.log(123)
    // }
    return Promise.reject(error.response);
  }
})
window.axios = Axios;

router.beforeEach((to, from, next) => {
  /* 路由发生变化修改页面title */
  if (to.meta.title) {
    document.title = to.meta.title
    // console.log(store)
  }
  next()
})
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

接下来就是router.js

import Vue from 'vue'
import Router from 'vue-router'
import Index from './views/Index.vue'

Vue.use(Router)

export default new Router({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [{
    // 首页
    path: '/',
    name: 'index',
    component: Index,
    meta: {
      title: "首页",
      keepAlive: true
    }
  },
  {
    // 课程
    path: '/video',
    name: 'video',
    component: () => import( /* webpackChunkName: "about" */ './views/Video.vue'),
    meta: {
      title: "课程",
      keepAlive: true
    }
  },
  {
    // 视频课程详情
    path: '/video_detail',
    name: 'video_detail',
    component: () => import( /* webpackChunkName: "about" */ './views/VideoDetail.vue'),
    meta: {
      title: "课程详情"
    }
  },
  // SharePosters.vue
  {
    // 分享海报
    path: '/share_posters/:id',
    name: 'share_posters',
    component: () => import( /* webpackChunkName: "about" */ './views/SharePosters.vue'),
    meta: {
      title: "课程详情"
    }
  },
  // ToolDetail.vue
  {
    // 功能单页面详情
    path: '/tool_detail/:id',
    name: 'tool_detail',
    component: () => import('./views/ToolDetail.vue'),
    meta: {
      title: "",
      keepAlive: true
    }
  },
  {
    // 文章
    path: '/article',
    name: 'article',
    component: () => import('./views/Article.vue'),
    meta: {
      title: "文章",
      keepAlive: true
    }
  },
  {
    // 体验课程
    path: '/experience/:id',
    name: 'experience',
    component: () => import('./views/Experience.vue'),
    meta: {
      title: "体验课程",
      keepAlive: true
    }
  },
  // ArticleList.vue
  {
    // 优雅美文
    path: '/article_list',
    name: 'article_list',
    component: () => import('./views/ArticleList.vue'),
    meta: {
      title: "优雅美文",
      keepAlive: true
    }
  },
  // CreateOrder.vue
  {
    // 确认购买
    path: '/create_order',
    name: 'create_order',
    component: () => import('./views/CreateOrder.vue'),
    meta: {
      title: "确认购买"
    }
  },
  // Feedback.vue
  {
    // 确认购买
    path: '/feedback',
    name: 'video_feedback',
    component: () => import('./views/Feedback.vue'),
    meta: {
      title: "确认购买"
    }
  },
  // SubscribeList.vue
  {
    // 预约
    path: '/subscribe_list',
    name: 'subscribe_list',
    component: () => import('./views/SubscribeList.vue'),
    meta: {
      title: "预约",
      keepAlive: true
    }
  },
  // SubscribeDetail
  {
    // 预约
    path: '/subscribe_detail/:id',
    name: 'subscribe_detail',
    component: () => import('./views/SubscribeDetail.vue'),
    meta: {
      title: "预约详情"
    }
  },
  // SubscribeAuth.vue
  {
    // 预约
    path: '/subscribe_auth/:course_id',
    name: 'subscribe_auth',
    component: () => import('./views/SubscribeAuth.vue'),
    meta: {
      title: "预约详情"
    }
  },
  // BindingInformation.vue
  {
    // 用户手机绑定
    path: '/binding_information',
    name: 'binding_information',
    component: () => import('./views/BindingInformation.vue'),
    meta: {
      title: "用户手机绑定"
    }
  },
  // Authentication
  {
    // 身份验证
    path: '/authentication',
    name: 'authentication',
    component: () => import('./views/Authentication.vue'),
    meta: {
      title: "身份验证"
    }
  },
  // Authentication
  {
    // 个人中心
    path: '/member',
    name: 'member_index',
    component: () => import('./views/member/Index.vue'),
    meta: {
      title: "个人中心",
      keepAlive: true
    }
  },
  // PackageGift.vue
  {
    // 提现
    path: '/member/package_gift',
    name: 'member_package_gift',
    component: () => import('./views/member/PackageGift.vue'),
    meta: {
      title: " 转赠课程"
    }
  },
  // Withdraw.vue
  {
    // 提现
    path: '/member/withdraw',
    name: 'member_withdraw',
    component: () => import('./views/member/Withdraw.vue'),
    meta: {
      title: "提现"
    }
  },
  // MyCoursesList.vue
  {
    // 我的课次
    path: '/member/my_courses_list',
    name: 'my_courses_list',
    component: () => import('./views/member/MyCoursesList.vue'),
    meta: {
      title: "我的课次"
    }
  },
  // DonationCourses.vue
  {
    // 转赠课程
    path: '/member/donation_courses',
    name: 'donation_courses',
    component: () => import('./views/member/DonationCourses.vue'),
    meta: {
      title: "转赠课程"
    }
  },
  // MyReservation.vue
  {
    // 我的预约
    path: '/member/my_reservation_list',
    name: 'my_reservation_list',
    component: () => import('./views/member/MyReservationList.vue'),
    meta: {
      title: "我的预约"
    }
  },
  // MyVideoList.vue
  {
    // 我的视频
    path: '/member/my_video_list',
    name: 'my_video_list',
    component: () => import('./views/member/MyVideoList.vue'),
    meta: {
      title: "我的视频"
    }
  },
  // MyRedeemCode.vue
  {
    // 我的兑换码
    path: '/member/produce_code',
    name: 'produce_code',
    component: () => import('./views/member/ProduceCode.vue'),
    meta: {
      title: "我的兑换码"
    }
  },
  // MyRedeemCode.vue
  {
    // 我的兑换码
    path: '/member/my_redeem_code',
    name: 'my_redeem_code',
    component: () => import('./views/member/MyRedeemCode.vue'),
    meta: {
      title: "我的兑换码"
    }
  },
  //WithdrawRecord.vue
  {
    // 提现记录
    path: '/member/withdraw_record',
    name: 'withdraw_record',
    component: () => import('./views/member/WithdrawRecord.vue'),
    meta: {
      title: "提现记录"
    }
  },
  //EarningsRecord.vue
  {
    // 收益记录
    path: '/member/earnings_record',
    name: 'earnings_record',
    component: () => import('./views/member/EarningsRecord.vue'),
    meta: {
      title: "收益记录"
    }
  },
  //EarningsRecord.vue
  {
    // 收益记录
    path: '/member/earnings_record2',
    name: 'earnings_record2',
    component: () => import('./views/member/EarningsRecord2.vue'),
    meta: {
      title: "收益记录"
    }
  },
  // PersonalInfo.vue
  {
    // 个人资料
    path: '/member/personal_info',
    name: 'personal_info',
    component: () => import('./views/member/PersonalInfo.vue'),
    meta: {
      title: "个人资料"
    }
  },
  // AddressList.vue
  {
    // 地址管理
    path: '/member/address_list',
    name: 'address_list',
    component: () => import('./views/member/AddressList.vue'),
    meta: {
      title: "地址管理"
    }
  },
  // AddressEdit.vue
  {
    // 地址编辑
    path: '/member/address_edit',
    name: 'address_edit',
    component: () => import('./views/member/AddressEdit.vue'),
    meta: {
      title: "地址编辑"
    }
  },
  // MyCart.vue
  {
    // 我的购物车
    path: '/member/my_cart',
    name: 'my_cart',
    component: () => import('./views/member/MyCart.vue'),
    meta: {
      title: "我的购物车"
    }
  },
  {
    // 核销单首页
    path: '/verification/index',
    name: 'verification_index',
    component: () => import('./views/verification/Index.vue'),
    meta: {
      title: "香港皇家优雅女子学堂"
    }
  },
  // OrderManage.vue
  {
    // 订单管理
    path: '/verification/order_manage',
    name: 'order_manage',
    component: () => import('./views/verification/OrderManage.vue'),
    meta: {
      title: "订单管理"
    }
  },
  // OrderDetail.vue
  {
    // 订单核销
    path: '/verification/order_detail',
    name: 'verification_order_detail',
    component: () => import('./views/verification/OrderDetail.vue'),
    meta: {
      title: "订单核销"
    }
  },

  {
    // 转赠课程包管理页面
    path: '/reservation/order_manage',
    name: 'reservation_order_manage',
    component: () => import('./views/reservation/OrderManage.vue'),
    meta: {
      title: "转赠课程管理"
    }
  },
  {
    // 转赠课程包详情核销
    path: '/reservation/order_detail',
    name: 'reservation_order_detail',
    component: () => import('./views/reservation/OrderDetail.vue'),
    meta: {
      title: "转赠课程核销"
    }
  },
  // Feedback.vue
  {
    // 反馈页面
    path: '/verification/feedback',
    name: 'feedback',
    component: () => import('./views/verification/Feedback.vue'),
    meta: {
      title: "反馈页面"
    }
  },
  // 产品列表
  {
    // 产品列表
    path: '/goods/index',
    name: 'goods_index',
    component: () => import('./views/goods/Index.vue'),
    meta: {
      title: "商品列表"
    }
  },
  // 产品列表
  {
    // 产品列表
    path: '/goods/index2',
    name: 'goods_index2',
    component: () => import('./views/goods/Index2.vue'),
    meta: {
      title: "商品列表"
    }
  },
  // 产品详情
  {
    // 产品详情
    path: '/goods_detail',
    name: 'goods_detail',
    component: () => import('./views/goods/Detail.vue'),
    meta: {
      title: "商品详情"
    }
  },
  // 商品创建订单 CreateOrder.vue
  {
    // 确认订单
    path: '/goods_create_order',
    name: 'goods_create_order',
    component: () => import('./views/goods/CreateOrder.vue'),
    meta: {
      title: "确认订单"
    }
  },
  // 订单支付反馈页面
  {
    // 订单支付反馈页面
    path: '/goods/pay_feedback',
    name: 'goods_pay_feedback',
    component: () => import('./views/goods/Feedback.vue'),
    meta: {
      title: ""
    }
  },
  // BranchList.vue
  {
    // 全国分院列表
    path: '/branch',
    name: 'branch_list',
    component: () => import('./views/branch/BranchList.vue'),
    meta: {
      title: "全国分院列表",
      keepAlive: true
    }
  },
  // BranchDetail.vue
  {
    // 分院详情
    path: '/branch/detail',
    name: 'branch_detail',
    component: () => import('./views/branch/BranchDetail.vue'),
    meta: {
      title: "分院详情"
    }
  },
  // 订单列表
  // OrderList.vue.vue
  {
    // 订单列表
    path: '/order_list',
    name: 'order_list',
    component: () => import('./views/order/OrderList.vue'),
    meta: {
      title: "订单列表"
    }
  },
  {
    // 订单详情
    path: '/order_detail',
    name: 'order_detail',
    component: () => import('./views/order/OrderDetail.vue'),
    meta: {
      title: "订单详情"
    }
  },
  {
    // 申请退款
    path: '/order/refund/:id',
    name: 'order_refund',
    component: () => import('./views/order/Refund.vue'),
    meta: {
      title: "申请退款"
    }
  },
  // RefundDetail.vue
  {
    // 退款详情
    path: '/order/refund_detail/:id',
    name: 'order_refund_detail',
    component: () => import('./views/order/RefundDetail.vue'),
    meta: {
      title: "退款详情"
    }
  },
  {
    // 梦想导师团
    path: '/tutor/index',
    name: 'tutor_index',
    component: () => import('./views/tutor/Index.vue'),
    meta: {
      title: "梦想导师团",
      keepAlive: true
    }
  },
  {
    // 梦想导师团
    path: '/tutor/detail',
    name: 'tutor_detail',
    component: () => import('./views/tutor/Detail.vue'),
    meta: {
      title: "梦想导师团"
    }
  },
  // 二期新增
  {
    // 服务对象ServiceObject.vue
    path: '/member/service_object',
    name: 'service_object',
    component: () => import('./views/member/ServiceObject.vue'),
    meta: {
      title: "服务对象"
    }
  },
  {
    // 服务对象ServiceObject.vue
    path: '/member/service_object2',
    name: 'service_object2',
    component: () => import('./views/member/ServiceObject2.vue'),
    meta: {
      title: "大使服务对象"
    }
  },
  {
    // 服务对象ServiceObject.vue
    path: '/member/my_ambassador',
    name: 'my_ambassador',
    component: () => import('./views/member/MyAmbassador.vue'),
    meta: {
      title: "我的传播大使"
    }
  },
  {
    // 业绩排行榜
    path: '/member/rank_list',
    name: 'rank_list',
    component: () => import('./views/member/RankList.vue'),
    meta: {
      title: "业绩排行榜"
    }
  },
  {
    // 课程列表
    path: '/live_list',
    name: 'live_list',
    component: () => import('./views/live/LiveList.vue'),
    meta: {
      title: "课程列表"
    }
  },
  {
    // 课程详情
    path: '/live_detail',
    name: 'live_detail',
    component: () => import('./views/live/LiveDetail.vue'),
    meta: {
      title: "课程详情"
    }
  },
  {
    // 直播课程
    path: '/live/my_live',
    name: 'my_live',
    component: () => import('./views/live/MyLive.vue'),
    meta: {
      title: "直播课程"
    }
  },
  {
    // 直播课程
    path: '/live/my_live_detail',
    name: 'my_live_detail',
    component: () => import('./views/live/MyLiveDetail.vue'),
    meta: {
      title: "直播课程"
    }
  },
  {
    // 直播课程
    path: '/live/feedback',
    name: 'live_feedback',
    component: () => import('./views/live/Feedback.vue'),
    meta: {
      title: "直播课程"
    }
  },
  {
    // 确认购买
    path: '/live_create',
    name: 'live_create',
    component: () => import('./views/live/Create.vue'),
    meta: {
      title: "确认购买"
    }
  },
  {
    // 确认购买
    path: '/upgrade',
    name: 'upgrade',
    component: () => import('./views/upgrade/Upgrade.vue'),
    meta: {
      title: ""
    }
  },
  {
    // 升级课程详情
    path: '/upgrade_detail',
    name: 'upgrade_detail',
    component: () => import('./views/upgrade/UpgradeDetail.vue'),
    meta: {
      title: "课程详情"
    }
  },
  {
    // 升级课程下单
    path: '/upgrade_create',
    name: 'upgrade_create',
    component: () => import('./views/upgrade/Create.vue'),
    meta: {
      title: "课程详情"
    }
  },
  {
    // 升级课程支付反馈
    path: '/upgrade_feedback',
    name: 'upgrade_feedback',
    component: () => import('./views/upgrade/Feedback.vue'),
    meta: {
      title: ""
    }
  },
  {
    // 升级课程支付反馈
    path: '/upgrade_order',
    name: 'upgrade_order',
    component: () => import('./views/upgrade/Detail.vue'),
    meta: {
      title: ""
    }
  }
  ]
})

接下来是App.vue

<template>
  <div id="app">
    <router-view>
    </router-view>
    <keep-alive>
      <!-- 底部菜单 -->
      <FooterNav v-if="$route.meta.keepAlive" />
      <!-- 底部菜单 -->
    </keep-alive>
  </div>
</template>
<script>
  import FooterNav from "./components/FooterNav"
  export default {
    components: {
      FooterNav
    },
    mounted() {
      window.addEventListener('focusout', function() {
        document.body.scrollTop = document.body.scrollHeight;
      })
    },
  }
</script>
<style lang="less">
  #app {
    padding-bottom: 60px;
    background-color: #fff;
  }
</style>

然后是footer组件

<template>
  <div>
    <van-tabbar v-model="index" active-color="#8DB9DF"
  inactive-color="#999999">
      <van-tabbar-item replace to="/">
        <span>首页</span>
        <img
          slot="icon"
          slot-scope="props"
          :src="props.active ? icons[0].active : icons[0].normal"
        >
      </van-tabbar-item>
      <van-tabbar-item replace to="/video">
        <span>视频</span>
        <img
          slot="icon"
          slot-scope="props"
          :src="props.active ? icons[1].active : icons[1].normal"
        >
      </van-tabbar-item>
      <van-tabbar-item replace to="/subscribe_list">
        <span>预约</span>
        <img
          slot="icon"
          slot-scope="props"
          :src="props.active ? icons[2].active : icons[2].normal"
        >
      </van-tabbar-item>
      <van-tabbar-item replace to="/member">
        <span>我的</span>
        <img
          slot="icon"
          slot-scope="props"
          :src="props.active ? icons[3].active : icons[3].normal"
        >
      </van-tabbar-item>
    </van-tabbar>
  </div>
</template>
<script>
export default {
  props: ["active"],
  data(){
    return{
      index:0,
      icons:[{
        normal: 'http://youya.chuncom.com/youya-h5/img/home-normal.png',
        active: 'http://youya.chuncom.com/youya-h5/img/home-active.png'
      },{
        normal: 'http://youya.chuncom.com/youya-h5/img/video-normal.png',
        active: 'http://youya.chuncom.com/youya-h5/img/video-active.png'
      },{
        normal: 'http://youya.chuncom.com/youya-h5/img/clock-normal.png',
        active: 'http://youya.chuncom.com/youya-h5/img/clock-active.png'
      },{
        normal: 'http://youya.chuncom.com/youya-h5/img/user-normal.png',
        active: 'http://youya.chuncom.com/youya-h5/img/user-active.png'
      }]
    }
  },
  mounted() {
    this.index = this.active || 0 ;
    console.log(this.$router.currentRoute.name)
  },
}
</script>
<style lang="less">
  .van-tabbar-item__icon img{
     24px;
    height: 24px !important;
  }
</style>

接下来我们看首页的写法

<template>
  <div class="plr-15 pt-10">
    <!-- 轮播图 -->
    <div class="mb-10">
      <van-swipe :autoplay="3000" :show-indicators="false">
        <van-swipe-item v-for="item in banner" :key="item.id">
          <!-- <router-link :to="item.url">
            <img :src="item.image" width="100%" alt="">
          </router-link>-->
          <a :href="item.url">
            <img :src="item.image" width="100%" alt />
          </a>
        </van-swipe-item>
      </van-swipe>
    </div>
    <!-- 轮播图 -->
    <!-- banner -->
    <div class="flex flex-jus">
      <div v-for="item in ad" :key="item.id" class="banner2">
        <!-- <router-link :to="item.url">
          <img :src="item.image" width="100%" alt="">
        </router-link>-->
        <a :href="item.url">
          <img :src="item.image" width="100%" alt />
        </a>
      </div>
      <!-- <div class="banner2">
        <router-link to="/goods/index">
          <img src="/img/banner2-02.png" width="100%" alt="">
        </router-link>
      </div>-->
    </div>
    <!-- banner -->
    <!-- 菜单 -->
    <van-grid :column-num="5" :border="false">
      <van-grid-item v-for="item in tool" :icon="item.image" :text="item.title" :to="{ name: 'tool_detail', params: { id: item.id }}" />
    </van-grid>
    <!-- 菜单 -->

    <!-- 升级课程 -->
    <div class="flex flex-wrap flex-jus mb-10">
      <div v-for="(item,index) in upgradeInfo" :key="index" class="course-item">
        <router-link :to="{name:'upgrade_detail',query:{id:item.id}}">
          <img v-lazy="item.image" width="100%" alt />
        </router-link>
      </div>
    </div>


    <!-- 升级课程 -->


    <!-- 课程推荐 -->
    <div class="flex flex-wrap flex-jus mb-10">
      <div class="course-item">
        <router-link to="/video">
          <img v-lazy="tool_parameter.HOME_SOURSE_IMAGE" width="100%" alt />
        </router-link>
      </div>
      <div class="course-item">
        <router-link to="/subscribe_list">
          <img v-lazy="tool_parameter.HOME_BOOKING_IMAGE" width="100%" alt />
        </router-link>
      </div>
      <div class="course-item">
        <router-link to="/article_list">
          <img v-lazy="tool_parameter.HOME_ARTICLE_IMAGE" width="100%" alt />
        </router-link>
      </div>
      <div class="course-item">
        <router-link to="/goods/index">
          <img v-lazy="tool_parameter.HOME_OFFSOURSE_IMAGE" width="100%" alt />
        </router-link>
      </div>
    </div>
    <!-- 课程推荐 -->
    <!-- 视频列表 -->
    <h2 class="fz-16 c3 mb-10 flex flex-jus flex-align-center">
      <div>直播课程</div>
      <router-link :to="{name:'live_list'}">
        <span class="fz-11 c9">查看跟多</span>
        <van-icon name="arrow" size="11" color="#999" />
      </router-link>
      </rou>
    </h2>
    <!-- <van-grid :border="false" :column-num="4">
      <van-grid-item v-for="(item ,index) in liveList" :key="index" :to="{name:'live_list',query:{id:item.id}}">
        <div class="live-item">
          <div>{{ item.name }}</div>
        </div>
      </van-grid-item>
    </van-grid> -->
    <div class="video-list mb-10">
      <div class="video-item" v-for="(item,index) in liveList" :key="index">
        <router-link :to="{name:'live_detail',query:{id:item.id}}">
          <div class="video-img">
            <img :src="item.image" width="100%" alt />
          </div>
        </router-link>
      </div>
    </div>
    <!-- 视频列表 -->

    <!-- 视频列表 -->
    <h2 class="fz-16 c3 mb-10">热门课程</h2>
    <div class="video-list mb-10">
      <div class="video-item" v-for="(item,index) in CourseHot" :key="index">
        <router-link :to="{ name: 'video_detail', query: { id: item.id }}">
          <div class="video-img">
            <img :src="item.image" width="100%" alt />
            <div class="sets">更新至{{item.period}}集</div>
          </div>
          <div class="fz-14 c3 text-hide">{{item.name}}</div>
          <div class="fz-14 text-price">¥{{item.price}}</div>
        </router-link>
      </div>
    </div>
    <!-- 视频列表 -->

    <!-- banner3 -->
    <div class="mb-10">
      <router-link :to="{name:'experience',params:{id:1}}">
        <img v-lazy="tool_parameter.HOME_EXPERIENCE_IMAGE" width="100%" alt />
      </router-link>
    </div>
    <div class="mb-10">
      <router-link to="/branch">
        <img v-lazy="tool_parameter.HOME_BRANCH_IMAGE" width="100%" alt />
      </router-link>
    </div>
    <div v-if="ad_foot.length" class="mb-10">
      <router-link to="/tutor/index">
        <img v-lazy="ad_foot[0].image" width="100%" alt />
      </router-link>
    </div>
    <div v-if="ad_foot.length" class="mb-10" style="margin-bottom:2.666667rem;">
      <router-link to="/goods/index2">
        <img v-lazy="ad_foot[1].image" width="100%" alt />
      </router-link>
    </div>
    <!-- banner3 -->
    <!-- banner -->
    <!-- <div v-if="ad_foot.length" class="flex flex-jus" style="margin-bottom:2.666667rem;">
      <div v-for="(item,index) in ad_foot" v-if="index !=0" :key="item.id" class="banner2">
        <a :href="item.url">
          <img :src="item.image" width="100%" alt="">
        </a>
      </div>
    </div>-->
    <!-- banner -->
    <!-- 联系我们 -->
    <div class="contact-us">
      <div class="logo">
        <img src="img/logo.png" alt />
      </div>
      <div v-html="tool_parameter.HOME_BOTTOM_TEXT"></div>
      <!-- <p>欢迎您的加入!</p>
      <p>香港皇家优雅女子学堂提供的不仅是一个课程,也是一种优雅的生活方式更是一个精神的殿堂!</p>
      <p>联系方式:020-38868921 · 020-38847236</p>
      <p>中国总部:广州市天河区体育东路108号创展中心</p>
      <p>(万凌汇旁)西座三楼</p>-->
    </div>
    <!-- 联系我们 -->
  </div>
</template>
<script>
  import wx from "weixin-js-sdk";
  export default {
    data() {
      return {
        active: 1,
        images: [
          "../assets/img/index-banner-01.png",
          "../assets/img/index-banner-01.png"
        ],
        ad: "",
        ad_foot: [],
        banner: "",
        tool: "",
        tool_parameter: "",
        CourseHot: [],
        liveList: [],
        upgradeInfo: []
      };
    },
    created() {
      this.activity_id = this.$route.query.activity_id;
      this.share_id = this.$route.query.share_id;
      this.getContactImg();
      if (this.$route.query.type) {
        this.jumpPage();
      } else {
        this.checkLogin();
      }
      this.getSDK();
      this.getLive();
      this.getUpgradeInfo();
    },
    methods: {
      async getUpgradeInfo() {
        let {
          code,
          data,
          message
        } = await window.axios.get("/home/upgrade-info");
        if (code == 0) {
          window.console.log(data);
          this.upgradeInfo = data;
        } else {
          window.console.error(message);
        }
      },
      async getLive() {
        let {
          code,
          data,
          message
        } = await window.axios.get("/home/live");
        if (code == 0) {
          // window.console.log(data);
          this.liveList = data;
        } else {
          window.console.error(message);
        }
      },
      async getContactImg() {
        let {
          code,
          data,
          message
        } = await window.axios.get("/config/detail", {
          params: {
            key: "CUSTOMER_CONTACT"
          }
        });
        if (code == 0) {
          this.$store.dispatch("setContact", data.value);
        } else {
          window.console.error(message);
        }
      },
      // 根据type跳转到不同的页面
      jumpPage() {
        let type = this.$route.query.type;
        switch (type) {
          case "1":
            this.$router.push({
              name: "article",
              query: {
                id: this.$route.query.id,
                share_id: this.$route.query.share_id
              }
            });
            break;
          case "2":
            this.$router.push({
              name: "video_detail",
              query: {
                id: this.$route.query.id,
                share_id: this.$route.query.share_id
              }
            });
            break;
          case "3":
            this.$router.push({
              name: "goods_detail",
              query: {
                id: this.$route.query.id,
                share_id: this.$route.query.share_id
              }
            });
            break;
          case "4":
            this.$router.push({
              name: "subscribe_detail",
              params: {
                id: this.$route.query.id
              }
            });
            break;
          case "5":
            this.$router.push({
              name: "live_detail",
              query: {
                id: this.$route.query.id,
                share_id: this.$route.query.share_id
              }
            });
            break;
          case "6":
            this.$router.push({
              name: "upgrade_detail",
              query: {
                id: this.$route.query.id,
                share_id: this.$route.query.share_id
              }
            });
            break;
          default:
            this.checkLogin();
            break;
        }
      },
      async login() {
        let {
          code,
          data,
          message
        } = await window.axios.get("/user/login?id=1");
        if (code == 0) {
          this.getData();
          this.getCourseHot();
          data = JSON.stringify(data);
          localStorage.setItem("userinfo", data);
        }
      },
      async checkLogin() {
        this.$toast.loading({
          message: "加载中..."
        });
        let {
          data,
          code
        } = await window.axios.get("/user");
        this.$toast.clear();
        if (code == 0) {
          data = JSON.stringify(data);
          localStorage.setItem("userinfo", data);
          this.getData();
          this.getCourseHot();
        } else if (code == 401) {
          this.login();
          // let href = encodeURIComponent(window.location.href);
          // window.location.href =
          //   "http://youya.chuncom.com/user/authorization?url=" + href;
        }
      },
      async getSDK() {
        // alert(location.href)
        let href = encodeURIComponent(window.location.href);
        let {
          data,
          code,
          message
        } = await window.axios.get(
          "/config/jsjdk?url=" + href
        );
        if (code == 0) {
          wx.config({
            debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: data.appId, // 必填,公众号的唯一标识
            timestamp: Number(data.timestamp), // 必填,生成签名的时间戳
            nonceStr: data.nonceStr, // 必填,生成签名的随机串
            signature: data.signature, // 必填,签名,见附录1
            jsApiList: [
              "chooseWXPay",
              "onMenuShareTimeline",
              "onMenuShareAppMessage", //1.0分享到朋友圈
              "updateAppMessageShareData", //1.4 分享到朋友
              "updateTimelineShareData",
              "openAddress"
            ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
          });
        } else {
          // $weui.topTips(message, 3000);
        }
      },
      async getData() {
        this.$toast.loading({
          message: "加载中..."
        });
        let {
          code,
          data,
          message
        } = await window.axios.get("/home");
        if (code == 0) {
          this.$toast.clear();
          this.ad = data.ad;
          this.banner = data.banner;
          this.tool = data.tool;
          this.tool_parameter = data.tool_parameter;
          this.ad_foot = data.ad_foot;
        } else {
          this.$toast.fail(message);
        }
      },
      async getCourseHot() {
        let {
          code,
          data,
          message
        } = await window.axios.get("/home/course-hot");
        if (code == 0) {
          this.CourseHot = data;
        } else {
          this.$toast.fail(message);
        }
      }
    }
  };
</script>
<style lang="less">
  .van-uploader__input {
    right: 0;
    left: -40vw !important;
     60vw !important;
  }

  .van-icon__image {
     45px !important;
    height: 45px !important;
  }

  .van-grid-item__text {
    color: #999 !important;
  }

  .course-item {
    margin-bottom: 10px;
     168px;

    img {
       100%;
      vertical-align: bottom;
    }
  }

  .banner2 {
     168px;

    img {
       100%;
      vertical-align: bottom;
    }
  }

  .video-list {
     100%;
    overflow-x: scroll;
    white-space: nowrap;

    .video-item {
      display: inline-block;
      margin-right: 10px;
       168px;

      .video-img {
        position: relative;
        margin-bottom: 5px;

        .sets {
          position: absolute;
          right: 7px;
          bottom: 2px;
          font-size: 11px;
          color: #fff;
        }
      }
    }
  }

  .contact-us {
    position: relative;
    border-top: 4px dotted #eee;
    border-bottom: 4px dotted #eee;
    padding: 46px 0 17px;

    .logo {
      position: absolute;
      background-color: #fff;
      padding: 0 24px;
      left: 50%;
      top: 0;
      transform: translate(-50%, -60%);

      img {
         90px;
      }
    }

    p {
      color: #bcbcbc;
      font-size: 12px;
      text-align: center;
    }
  }

  .live-item {
     100%;
    height: 40px;
    line-height: 40px;
    background: rgba(255, 255, 255, 1);
    border-radius: 20px;
    border: 1px solid rgba(236, 236, 236, 1);
    color: #333;
    text-align: center;
    font-size: 12px;
    overflow: hidden;
    text-overflow: ellipsis;
  }
</style>

看着内容挺多的,然后其实用了van这个Ui组件之后,再加上异步的渲染,其实很简洁很高效
接下来看品牌故事页面

<template>
  <div>
    <div v-html="content"></div>
  </div>
</template>

<script>
export default {
  components: {},
  props: {},
  data() {
    return {
      content:""
    };
  },
  watch: {},
  computed: {},
  methods: {
    async getData(){
      this.$toast.loading({messages:"加载中..."})
      let {code,data,messages} = await axios.get(`/home/tool-detail?id=${this.$route.params.id}`);
      if(code==0){
          this.$toast.clear();
          this.content = data.detail;
          document.title = data.title
        }else{
          this.$toast.fail(messege)
        }
    },
    async getAbout(){
      this.$toast.loading({messages:"加载中..."})
      let {code,data,messages} = await axios.get(`/config/detail?key=ABOUT_US`);
      if(code==0){
        this.$toast.clear();
        this.content = data.value;
        document.title = data.tip;
      }else{
        this.$toast.fail(messege)
      }
    }
  },
  created() {
    if(this.$route.query.key){
      this.getAbout()
    }else{
      this.getData()
    }

  },
  mounted() {}
};
</script>
<style lang="less" scoped>
</style>

这个content不知道是哪里来的
打印结果,居然是H5的切片,有意思极了
接下来我们看

//UpgradeDetail
<template>
  <div>
    <img :src="detail.image" class="live-banner" alt />
    <!-- 课程信息 -->
    <div class="p-15 flex mb-10">
      <div class="course-info">
        <h2 class="fz-17 c3 mb-5">{{detail.name}}</h2>
        <!-- <div class="fz-12 c9 mb-5">全部{{catalogue.length || 0}}集</div> -->
        <div>
          <span class="fz-15 text-price">¥{{detail.bug_info.price}} </span>
          <span class="fz-12 c9 text-line">原价¥{{detail.bug_info.original_price}}</span>
        </div>
      </div>
      <div v-if="detail.is_share" @click="isShowPoster = true" class="course-share flex flex-align-start">
        <div class="flex flex-column flex-jus flex-align-center">
          <img src="@/assets/img/icon-wallet.png" alt />
          <div class="fz-11 c9">分享获得</div>
        </div>
        <div class="award-tips">{{parseInt(detail.share_amount||0)}}元奖励</div>
      </div>
    </div>
    <!-- 课程信息 -->
    <div class="bar-10"></div>
    <!-- 课程详情和目录 -->
    <van-tabs v-model="active" title-active-color="#8DB9DF" title-inactive-color="#999999" color="#8DB9DF">
      <van-tab title="课程详情">
        <div class="p-15" v-html="detail.detail"></div>
      </van-tab>
      <van-tab title disabled></van-tab>
    </van-tabs>
    <!-- 课程详情和目录 -->

    <!-- footer -->
    <div class="footer-bar plr-15 flex flex-align-center">
      <router-link to="/">
        <div class="back-home">
          <img src="@/assets/img/icon-home.png" alt />
          <div class="fz-11 c9">首页</div>
        </div>
      </router-link>
      <div v-if="detail.is_bug == 0" class="btn-youya" @click="buying">购买课程</div>
      <div v-else class="btn-youya disable">已购买</div>
    </div>
    <!-- footer -->
    <!-- 侧边客服购物车按钮 -->
    <div class="side-btn">
      <img @click="showContact" src="@/assets/img/btn-service.png" alt />
    </div>
    <van-popup v-model="isShowContact">
      <img style="70vw;" :src="this.$store.getters.getContact" alt />
    </van-popup>
    <!-- 侧边客服购物车按钮 -->

    <van-popup v-model="isShowPoster">
      <img :src="imgUrl || this.detail.share_info.share_qr" class="poster" alt />
    </van-popup>

  </div>
</template>

<script>
  import MCanvas from "mcanvas";
  // require styles
  import wx from "weixin-js-sdk";
  export default {
    props: {},
    data() {
      return {
        show: false,
        flag: false,
        isShowPoster: false,
        active: 0,
        isShowContact: false,
        showVideo: false,
        // 是否购买该教程
        isbought: false,
        catalogue: [],
        detail: "",
        userinfo: {},
        imgUrl: ""
      };
    },
    watch: {},
    computed: {},
    methods: {
      async add() {
        if (!this.$route.query.share_id) {
          return;
        }
        let {
          code
        } = await window.axios.post("/user/superior/add", {
          superior_id: this.$route.query.share_id
        });
        if (code == 0) {
          window.console.log("绑定成功");
        }
      },
      showContact() {
        this.isShowContact = true;
      },
      async getSDK() {
        // alert(location.href)
        let href = encodeURIComponent(window.location.href);
        let {
          data,
          code,
          message
        } = await window.axios.get(
          "/config/jsjdk?url=" + href
        );
        if (code == 0) {
          wx.config({
            debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: data.appId, // 必填,公众号的唯一标识
            timestamp: Number(data.timestamp), // 必填,生成签名的时间戳
            nonceStr: data.nonceStr, // 必填,生成签名的随机串
            signature: data.signature, // 必填,签名,见附录1
            jsApiList: [
              "onMenuShareTimeline",
              "onMenuShareAppMessage", //1.0分享到朋友圈
              "updateAppMessageShareData", //1.4 分享到朋友
              "updateTimelineShareData"
            ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
          });
        } else {
          this.$toast(message);
        }
      },
      wxShare() {
        wx.ready(() => {
          let shareData = {
            title: this.detail.share_title,
            desc: this.detail.share_subtitle, //这里请特别注意是要去除html
            link: this.detail.share_info.share_url,
            imgUrl: this.detail.share_image ||
              "http://youya.chuncom.com/youya-h5/img/logo.png"
          };
          if (wx.onMenuShareAppMessage) {
            //微信文档中提到这两个接口即将弃用,故判断
            wx.onMenuShareAppMessage(shareData); //1.0 分享到朋友
            wx.onMenuShareTimeline(shareData); //1.0分享到朋友圈
          } else {
            wx.updateAppMessageShareData(shareData); //1.4 分享到朋友
            wx.updateTimelineShareData(shareData); //1.4分享到朋友圈
          }
          wx.error(function(res) {
            // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
            // alert("errorMSG:" + res)
            window.console.log("errorMSG:" + res);
          });
        });
      },
      // 购买事件
      async buying() {
        let {
          code,
          data,
          message
        } = await window.axios.get("/user");
        if (code == 0) {
          this.userInfo = data;
          if (data.is_bind == 0) {
            this.$dialog
              .confirm({
                title: "提示",
                message: "您还未绑定手机号,是否前往绑定?"
              })
              .then(() => {
                this.$router.push({
                  name: "binding_information"
                });
              })
              .catch(e => {
                window.console.log(e);
              });
            return;
          } else {
            this.$router.push({
              name: "upgrade_create",
              query: {
                id: this.$route.query.id,
                share_id: this.$route.query.share_id || ""
              }
            });
          }
        } else if (code == 401) {
          this.$dialog
            .confirm({
              title: "提示",
              message: "您还未授权登录,无法进行购买,是否前往授权?"
            })
            .then(() => {
              window.location.href = `http://youya.chuncom.com/user/authorization?url=${encodeURIComponent(
              window.location.href
            )}`;
            })
            .catch(e => {
              window.console.log(e);
            });
        }
      },
      async getData() {
        this.$toast.loading({
          message: "加载中..."
        });
        let {
          code,
          data,
          message
        } = await window.axios.get(
          "/user/upgrade/info", {
            params: {
              info_id: this.$route.query.id
            }
          }
        );
        if (code == 0) {
          this.$toast.clear();
          this.detail = data;
          this.compoundImg();
          this.wxShare();
        } else {
          this.$toast.fail(message);
          // this.$router.push({ path: "/" });
        }
      },
      async compoundImg() {
        let {
          poster,
          image,
          share_info,
          name
        } = this.detail;
        // window.console.log(poster, image, share_info);
        let mc = new MCanvas({
           750,
          height: 1334,
          backgroundColor: "white"
        });
        // 海报背景图 this.list[this.active].image ../img/poster-psd.jpg
        mc.background(poster, {
            left: 0,
            top: 0,
            color: "#000000",
            type: "crop"
          })
          // 模板背景图连接
          // .add("../img/poster-bg.pn
          // hg",{
          //     610,
          //     height:642,
          //     pos:{
          //         x:70,
          //         y:160,
          //         scale:1
          //     },
          // })
          // 二维码连接 this.createShareImage.share_qr ../img/erweima.png
          .add(share_info.share_qr, {
             126,
            height: 126,
            pos: {
              x: 110,
              y: 635,
              scale: 1
            }
          })
          // 产品图连接 this.detail.image ../img/banner2-01.png
          .add(image, {
             570,
            height: 321,
            pos: {
              x: 90,
              y: 180,
              scale: 1
            }
          })
          .add("/youya-h5/img/logo.png", {
             162,
            height: 168,
            pos: {
              x: 487,
              y: 620,
              scale: 1
            }
          })
          // text 添加文字数据基础函数;
          .text(name, {
             530,
            align: "left",
            normalStyle: {
              font: `30px Microsoft YaHei,sans-serif`,
              lineHeight: 32
            },
            pos: {
              x: 110,
              y: 525
            }
          })
          // text 添加文字数据基础函数;
          .text("加入学习", {
             96,
            align: "left",
            normalStyle: {
              font: `24px Microsoft YaHei,sans-serif`,
              lineHeight: 28,
              color: "#999"
            },
            pos: {
              x: 254,
              y: 660
            }
          })
          // text 添加文字数据基础函数;
          .text("长按识别二维码", {
             168,
            align: "left",
            normalStyle: {
              font: `24px Microsoft YaHei,sans-serif`,
              lineHeight: 28,
              color: "#999"
            },
            pos: {
              x: 254,
              y: 708
            }
          })
          .draw(b64 => {
            window.console.log(b64);
            this.imgUrl = b64;
          });
      }
    },
    created() {
      this.add();
      this.getData();
      this.getSDK();
    },
    mounted() {}
  };
</script>
<style lang="less">
  .live-banner {
     100%;
  }

  .course-info {
    flex: 1;
  }

  .course-share {
    position: relative;
     84px;
    padding-top: 10px;

    img {
       24px;
      height: 24px;
    }

    .award-tips {
      position: absolute;
      top: 0;
      right: -5px;
      padding: 2px 4px;
      font-size: 10px;
      color: #fff;
      background: linear-gradient(141deg,
          rgba(252, 186, 133, 1) 0%,
          rgba(255, 169, 117, 1) 100%);
      border-radius: 11px 11px 11px 0;
    }
  }

  .footer-bar {
    box-shadow: 0px 0px 5px 0px rgba(238, 238, 238, 1);
  }

  .btn-youya {
     260px;
    height: 40px;
    line-height: 40px;
    background: linear-gradient(143deg,
        rgba(157, 195, 230, 1) 0%,
        rgba(131, 179, 219, 1) 100%);
    border-radius: 20px;
    color: #fff;
    font-size: 15px;
    text-align: center;
    box-shadow: 1px 5px 6px rgba(131, 179, 219, 0.2);

    &.disable {
      background: #cccccc;
      box-shadow: none;
    }
  }

  .back-home {
     90px;
    text-align: center;

    img {
      display: inline-block;
       24px;
      height: 24px;
    }
  }

  .catalogue-list {
    padding: 15px;

    .catalogue-item {
      display: flex;
      margin-bottom: 15px;
      align-items: center;

      .thumb {
        position: relative;
         90px;
        height: 50px;
        background-position: center;
        background-size: contain;
        background-repeat: no-repeat;
        border-radius: 5px;

        .duration {
          position: absolute;
          right: 7px;
          bottom: 2px;
          font-size: 11px;
          color: #fff;
        }
      }

      .tilte {
        margin-left: 10px;
        flex: 1;
      }
    }
  }

  .side-btn {
    position: fixed;
    top: 60%;
    right: 5px;

    img {
       45px;
      height: 45px;
    }
  }

  .poster {
     80vw;
  }

  .xieyi-box {
    padding: 0 20px;
     310px;
    height: 395px;
    background: rgba(255, 255, 255, 1);
    border-radius: 8px;
    box-sizing: border-box;

    .title {
      padding: 25px 0;
      font-size: 18px;
      color: #333;
      text-align: center;
    }

    .content-box {
      margin-bottom: 10px;
      height: 260px;
      overflow-y: scroll;
    }

    .btns {
      display: flex;
      justify-content: space-around;

      .btn {
         105px;
        height: 35px;
        line-height: 35px;
        background: linear-gradient(143deg,
            rgba(157, 195, 230, 1) 0%,
            rgba(131, 179, 219, 1) 100%);
        border-radius: 18px;
        text-align: center;
        font-size: 13px;
        color: #fff;

        &.disable {
          opacity: 0.5;
        }
      }

      .btn-o {
         105px;
        height: 35px;
        line-height: 35px;
        border-radius: 18px;
        border: 1px solid rgba(204, 204, 204, 1);
        text-align: center;
        font-size: 13px;
        color: #999999;
      }
    }
  }

  .checked {
    position: relative;
    margin-right: 10px;
     15px;
    height: 15px;
    border: 1px solid rgba(153, 153, 153, 1);
    border-radius: 50%;

    &.on {
      border-color: #8db9df;
    }

    &.on::after {
      content: " ";
      position: absolute;
      left: 50%;
      top: 50%;
       10px;
      height: 10px;
      background-color: #8db9df;
      border-radius: 50%;
      transform: translate(-50%, -50%);
    }
  }
</style>

后记东西太多了

原文地址:https://www.cnblogs.com/smart-girl/p/12878169.html