【珍惜时间】 vant-finance-mobile

放肆的年华 提交于 2020-08-13 09:59:08

先说下这个作者大大的项目
运行就跳转到黄色网页了,然后我把网页差掉,接下来就是继续运行,然后就可以打开网页了
先放下作者大大的项目地址,接下来我们看下页面效果
https://github.com/huzongyao/vant-finance-mobile

接下来我们就来看代码喽




<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <title>Vant Finance</title>
  <style>
    body {
      padding: 0;
      margin: 0
    }

    #h-lb {
      width: 100%;
      height: 100%;
      position: fixed;
      text-align: center;
      background-color: #CA4040;
    }

    #h-con {
      position: fixed;
      top: 50%;
      left: 50%;
      -webkit-transform: translate3d(-50%, -50%, 0);
      transform: translate3d(-50%, -50%, 0);
    }

    #h-con .l-s {
      position: static;
      width: 60px;
      height: 60px;
      -webkit-transform: scale(0.7);
      transform: scale(0.7);
      -webkit-animation: l-2-s 1s ease alternate infinite;
      animation: l-2-s 1s ease alternate infinite;
    }

    #h-con .l-c {
      width: 8px;
      height: 8px;
      background: #ffffff;
      border-radius: 50%;
      position: absolute;
      left: calc(50% - 4px);
      top: calc(50% - 4px);
      -webkit-transition: all 1s ease;
      transition: all 1s ease;
      -webkit-animation: l-2-c 1s ease-in-out alternate infinite;
      animation: l-2-c 1s ease-in-out alternate infinite;
    }

    @-webkit-keyframes l-2-c {
      0% {
        box-shadow: 0 0 0 #ffffff;
        opacity: 1;
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      50% {
        box-shadow: 24px -22px #ffffff, 30px -15px 0 -3px #ffffff, 31px 0 #ffffff, 29px 9px 0 -3px #ffffff,
        24px 23px #ffffff, 17px 30px 0 -3px #ffffff, 0 33px #ffffff, -10px 28px 0 -3px #ffffff,
        -24px 22px #ffffff, -29px 14px 0 -3px #ffffff, -31px -3px #ffffff, -30px -11px 0 -3px #ffffff,
        -20px -25px #ffffff, -12px -30px 0 -3px #ffffff, 5px -29px #ffffff, 13px -25px 0 -3px #ffffff;
        -webkit-transform: rotate(180deg);
        transform: rotate(180deg);
      }
      100% {
        opacity: 0;
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg);
        box-shadow: 25px -22px #ffffff, 15px -22px 0 -3px black, 31px 2px #ffffff, 21px 2px 0 -3px black,
        23px 25px #ffffff, 13px 25px 0 -3px black, 0 33px #ffffff, -10px 33px 0 -3px black,
        -26px 24px #ffffff, -19px 17px 0 -3px black, -32px 0 #ffffff, -23px 0 0 -3px black,
        -25px -23px #ffffff, -16px -23px 0 -3px black, 0 -31px #ffffff, -2px -23px 0 -3px black;
      }
    }

    @keyframes l-2-c {
      0% {
        box-shadow: 0 0 0 #ffffff;
        opacity: 1;
        -webkit-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      50% {
        box-shadow: 24px -22px #ffffff, 30px -15px 0 -3px #ffffff, 31px 0 #ffffff, 29px 9px 0 -3px #ffffff,
        24px 23px #ffffff, 17px 30px 0 -3px #ffffff, 0 33px #ffffff, -10px 28px 0 -3px #ffffff,
        -24px 22px #ffffff, -29px 14px 0 -3px #ffffff, -31px -3px #ffffff, -30px -11px 0 -3px #ffffff,
        -20px -25px #ffffff, -12px -30px 0 -3px #ffffff, 5px -29px #ffffff, 13px -25px 0 -3px #ffffff;
        -webkit-transform: rotate(180deg);
        transform: rotate(180deg);
      }
      100% {
        opacity: 0;
        -webkit-transform: rotate(360deg);
        transform: rotate(360deg);
        box-shadow: 25px -22px #ffffff, 15px -22px 0 -3px black, 31px 2px #ffffff, 21px 2px 0 -3px black,
        23px 25px #ffffff, 13px 25px 0 -3px black, 0 33px #ffffff, -10px 33px 0 -3px black, -26px 24px #ffffff,
        -19px 17px 0 -3px black, -32px 0 #ffffff, -23px 0 0 -3px black, -25px -23px #ffffff,
        -16px -23px 0 -3px black, 0 -31px #ffffff, -2px -23px 0 -3px black;
      }
    }

    @-webkit-keyframes l-2-s {
      0% {
        -webkit-transform: scale(0) rotate(0deg);
        transform: scale(0) rotate(0deg);
      }
      100% {
        -webkit-transform: scale(0.7) rotate(360deg);
        transform: scale(0.7) rotate(360deg);
      }
    }

    @keyframes l-2-s {
      0% {
        -webkit-transform: scale(0) rotate(0deg);
        transform: scale(0) rotate(0deg);
      }
      100% {
        -webkit-transform: scale(0.7) rotate(360deg);
        transform: scale(0.7) rotate(360deg);
      }
    }
  </style>
</head>

<body>
<div id="app">
  <div id="h-lb">
    <div id="h-con">
      <svg class="l-s" xmlns="http://www.w3.org/2000/svg" version="1.1">
        <polygon
          points="29.8 0.3 22.8 21.8 0 21.8 18.5 35.2 11.5 56.7 29.8 43.4 48.2 56.7 41.2 35.1 59.6 21.8 36.8 21.8 "
          fill="#ffffff"></polygon>
      </svg>
      <div class="l-c"></div>
    </div>
  </div>
</div>
</body>
</html>

html文件中定义了不少的动画
接下来看main.js中引用了哪些东西

//main.js
import Vue from 'vue';
import Vant from 'vant';
import {Lazyload} from 'vant';
import VueClipboards from 'vue-clipboards';
import ScrollPosition from 'vue-keep-scroll-position'

import 'vant/lib/index.less'
//使用本地的icon字体
import 'vant/lib/icon/local.less';
import './assets/style/common.less';

import App from './App.vue';
import VueMixin from './mixins/VueMixin';
import i18n from './locales';
import router from './router';
import store from './vuex';
import stream from './http';
import urls from './http/urls';

Vue.use(Vant);
Vue.use(Lazyload);
Vue.use(VueClipboards);
Vue.use(ScrollPosition);
Vue.mixin(VueMixin);

Vue.prototype.$http = stream;
Vue.prototype.$urls = urls;

new Vue({
  i18n,
  router,
  store,
  el: '#app',
  render: h => h(App)
});

接下来看App.vue

<template>
  <div id="app">
    <!--缓存的页面-->
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive">
      </router-view>
    </keep-alive>
    <!--不缓存的页面-->
    <router-view v-if="!$route.meta.keepAlive">
    </router-view>
  </div>
</template>

<script>
  export default {
    name: "app",
    mounted() {
      this.loadUserInfo();
    },
    methods: {
      loadUserInfo() {
        try {
          // 读取用户信息
          let infoStr = localStorage.getItem('userInfo');
          if (infoStr) {
            let info = JSON.parse(infoStr);
            this.$store.commit('setUserInfo', info);
          }
        } catch (e) {
        }
      },
    },
  }
</script>


<style scoped lang="scss">
  #app {
    background-color: #f7f7f7;
    height: 100vh;
  }
</style>

接下来看router.js

import Vue from 'vue'
import VueRouter from 'vue-router';

Vue.use(VueRouter);

import MainPage from '../view/main/MainPage';
import TabHome from '../view/main/tabs/TabHome';
import TabProducts from '../view/main/tabs/TabProducts';
import TabDiscover from '../view/main/tabs/TabDiscover';
import TabMine from '../view/main/tabs/TabMine';

const SettingsPage = r => require.ensure([], () => r(require('../view/mine/SettingsPage')), 'SettingsPage');
const IFrameWebPage = r => require.ensure([], () => r(require('../view/common/IFrameWebPage')), 'IFrameWebPage');
const TestCasePage = r => require.ensure([], () => r(require('../view/mine/TestCasePage')), 'TestCasePage');
const ForumPage = r => require.ensure([], () => r(require('../view/discover/ForumPage')), 'ForumPage');
const MessagePage = r => require.ensure([], () => r(require('../view/mine/MessagePage')), 'MessagePage');
const MessageDetail = r => require.ensure([], () => r(require('../view/mine/MessageDetail')), 'MessageDetail');
const ProductDetail = r => require.ensure([], () => r(require('../view/product/ProductDetail')), 'ProductDetail');
const LoginPage = r => require.ensure([], () => r(require('../view/login/LoginPage')), 'LoginPage');
const GestureCreate = r => require.ensure([], () => r(require('../view/login/GestureCreate')), 'GestureCreate');

const routes = [
  {path: '*', redirect: '/main'},
  {
    name: 'main', redirect: '/main/home', component: MainPage,
    children: [
      {name: 'home', path: 'home', component: TabHome, meta: {keepAlive: true}},
      {name: 'products', path: 'products', component: TabProducts, meta: {keepAlive: true}},
      {name: 'discover', path: 'discover', component: TabDiscover, meta: {keepAlive: true}},
      {name: 'mine', path: 'mine', component: TabMine, meta: {keepAlive: true}},
    ], meta: {keepAlive: true}
  },
  {name: 'LoginPage', component: LoginPage},
  {name: 'GestureCreate', component: GestureCreate},
  {name: 'SettingsPage', component: SettingsPage},
  {name: 'IFrameWebPage', component: IFrameWebPage},
  {name: 'TestCasePage', component: TestCasePage},
  {name: 'ForumPage', component: ForumPage},
  {name: 'MessagePage', component: MessagePage},
  {name: 'ProductDetail', component: ProductDetail},
  {name: 'MessageDetail', component: MessageDetail},
];

// 懒得写path,给他们自动生成一个,和name同名
routes.forEach(route => {
  route.path = route.path || '/' + (route.name || '');
});

const router = new VueRouter({routes});

// 生命周期之前
router.beforeEach((to, from, next) => {
  // 保存个路由来路,以备不时之需
  localStorage.setItem('fromPage', from.name);
  next();
});

//生命周期之后
router.afterEach((to, from) => {
  // 滑动到顶吧
  window.scrollTo(0, 0);
});

export default router;

这个router.js也是很有意思,作者大大很有想法的
接下来看首页了


<template>
  <div>
    <div style="position: relative">
      <!--头部轮播-->
      <van-swipe :autoplay="5000" indicator-color="red">
        <van-swipe-item v-for="(item, index) in swipeImages" :key="index">
          <van-image class="swipe-img" :src="item.img" @click="swipeImageClick(item)" fit="fill"></van-image>
        </van-swipe-item>
      </van-swipe>
      <!--消息按钮-->
      <div class="msg-con" @click="onMessageClick">
        <van-image src="static/img/home/icon_message_back.png" class="msg-image"></van-image>
        <div class="msg-text">3</div>
      </div>
      <!--文本轮播-->
      <van-swipe :autoplay="3000" vertical :show-indicators="false" class="swipe-text-con">
        <van-swipe-item class="swipe-text-item" v-for="(it,idx) in textSwipes" :key="idx">
          <div class="swipe-text-txt">{{it.text}}</div>
        </van-swipe-item>
      </van-swipe>
    </div>
    <!--新手专享-->
    <div class="fresher-all">
      <div class="fresher-back align-center"
           :style="{'background-image':'url(static/img/home/fresher_ticket_back.png)'}">
        <div class="fresher-top">
          <div class="fresher-left">新手专享</div>
          <div class="fresher-right">2个活动奖励</div>
        </div>
        <div class="fresh-month">
          <div class="month-line"></div>
          <div class="month-txt light-txt">一个月期限</div>
          <div class="month-line"></div>
        </div>
        <div class="red-txt"><span class="rate-big">14</span>%+0.5%</div>
        <!--二等分区域-->
        <van-row class="num-con">
          <van-col span="12">
            <div><span class="money-big">25.50</span>万元</div>
            <div class="ins-txt light-txt">剩余金额</div>
          </van-col>
          <van-col span="12" class="right-con">
            <div><span class="money-big">12</span>万元</div>
            <div class="ins-txt light-txt">起投金额</div>
          </van-col>
        </van-row>
        <van-button type="danger" round class="buy-btn" @click="onBuyClick">立即抢购</van-button>
      </div>
    </div>
    <!--中部应用入口-->
    <van-row class="mid-app">
      <van-col span="12" v-for="(it, idx) in middleApps" :key="idx" class="mid-item click-box">
        <img :src="'static/img/home/'+it.icon" class="line2-icon"/>
        <div>
          <div class="mid-title">{{it.title}}</div>
          <div class="mid-text light-txt">{{it.text}}</div>
        </div>
      </van-col>
    </van-row>
    <!--我的账户-->
    <van-row class="money-all">
      <van-col span="12">
        <div class="light-txt">累计投资</div>
        <div class="red-txt">567,875,565.59</div>
      </van-col>
      <van-col span="12">
        <div class="light-txt">累计赚取</div>
        <div class="red-txt">67,875,565.59</div>
      </van-col>
    </van-row>
    <!--底部说明-->
    <van-row class="bot-app">
      <van-col span="12" v-for="(it, idx) in bottomApps" :key="idx" class="bot-item">
        <img :src="'static/img/home/'+it.icon" class="line4-icon"/>
        <div class="bot-text">
          <div>{{it.title}}</div>
          <div class="light-txt bot-small">{{it.text}}</div>
        </div>
      </van-col>
    </van-row>
  </div>
</template>

<script>
  export default {
    name: "tab-home",
    data() {
      return {
        swipeImages: [
          {img: 'static/img/banner/banner1.png', link: ''},
          {img: 'static/img/banner/banner2.jpg', link: ''},
          {img: 'static/img/banner/banner3.jpg', link: ''},
          {img: 'static/img/banner/banner4.jpg', link: ''},
        ],
        textSwipes: [
          {text: '修复 DatetimePicker 使用 formatter 且为 time 类型时 confirm 事件参数错误的问题'},
          {text: '修复 Tabs 在 sticky 模式下滚动回到顶部时存在 1 像素偏差的问题'},
          {text: 'ActionSheet: 新增多个 less 变量'},
        ],
        middleApps: [
          {icon: 'line2_icon1.png', title: '推荐有礼', 'text': '红包送不停'},
          {icon: 'line2_icon2.png', title: '每日签到', 'text': '积分等你加'},
          {icon: 'line2_icon3.png', title: '安全保障', 'text': '贴心小管家'},
          {icon: 'line2_icon4.png', title: '融金数据', 'text': '投资好帮手'},
        ],
        bottomApps: [
          {icon: 'line4_icon1.png', title: '互联网金融协会', 'text': '会长级别单位'},
          {icon: 'line4_icon2.png', title: '5000万融资保障', 'text': '保护您的资产安全'},
          {icon: 'line4_icon3.png', title: '国家AAA级企业', 'text': '贴心小管家'},
          {icon: 'line4_icon4.png', title: '银行风险控制', 'text': '第三方资金托管'},
        ],
      };
    },
    methods: {
      onBuyClick() {
        this._routePushQ('ProductDetail', {id: 1});
      },
      onMessageClick() {
        this._routePush('MessagePage');
      },
      swipeImageClick(item) {
      }
    }
  }
</script>

<style scoped lang="scss">
  .swipe-text-con {
    height: 30px;
    .swipe-text-item {
      height: 30px;
      display: flex;
      background-color: #fff7cc;
      align-items: center;
      .swipe-text-txt {
        height: 30px;
        font-size: 14px;
        line-height: 30px;
        padding: 0 10px;
        color: #f60;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }

  .msg-con {
    position: absolute;
    top: 20px;
    right: 20px;
    .msg-image {
      width: 36px;
      height: 36px;
    }
    .msg-text {
      position: absolute;
      top: -2px;
      right: 4px;
      box-sizing: border-box;
      min-width: 18px;
      padding: 1px 5px;
      color: #fff;
      font-size: 12px;
      text-align: center;
      background-color: #f44;
      border-radius: 30px;
      transform: translateX(50%);
      transform-origin: 100%;
    }
  }

  .money-all {
    background-color: white;
    margin-top: 10px;
    text-align: center;
    padding: 20px 0;
  }

  .bot-app {
    margin-top: 10px;
    margin-bottom: 20px;
    .bot-item {
      display: flex;
      padding: 6px 10px;
      align-items: center;
      background-color: white;
      border: 1px solid #f7f7f7;
      .bot-text {
        font-size: 12px;
        .bot-small {
          margin-top: 2px;
        }
      }
      .line4-icon {
        width: 40px;
        height: 40px;
        margin: 6px;
      }
    }
  }

  .mid-app {
    .mid-item {
      display: flex;
      align-items: center;
      border: 1px solid #f7f7f7;
      padding: 10px;
      .line2-icon {
        width: 60px;
        height: 60px;
      }
      .mid-title {
        font-size: 14px;
      }
      .mid-text {
        margin-top: 2px;
        font-size: 12px;
      }
    }
  }

  .num-con {
    margin: 12px 0;
    .money-big {
      font-size: 20px;
    }
    .ins-txt {
      font-size: 12px;
      margin-top: 6px;
    }
    .right-con {
      border-left: 1px solid #dddddd;
    }
  }

  .fresher-all {
    padding: 10px;
    .fresher-back {
      background-size: 100% 100%;
      padding: 10px 16px 16px 16px;
      .rate-big {
        font-size: 30px;
      }
      .fresher-top {
        display: flex;
        justify-content: space-between;
        color: #FE7846;
        .fresher-right {
          font-size: 14px;
          border-radius: 20px;
          padding: 1px 6px;
          border: 1px solid #FE7846;
        }
      }
      .fresh-month {
        display: flex;
        align-items: center;
        justify-content: center;
        margin-top: 30px;
        margin-bottom: 10px;
        .month-txt {
          margin: 0 20px;
        }
        .month-line {
          width: 24%;
          height: 1px;
          background-color: #aaaaaa;
        }
      }
      .buy-btn {
        width: 70%;
        font-size: 16px;
        height: 36px;
        line-height: 30px;
      }
    }
  }

  .swipe-img {
    vertical-align: bottom;
    width: 100%;
    height: 50vw;
  }
</style>

接下来是message页面

<template>
  <div>
    <van-nav-bar left-arrow @click-left="_routerBack" title="融金公告" fixed :z-index="10"></van-nav-bar>
    <div class="nav-con-16">
      <div v-for="(it, idx) in messageData" :key="idx" class="msg-item click-box" @click="onClickMessage(it)">
        <div class="msg-title">{{it.title}}</div>
        <div class="msg-sub">
          <div class="msg-flag">{{it.flag}}</div>
          <div class="msg-date light-txt">{{it.date}}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: "message-page",
    data() {
      return {
        messageData: [
          {title: '新增 Grid、GridItem 组件', flag: '平台公告', date: '2019-05-02'},
          {title: '修复 Collapse 在 safari 浏览器上动画可能闪烁的问题', flag: '平台公告', date: '2019-05-02'},
          {title: 'CouponList: 新增 enabled-title、disabled-title 属性', flag: '平台公告', date: '2019-03-02'},
          {title: '新增 Grid、GridItem 组件', flag: '平台公告', date: '2019-05-02'},
          {title: '修复 Collapse 在 safari 浏览器上动画可能闪烁的问题', flag: '平台公告', date: '2019-05-02'},
          {title: 'CouponList: 新增 enabled-title、disabled-title 属性', flag: '平台公告', date: '2019-03-02'},
        ],
      };
    },
    methods: {
      onClickMessage(item) {
        this._routePush('MessageDetail');
      }
    },
  }
</script>

<style scoped lang="scss">
  .msg-item {
    margin-bottom: 12px;
    padding: 12px;
    .msg-title {
      font-size: 14px;
      color: #666666;
    }
    .msg-sub {
      display: flex;
      align-items: center;
      margin-top: 10px;
      justify-content: space-between;
      .msg-date {
        font-size: 12px;
      }
      .msg-flag {
        font-size: 14px;
        border-radius: 20px;
        border: solid 1px #f56723;
        color: #f56723;
        padding: 1px 8px;
      }
    }
  }
</style>

<template>
  <div>
    <van-nav-bar left-arrow @click-left="_routerBack" title="C计划详情" fixed :z-index="10"></van-nav-bar>
    <div class="nav-con-16">
      <!--头部信息-->
      <div class="main-con">
        <div class="van-hairline--bottom prod-name">
          <span class="name-ico">C</span>中小企业-E车贷ECO JKI45002 1654241
        </div>
        <div class="align-center rate-con">
          <div class="red-txt"><span class="big-rate">4.98</span>%</div>
          <div class="rate-tit">预期年化收益</div>
          <div class="period-txt top-mar-16">期限12个月</div>
        </div>
        <div>
          <div class="pro-per">投资进度<span class="red-txt">64.5%</span></div>
          <van-progress :percentage="64.5" color="#ff6611" class="prod-progress" :show-pivot="false">
          </van-progress>
          <div class="pro-amount">
            <div>项目总额180万</div>
            <div>剩余可投<span class="red-txt">75万</span></div>
          </div>
        </div>
      </div>
      <!--中部信息-->
      <div class="top-mar-16 detail-con">
        <div class="top-title van-hairline--bottom">
          <div>C计划简介</div>
          <div class="period-txt">优享计划</div>
        </div>
        <div class="top-intro">优选分散投资,确保稳定收益</div>
        <van-row>
          <van-col span="6" class="row-item" v-for="(it,idx) in statusList" :key="idx">
            <div class="align-center">
              <van-image :src="'static/img/product/'+it.img1" class="status-img"></van-image>
              <div class="status-txt">{{it.text}}</div>
            </div>
            <van-image :src="'static/img/product/'+it.img2" v-if="idx!=3" class="arrow-img"></van-image>
          </van-col>
        </van-row>
      </div>
      <!--底部选项-->
      <div class="top-mar-16">
        <van-cell-group>
          <van-cell title="计划详情" is-link size="large"></van-cell>
          <van-cell title="购买记录" is-link size="large"></van-cell>
          <van-cell title="常见问题" is-link size="large"></van-cell>
        </van-cell-group>
      </div>
      <div class="align-center bottom-txt">个人资产由银行托管保障安全</div>
      <!--底部按钮-->
      <van-button type="danger" class="bottom-btn">
        立即投标 <span class="btn-left">(剩余可投70万元)</span>
      </van-button>
    </div>
  </div>
</template>

<script>
  export default {
    name: "product-detail",
    data() {
      return {
        statusList: [
          {img1: 'prod_status2.png', img2: 'prod_arrow1.png', text: '启动计划'},
          {img1: 'prod_status3.png', img2: 'prod_arrow1.png', text: '启动计划'},
          {img1: 'prod_status4.png', img2: 'prod_arrow1.png', text: '启动计划'},
          {img1: 'prod_status1.png', img2: 'prod_arrow1.png', text: '启动计划'},
        ],
      };
    },
  }
</script>

<style scoped lang="scss">
  .bottom-txt {
    padding: 30px 0 64px 0;
    font-size: 14px;
    background-color: #f7f7f7;
    color: #999999;
  }

  .detail-con {
    background-color: white;
    padding: 10px;
    .top-intro {
      margin-top: 16px;
      color: #999999;
    }
    .row-item {
      display: flex;
      align-items: center;
      padding: 16px 0;
      .status-img {
        width: 10vw;
        height: 10vw;
      }
      .arrow-img {
        width: 6vw;
        height: 6vw;
      }
      .status-txt {
        font-size: 12px;
        color: #999999;
      }
    }
    .top-title {
      display: flex;
      align-items: center;
      justify-content: space-between;
      font-size: 14px;
      padding-bottom: 10px;
      color: #999999;
    }
  }

  .bottom-btn {
    position: fixed;
    bottom: 0;
    width: 100%;
    border-radius: 0;
    font-size: 20px;
    height: 46px;
    .btn-left {
      font-size: 14px;
    }
  }

  .period-txt {
    font-size: 14px;
    color: #ff6611;
    display: inline-block;
    padding: 1px 8px;
    border: 1px solid #ff6611;
    border-radius: 20px;
  }

  .rate-con {
    padding: 20px 0;
    .rate-tit {
      color: #999999;
      font-size: 14px;
      margin-top: 8px;
    }
    .big-rate {
      font-size: 34px;
    }
  }

  .pro-per {
    margin: 4px 0;
    font-size: 14px;
    color: #999999;
  }

  .pro-amount {
    display: flex;
    justify-content: space-between;
    margin-top: 4px;
    font-size: 14px;
    color: #999999;
  }

  .prod-progress {
    height: 6px;
  }

  .main-con {
    background-color: white;
    padding: 10px;
    .prod-name {
      padding: 4px 0;
      font-size: 14px;
      color: #666666;
      .name-ico {
        background-color: #ff6c6c;
        height: 20px;
        padding: 0 4px;
        margin-right: 4px;
        border-radius: 2px;
        color: white;
        line-height: 20px;
      }
    }
  }
</style>

<template>
  <div>
    <div class="top-fixed">
      <van-nav-bar :title="$t('tab_products')" fixed :z-index="10"></van-nav-bar>
      <div class="nav-con navbar-con">
        <van-tabs v-model="activeSort" class="sort-all" sticky @change="onTabChange" line-width="33%" type="card">
          <van-tab :title="it_so.title" v-for="(it_so, idx) in sortItems" :key="idx">
            <div class="prod-item click-box" v-for="(it_po,idx_p) in getProductList(idx)"
                 :key="idx_p" @click="onProductClick(it_po)">
              <van-row>
                <van-col span="12" class="prod-rate">
                  <div class="red-txt rate-txt"><span class="rate-big">{{it_po.rate}}</span>%+{{it_po.add}}%</div>
                  <div class="light-txt rate-ins">预期年化收益率</div>
                </van-col>
                <van-col span="12" class="prod-ins">
                  <div class="prod-title">{{it_po.name}}</div>
                  <div class="prod-tag">期限{{it_po.days}}天</div>
                </van-col>
              </van-row>
              <!--进度条-->
              <van-progress :percentage="it_po.percent" color="#ff6611" class="prod-progress" :show-pivot="false">
              </van-progress>
              <div class="pro-amount">
                <div>项目总额180万</div>
                <div>剩余可投<span class="red-txt">75万</span></div>
              </div>
            </div>
          </van-tab>
        </van-tabs>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: "tab-products",
    data() {
      return {
        activeSort: 0,
        sortItems: [
          {title: '推荐'},
          {title: '收益率'},
          {title: '期限'},
        ],
        allProducts: [
          {id: 5, rate: 4.5, add: 0.5, name: 'A计划064512544', days: 365, percent: 65},
          {id: 6, rate: 4.0, add: 0.5, name: 'B计划064512542', days: 60, percent: 95},
          {id: 7, rate: 2.5, add: 0.1, name: 'C计划064512546', days: 30, percent: 23},
          {id: 8, rate: 4.5, add: 0.5, name: 'A计划064512544', days: 365, percent: 65},
          {id: 9, rate: 4.0, add: 0.5, name: 'B计划064512542', days: 60, percent: 95},
          {id: 22, rate: 2.5, add: 0.1, name: 'C计划064512546', days: 30, percent: 23},
          {id: 34, rate: 4.5, add: 0.5, name: 'A计划064512544', days: 365, percent: 65},
          {id: 21, rate: 4.0, add: 0.5, name: 'B计划064512542', days: 60, percent: 95},
          {id: 12, rate: 2.5, add: 0.1, name: 'C计划064512546', days: 30, percent: 23},
          {id: 13, rate: 6.0, add: 0.1, name: 'C计划064512546(售罄)', days: 10, percent: 100},
          {id: 14, rate: 5.0, add: 0.1, name: 'C计划064512543(售罄)', days: 120, percent: 100},
          {id: 15, rate: 6.0, add: 0.1, name: 'C计划064512546(售罄)', days: 10, percent: 100},
          {id: 16, rate: 5.0, add: 0.1, name: 'C计划064512543(售罄)', days: 120, percent: 100},
          {id: 17, rate: 6.0, add: 0.1, name: 'C计划064512546(售罄)', days: 10, percent: 100},
          {id: 18, rate: 5.0, add: 0.1, name: 'C计划064512543(售罄)', days: 120, percent: 100},
        ],
      };
    },
    computed: {
      getProductList() {
        let newList = this.allProducts.slice(0);
        return (index) => {
          if (index == 0) {
            return this.allProducts;
          } else if (index == 1) {
            return newList.sort((a, b) => {
              return a.rate - b.rate;
            });
          } else if (index == 2) {
            return newList.sort((a, b) => {
              return a.days - b.days;
            });
          }
        }
      }
    },
    methods: {
      onProductClick(item) {
        this._routePushQ('ProductDetail', {id: item.id});
      },
      onTabChange() {
      },
    },
  }
</script>

<style scoped lang="scss">
  .prod-item {
    padding: 12px;
    margin-top: 12px;
    .pro-amount {
      display: flex;
      justify-content: space-between;
      margin-top: 4px;
      font-size: 14px;
      color: #999999;
    }
    .prod-progress {
      margin-top: 20px;
      height: 6px;
    }
    .prod-rate {
      text-align: center;
      padding: 2px 10px;
      .rate-txt {
        font-size: 14px;
        .rate-big {
          font-size: 24px;
        }
      }
      .rate-ins {
        font-size: 12px;
        margin-top: 4px;
      }
    }
    .prod-ins {
      border-left: 1px solid #aaaaaa;
      padding: 2px 10px;
      .prod-title {
        font-size: 14px;
      }
      .prod-tag {
        display: table;
        font-size: 12px;
        margin-top: 16px;
        border: 1px solid #ff6c6c;
        border-radius: 20px;
        color: #ff6c6c;
        padding: 0 6px;
      }
    }
  }

  .navbar-con {
    .sort-all {
      padding-top: 0;
    }
  }
</style>

<template>
  <div>
    <van-nav-bar :title="$t('tab_discovery')" fixed :z-index="10"></van-nav-bar>
    <div class="nav-con">
      <!--顶部图片-->
      <van-image src="static/img/discovery/discovery_banner.jpg" class="banner-img"></van-image>
      <!--中部内容-->
      <div style="padding: 10px">
        <div class="align-center commu-all"
             :style="{'background-image':'url(static/img/home/fresher_ticket_back.png)'}">
          <div class="commu-top">
            <div class="commu-left">好帖推荐</div>
            <div class="commu-right">2个活动奖励</div>
          </div>
          <div class="commu-mid">
            <div class="commu-title">外交部:台湾同胞可在中国驻外使领馆寻求保护协助</div>
            <div class="light-txt commu-txt">
              外交部领保中心常务副主任杨舒介绍了“26条措施”的第14条,台湾同胞可在中国驻外使领馆寻求领事保护与协助的途径...
            </div>
          </div>
          <van-button type="danger" round class="commu-btn" @click="onCommuClick">进入社区</van-button>
        </div>
      </div>
      <!--下部应用入口-->
      <van-row class="line2-all">
        <van-col span="12" v-for="(it, idx) in middleApps" :key="idx" class="line2-item click-box">
          <img :src="'static/img/discovery/'+it.icon" class="line2-icon"/>
          <div>
            <div class="line2-title">{{it.title}}</div>
            <div class="line2-text light-txt">{{it.text}}</div>
          </div>
        </van-col>
      </van-row>
    </div>
  </div>
</template>

<script>
  export default {
    name: "tab-discover",
    data() {
      return {
        middleApps: [
          {icon: 'discovery_app_icon4.png', title: '积分商城', 'text': '绝不让每一个积分落空'},
          {icon: 'discovery_app_icon2.png', title: '融金公益', 'text': '时间有爱,融金有益'},
          {icon: 'discovery_app_icon3.png', title: '红包广场', 'text': '福利大派送,一起来抢钱'},
          {icon: 'discovery_app_icon1.png', title: '任务大厅', 'text': 'VIP进阶之路'},
          {icon: 'discovery_app_icon5.png', title: '理财小公举', 'text': '算一算我的第一桶金'},
        ],
      };
    },
    methods: {
      onCommuClick() {
        this._loginOr(() => {
          this._routePush('ForumPage');
        })
      }
    },
  }
</script>

<style scoped lang="scss">
  .commu-all {
    background-size: 100% 100%;
    padding: 6px 16px 20px 16px;
    .commu-mid {
      padding: 10px;
      text-align: left;
      .commu-title {
        font-size: 16px;
        margin-top: 14px;
      }
      .commu-txt {
        font-size: 14px;
        margin-top: 10px;
      }
    }
    .commu-btn {
      margin-top: 10px;
      width: 70%;
      font-size: 16px;
      height: 36px;
      line-height: 30px;
    }
    .commu-top {
      display: flex;
      justify-content: space-between;
      color: #FE7846;
      .commu-right {
        font-size: 14px;
        border-radius: 20px;
        padding: 0 6px;
        border: 1px solid #FE7846;
      }
    }
  }

  .banner-img {
    width: 100%;
    height: 35vw;
  }

  .line2-all {
    margin-bottom: 20px;
    .line2-item {
      display: flex;
      border: 1px solid #f7f7f7;
      align-items: center;
      padding: 10px;
      .line2-icon {
        width: 60px;
        height: 60px;
      }
      .line2-title {
        font-size: 14px;
      }
      .line2-text {
        font-size: 12px;
        margin-top: 2px;
      }
    }
  }
</style>

<template>
  <div>
    <van-nav-bar left-arrow @click-left="_routerBack" title="登录" fixed :z-index="10"></van-nav-bar>
    <div class="nav-con align-center login-con"
         :style="{'background-image':'url(static/img/login/login_back.png)'}">
      <div class="top-area">
        <van-image src="static/img/login/vant_logo.png" class="top-logo"></van-image>
        <div>Vant Finance</div>
      </div>
      <!--用户名密码登录-->
      <div v-if="loginWay==1">
        <van-cell-group>
          <!--输入账号-->
          <van-field v-model="userName" left-icon="static/img/login/login_user.png" required clearable label="用户名"
                     placeholder="请输入手机号/用户名(随便填)" label-align="left" size="large" maxlength="20"></van-field>
          <!--输入密码-->
          <van-field v-model="password" left-icon="static/img/login/login_pass.png" label="密 码"
                     placeholder="请输入密码(随便填)" size="large" required clearable
                     :type="showPassword?'text':'password'" maxlength="20"
                     :right-icon="'static/img/login/eye_'+(showPassword?'open':'close')+'.png'"
                     @click-right-icon="showPassword=!showPassword"></van-field>
        </van-cell-group>
        <!--账密登录按钮-->
        <div class="button-con">
          <van-button type="danger" round class="login-btn" :disabled="!canPwdLogin" @click="onLoginClick">登录
          </van-button>
          <van-button type="danger" plain round class="login-btn" @click="loginWay=3-loginWay">短信登录</van-button>
        </div>
      </div>
      <!--验证码登陆-->
      <div v-else>
        <van-cell-group>
          <!--输入账号-->
          <van-field v-model="userName" left-icon="static/img/login/login_user.png" required clearable label="手机号"
                     placeholder="请输入手机号(随便填)" label-align="left" size="large" maxlength="11"></van-field>
          <!--填写验证码-->
          <van-field v-model="smsCode" clearable label="验证码" placeholder="请输入短信验证码" size="large"
                     left-icon="envelop-o" maxlength="6" required>
            <van-button slot="button" size="small" plain type="danger" class="send-btn" @click="onSMSSend"
                        :disabled="!isSendSMSEnable">
              {{getSendBtnText}}
            </van-button>
          </van-field>
        </van-cell-group>
        <!--账密登录按钮-->
        <div class="button-con">
          <van-button type="danger" round class="login-btn" :disabled="!canSMSLogin" @click="onSMSLogin">登录
          </van-button>
          <van-button type="danger" plain round class="login-btn" @click="loginWay=3-loginWay">账号登录</van-button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  export default {
    name: "login-page",
    data() {
      return {
        userName: '',
        password: '',
        smsCode: '',
        showPassword: false, //是否显示明文
        loginWay: 1, //1: 账密,2:验证码
        smsCountDown: 0,
        smsCountInterval: null,
      };
    },
    computed: {
      isSendSMSEnable() {
        return this.smsCountDown <= 0 && this.userName.length > 4;
      },
      getSendBtnText() {
        if (this.smsCountDown > 0) {
          return this.smsCountDown + '秒后发送';
        } else {
          return '发送验证码';
        }
      },
      canSMSLogin() {
        return this.userName.length > 4 && this.smsCode.length > 4;
      },
      canPwdLogin() {
        return this.userName.length > 4 && this.password.length > 4;
      },
    },
    mounted() {
    },
    beforeDestroy() {
      if (this.smsCountInterval) {
        clearInterval(this.smsCountInterval);
      }
    },
    methods: {
      onSMSSend() {
        this._showLoading();
        setTimeout(() => {
          this._dismissLoading();
          this._showToast('已发送');
          this.smsCountDown = 60;
          this.startSMSTimer();
        }, 300);
      },
      startSMSTimer() {
        this.smsCountInterval = setInterval(() => {
          this.smsCountDown--;
          if (this.smsCountDown <= 0) {
            clearInterval(this.smsCountInterval);
          }
        }, 1000);
      },
      onSMSLogin() {
        this.onLoginClick();
      },
      // 模拟登陆
      onLoginClick() {
        this._showLoading();
        setTimeout(() => {
          this._dismissLoading();
          this.saveUserInfo();
          this._showConfirm('登陆成功, 去设置手势密码?', () => {
            this._routeReplace('GestureCreate');
          }, this._routerBack);
        }, 1000);
      },
      //保存用户信息
      saveUserInfo() {
        let info = {userName: this.userName};
        // 全局修改
        this.$store.commit('setUserInfo', info);
        // 持久化修改
        localStorage.setItem('userInfo', JSON.stringify(info));
      },
    },
  }
</script>

<style scoped>
  .send-btn {
    height: 26px;
    line-height: 24px;
  }

  .button-con {
    margin-top: 36px;
  }

  .top-area {
    margin: 30px 0;
  }

  .login-con {
    background-size: 100% 100%;
    height: calc(100vh - 46px);
  }

  .login-btn {
    width: 60%;
    margin: 12px;
  }

  .top-logo {
    width: 100px;
    margin: 16px 0;
  }
</style>

<template>
  <div>
    <!--顶部导航-->
    <div class="top-nav">
      <van-image lazy-load src="https://img.yzcdn.cn/vant/cat.jpeg" class="head-img" fit="cover"></van-image>
      <div>愤怒的小猫</div>
      <div class="top-right">
        <van-icon name="static/img/mine/mine_nav_message2.png" size="28px" style="margin-right: 6px"
                  @click="onMessageClick"></van-icon>
        <van-icon name="static/img/mine/mine_nav_settings2.png" size="28px" @click="onSettingsClick"></van-icon>
      </div>
    </div>
    <!--下部内容-->
    <div class="nav-con">
      <div class="amount-con">
        <div class="red-txt amount-txt">15,564,589,744.63</div>
        <div class="light-txt amount-ins">资产总额(元)></div>
      </div>
      <!--代收收益-->
      <van-row class="receive-all">
        <van-col span="12">
          <div>567,875,565.59</div>
          <div class="light-txt receive-ins">累计投资</div>
        </van-col>
        <van-col span="12" class="receive-right">
          <div>67,875,56</div>
          <div class="light-txt receive-ins">累计赚取</div>
        </van-col>
      </van-row>
      <!--我的余额-->
      <div class="remain-con">
        <div>
          <div class="red-txt avail-amount">6850.65</div>
          <div class="light-txt avail-ins">可用余额(元)</div>
        </div>
        <div class="remain-right">
          <div class="remain-draw">提现</div>
          <div class="remain-divi"></div>
          <van-button type="danger" round size="small" class="remain-charge">充值</van-button>
        </div>
      </div>
      <!--下方应用入口-->
      <van-row class="app-con">
        <van-col span="8" v-for="(it,idx) in bottomApps" :key="idx" class="app-item click-box">
          <van-image v-if="it.flag" :src="'static/img/mine/'+it.flag" class="flag-icon"></van-image>
          <div>
            <van-image :src="'static/img/mine/'+it.icon" class="app-icon"></van-image>
            <div class="app-text light-txt">{{it.title}}</div>
          </div>
        </van-col>
      </van-row>
    </div>
  </div>
</template>

<script>
  export default {
    name: "tab-mine",
    data() {
      return {
        bottomApps: [
          {icon: 'mine_app_icon3.png', flag: '', title: '我的投资',},
          {icon: 'mine_app_icon8.png', flag: '', title: '回款日历',},
          {icon: 'mine_app_icon2.png', flag: '', title: '投资设置',},
          {icon: 'mine_app_icon6.png', flag: 'mine_app_flag2.png', title: '卡券包',},
          {icon: 'mine_app_icon9.png', flag: '', title: '积分',},
          {icon: 'mine_app_icon5.png', flag: 'mine_app_flag1.png', title: '邀请好友',},
          {icon: 'mine_app_icon4.png', flag: '', title: '我要借款',},
          {icon: 'mine_app_icon7.png', flag: '', title: '关于我们',},
          {icon: 'mine_app_icon1.png', flag: '', title: '联系客服',},
        ],
      };
    },
    methods: {
      onMessageClick() {
        this._routePush('MessagePage');
      },
      onSettingsClick() {
        this._routePush('SettingsPage')
      },
    },
  }
</script>

<style scoped lang="scss">
  .app-con {
    margin: 12px 0;
    .app-item {
      border: 1px solid #f7f7f7;
      text-align: center;
      position: relative;
      padding: 24px 0;
      .flag-icon {
        position: absolute;
        right: 0;
        top: 0;
        width: 36px;
        height: 36px;
      }
      .app-text {
        font-size: 14px;
      }
      .app-icon {
        width: 36px;
        height: 36px;
      }
    }
  }

  .remain-con {
    margin-top: 12px;
    background-color: white;
    display: flex;
    justify-content: space-between;
    padding: 14px;
    .avail-amount {
      font-size: 20px;
    }
    .avail-ins {
      margin-top: 4px;
      font-size: 14px;
    }
    .remain-right {
      display: flex;
      align-items: center;
      font-size: 16px;
      .remain-divi {
        width: 1px;
        height: 24px;
        margin: 0 18px;
        background-color: #cccccc;
      }
      .remain-charge {
        height: 24px;
        line-height: 21px;
      }
    }
  }

  .receive-all {
    text-align: center;
    margin-top: 12px;
    background-color: white;
    padding: 16px;
    .receive-right {
      border-left: 1px solid #cccccc;
    }
    .receive-ins {
      font-size: 14px;
      margin-top: 6px;
    }
  }

  .amount-con {
    width: 100%;
    background-color: white;
    text-align: center;
    padding-top: 30px;
    padding-bottom: 20px;
    .amount-ins {
      font-size: 14px;
      margin-top: 10px;
    }
    .amount-txt {
      font-size: 28px;
    }
  }

  .top-nav {
    background-color: white;
    position: fixed;
    height: 50px;
    z-index: 10;
    border-bottom: 1px solid #f7f7f7;
    top: 0;
    left: 0;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    .top-right {
      margin-right: 16px;
    }
    .head-img {
      width: 30px;
      height: 30px;
      border-radius: 40px;
      overflow: hidden;
      margin-left: 16px;
    }
  }
</style>

<template>
  <div>
    <van-nav-bar left-arrow @click-left="_routerBack" :title="$t('settings')" fixed :z-index="10"></van-nav-bar>
    <!--内容区-->
    <div class="nav-con-16">
      <van-cell-group>
        <van-cell :title="$t('version')" icon="info-o" :value="versionName" size="large" @click="onVersionClick">
        </van-cell>
        <van-cell :title="$t('language')" icon="flag-o" :value="$t(langOptions[currentLang])" size="large"
                  @click="onLangClick" is-link>
        </van-cell>
        <van-cell title="Vant文档" is-link size="large" @click="onVantDocClick"></van-cell>
        <van-cell title="手势密码设置" icon="eye-o" size="large" @click="_routePush('GestureCreate')" is-link>
        </van-cell>
      </van-cell-group>
    </div>
    <!--语言弹窗-->
    <van-popup v-model="showLangPop" class="lang-pop">
      <van-radio-group v-model="currentLang" @change="onLangChange">
        <van-cell clickable @click="currentLang = 'en'">
          <van-radio name="en" @click="showLangPop=false">{{$t(langOptions.en)}}</van-radio>
        </van-cell>
        <van-cell clickable @click="currentLang = 'zh'">
          <van-radio name="zh" @click="showLangPop=false">{{$t(langOptions.zh)}}</van-radio>
        </van-cell>
      </van-radio-group>
    </van-popup>
  </div>
</template>

<script>
  import 'vant/lib/radio/index.less'

  export default {
    name: "settings-page",
    data() {
      return {
        versionName: 'V ' + pack.PACK_VERSION,
        currentLang: this.$i18n.locale,
        showLangPop: false,
        langOptions: {
          'en': 'english',
          'zh': 'chinese',
        },
        versionClickTime: 0,
      };
    },
    methods: {
      onVantDocClick() {
        location.href = 'https://youzan.github.io/vant/mobile.html';
      },
      onLangChange(val) {
        this.showLangPop = false;
        window.localStorage.setItem('language', val);
        this.$i18n.reload();
      },
      onLangClick() {
        this.showLangPop = true;
      },
      onVersionClick() {
        this._showToast(pack.PACK_DATE + ' ' + process.env.HOST_ENV);
        this.versionClickTime += 1;
        // 打开测试菜单
        if (this.versionClickTime == 4) {
          this._routePush('TestCasePage');
        }
      },
    }
  }
</script>

<style scoped>
  .lang-pop {
    width: 80%;
    padding: 10px;
    border-radius: 8px;
  }
</style>

这个页面也挺有意思的,作者大大的代码很有趣

<template>
  <div>
    <van-nav-bar left-arrow @click-left="_routerBack" title="设置手势密码" fixed :z-index="10"></van-nav-bar>
    <div class="align-center navbar-con-16">
      <!--上方小框-->
      <div class="top-small-con">
        <div class="top-small">
          <div v-for="i in 9" :key="i" class="top-dot" :class="{'high-dot':isHighlight(i)}"></div>
        </div>
      </div>
      <!--提示语-->
      <div class="info-tip" :class="{'error-tips': isTipsError}">{{infoTips}}</div>
      <!--密码输入-->
      <gesture-lock @input="onLockInput" ref="inputLock" class="main-lock">
      </gesture-lock>
      <div class="reinput-entry" @click="onResetInput" v-if="lastInput.length">
        重新设置手势密码
      </div>
    </div>
  </div>
</template>

<script>
  import GestureLock from "../common/GestureLock";

  export default {
    components: {GestureLock},
    name: "gesture-create",
    data() {
      return {
        isTipsError: false,
        infoTips: '',
        lastInput: [],
      };
    },
    computed: {
      isHighlight() {
        return (idx) => {
          if (this.lastInput) {
            for (let ii in this.lastInput) {
              if (this.lastInput[ii] == idx - 1) {
                return true;
              }
            }
          }
        }
      }
    },
    mounted() {
      this.showMessage('请输入手势密码')
    },
    methods: {
      onResetInput() {
        this.lastInput = [];
        this.showMessage('请输入手势密码')
      },
      requestSetGesturePwd(pwd) {
        this._showLoading();
        // 持久化修改
        localStorage.setItem('gesturePassword', pwd);
        setTimeout(() => {
          this._dismissLoading();
          this._showToast('手势密码设置成功!');
          this._routerBack();
        }, 1000);
      },
      checkPwdAndUpdate(code) {
        let lastPwd = this.lastInput.join('');
        let pwd = code.join('');
        if (pwd && pwd == lastPwd) {
          this.showMessage('请输入手势密码')
          this.$refs.inputLock.clear();
          this.requestSetGesturePwd(pwd);
        } else {
          this.showLockError('两次输入不一致,请重新输入');
        }
      },
      onLockInput(res) {
        if (res.length < 4) {
          this.showLockError('至少需要连接四个点');
          return
        }
        // 第二次输入
        if (this.lastInput.length) {
          this.checkPwdAndUpdate(res)
        } else {
          this.lastInput = res;
          this.showMessage('请再重复一遍');
          this.$refs.inputLock.clear();
        }
      },
      showMessage(msg) {
        this.isTipsError = false;
        this.infoTips = msg;
      },
      showLockError(msg) {
        this.isTipsError = true;
        this.infoTips = msg;
        this.$refs.inputLock.showError()
      }
    }
  }
</script>

<style scoped lang="less">
  .reinput-entry {
    color: @blue;
    margin-top: 40px;
    text-decoration: underline;
  }

  .top-small-con {
    display: flex;
    justify-content: center;
    .top-small {
      width: 42px;
      display: flex;
      flex-wrap: wrap;
      .top-dot {
        margin: 2px;
        width: 10px;
        height: 10px;
        background-color: #aaaaaa;
        border-radius: 20px;
        display: block;
      }
      .high-dot {
        background-color: @blue;
      }
    }
  }

  .info-tip {
    margin-top: 20px;
    font-size: 14px;
  }

  .error-tips {
    color: red;
  }

  .main-lock {
    margin: 20px 0;
  }
</style>

代码看了这么久,有没有发现他们好像没有底部的导航栏
在这里呢

<template>
  <div>
    <!--缓存的页面-->
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive" class="main-router-view" v-keep-scroll-position>
      </router-view>
    </keep-alive>
    <!--不缓存的页面-->
    <router-view v-if="!$route.meta.keepAlive" class="main-router-view">
    </router-view>
    <!--下方的TabBar-->
    <van-tabbar v-model="tabBarSelect">
      <!--TabBar项目-->
      <van-tabbar-item v-for="(item, i) in tabItemList" :key="i" :to="item.to" replace>
        <div class="tab-txt">{{$t(item.name)}}</div>
        <img :src="getTabIconSrc(item, props.active)" slot="icon" slot-scope="props" class="icon-img"/>
      </van-tabbar-item>
    </van-tabbar>
  </div>
</template>

<script>
  export default {
    name: "main-page",
    watch: {
      '$route'() {
        this.checkTabSelection();
      }
    },
    computed: {
      // 获取图标资源
      getTabIconSrc() {
        return (item, active) => {
          let img = active ? item.active : item.normal;
          return 'static/img/main/' + img;
        }
      },
    },
    data() {
      return {
        tabBarSelect: 0,
        // Tab栏数据
        tabItemList: [
          {
            active: 'main_tab_3.png',
            normal: 'main_tab_2.png',
            name: 'tab_home',
            to: "home"
          },
          {
            active: 'main_tab_5.png',
            normal: 'main_tab_4.png',
            name: 'tab_products',
            to: "products"
          },
          {
            active: 'main_tab_7.png',
            normal: 'main_tab_6.png',
            name: 'tab_discovery',
            to: "discover"
          },
          {
            active: 'main_tab_1.png',
            normal: 'main_tab_8.png',
            name: 'tab_mine',
            to: "mine"
          },
        ],
      };
    },
    methods: {
      // 看一下tab栏应给高亮哪一个
      checkTabSelection() {
        for (let i = 0; i < this.tabItemList.length; i++) {
          let p = this.tabItemList[i];
          if (this.$route.path.endsWith(p.to)) {
            this.tabBarSelect = i;
          }
        }
      }
    },
    mounted() {
      this.checkTabSelection();
    }
  }
</script>

<style scoped>
  .tab-txt {
    text-align: center;
    margin-top: -2px;
  }

  .main-router-view {
    height: calc(100vh - 50px);
    overflow-y: auto;
    box-sizing: border-box;
    background-color: #f8f8f8;
  }

  .icon-img {
    margin-bottom: -1px;
    height: 25px;
  }
</style>

这个项目很有意思,里面的东西还有许多有趣的,等着你去发现呢~~~给这个博主大大点赞,不过他的黄色网址差评
看了一下代码,好像是在这里配置的

不过作者大大的项目确实写的很好,所以,赞赞赞 老实说有些点我没有消化,不过项目很有趣,有些实现的点,还是第一次见呢


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!