zoukankan      html  css  js  c++  java
  • 【vue】openshopping-vue

    这是一个基于Vue实现开箱即用H5移动端商城的单页应用
    作者的开源地址是:https://github.com/yrinleung/openshopping-vue
    我们一起来欣赏页面吧

    看看代码有什么乾坤
    看了下package.json发现有axios和vue-lazyload

    先看代码一层一层进去里面

    //app.vue
    <template>
      <div id="app">
        <router-view/>
      </div>
    </template>
    
    <script>
    import './assets/style/common.css';
    
    export default {
      name: 'app'
    }
    </script>
    

    看main.js中的
    由上到下一步一步来

    先看config中的router.js
    虽说是普通的router页面,不过对路由的处理很有意思

    //router.js
    import Vue from 'vue';
    import Router from 'vue-router';
    
    Vue.use(Router);
    
    const routes = [
      {
        path: '*',
        redirect: '/home'
      },
      {
        name: 'home',
        component: () => import('../page/index'),
        meta: {
          title: '首页'
        }
      },
      {
    		path: '/login',
        component: () => import('../page/account/login'),
        meta: {
          title: '登录'
        }
      },
      {
    		path: '/login/password',
        component: () => import('../page/account/password'),
        meta: {
          title: '登录'
        }
      },
      {
    		path: '/login/phone',
        component: () => import('../page/account/phonelogin'),
        meta: {
          title: '手机号登录'
        }
      },
      {
    		path: '/login/register',
        component: () => import('../page/account/register'),
        meta: {
          title: '注册'
        }
      },
      {
    		path: '/user/index',
        component: () => import('../page/user/index'),
        name: 'user',
        meta: {
          title: '会员中心'
        }
      },
      {
    		path: '/user/info',
        component: () => import('../page/user/info/detail'),
        name: 'user',
        meta: {
          title: '账号管理'
        }
      },
      {
        path: '/user/address',
        component: () => import('../page/user/address/list'),
        meta: {
          title: '我的地址'
        }
      },
      {
        path: '/user/address/edit',
        component: () => import('../page/user/address/edit'),
        meta: {
          title: '修改地址'
        }
      },
      {
        path: '/user/favorite',
        component: () => import('../page/user/favorite/list'),
        meta: {
          title: '我的收藏'
        }
      },
      {
        path: '/user/coupon',
        component: () => import('../page/user/coupon/list'),
        meta: {
          title: '我的优惠券'
        }
      },
      {
        path: '/user/order',
        component: () => import('../page/user/order/list'),
        meta: {
          title: '我的订单'
        }
      },
      {
        path: '/user/order/:id',
        component: () => import('../page/user/order/list'),
        meta: {
          title: '我的订单'
        }
      },
      {
        path: '/user/order/info/:id',
        component: () => import('../page/user/order/info'),
        meta: {
          title: '我的订单'
        }
      },
      {
        path: '/user/order/logistics/:id',
        component: () => import('../page/user/order/logistics'),
        meta: {
          title: '订单追踪'
        }
      },
      {
        path: '/user/aftersale',
        component: () => import('../page/user/aftersale/list'),
        meta: {
          title: '售后'
        }
      },
      {
        path: '/user/aftersale/apply',
        component: () => import('../page/user/aftersale/apply'),
        meta: {
          title: '申请售后'
        }
      },
      {
        path: '/user/aftersale/detail',
        component: () => import('../page/user/aftersale/detail'),
        meta: {
          title: '服务单详情'
        }
      },
      {
        path: '/user/aftersale/track/:id',
        component: () => import('../page/user/aftersale/track'),
        meta: {
          title: '进度详情'
        }
      },
      {
        path: '/product/:id',
        component: () => import('../page/product/detail'),
        meta: {
          title: '商品详情'
        }
      },
      {
        path: '/search',
        component: () => import('../page/product/list'),
        meta: {
          title: '商品列表'
        }
      },
      {
        name: 'cart',
        component: () => import('../page/cart/index'),
        meta: {
          title: '购物车'
        }
      },
      {
        path: '/order',
        component: () => import('../page/shipping/order'),
        meta: {
          title: '确认订单'
        }
      },
      {
        name: 'category',
        component: () => import('../page/category/index'),
        meta: {
          title: '分类'
        }
      },
    ];
    
    // add route path
    routes.forEach(route => {
      route.path = route.path || '/' + (route.name || '');
    });
    
    const router = new Router({ routes });
    // 这里对title的处理也挺有意思的
    router.beforeEach((to, from, next) => {
      const title = to.meta && to.meta.title;
      if (title) {
        document.title = title;
      }
      next();
    });
    
    export {
      router
    };
    

    我们再看srcconfigcomponents.js的components.js
    代码如下

    
    
    import headerNav from '../components/header/nav';
    
    import navigate from '../components/footer/navigate.vue'
    import productcard from '../components/common/productcard.vue'
    import {
      Tag,
      Col,
      Icon,
      Cell,
      CellGroup,
      Swipe,
      Toast,
      SwipeItem,
      GoodsAction,
      GoodsActionBigBtn,
      GoodsActionMiniBtn,
      Actionsheet,
      Sku,
      Card,Button,SwipeCell,Dialog,Tab, Tabs,Row,Checkbox, CheckboxGroup, SubmitBar,NavBar,Tabbar, TabbarItem,Panel,List,Step, Steps,Field ,
      Badge, BadgeGroup,Popup,Stepper,RadioGroup, Radio,Picker,Uploader,Info
    } from 'vant';
    
    const components=[
        Tag,
        Col,
        Icon,
        Cell,
        CellGroup,
        Swipe,
        SwipeItem,
        GoodsAction,
        GoodsActionBigBtn,
        GoodsActionMiniBtn,
        Actionsheet,
        Sku,
        Card,
        Button,
        SwipeCell ,
        Dialog ,
        headerNav, 
        Tab, Tabs,Toast,Row,Checkbox, CheckboxGroup, SubmitBar,NavBar ,Tabbar, TabbarItem,navigate,Panel,List ,Step, Steps,Field ,
        Badge, BadgeGroup,Popup,productcard,Stepper,RadioGroup, Radio,Picker,Uploader,Info
    ]
    
    
    export default (Vue)=>{
        components.forEach(Component => {
            Vue.component(Component.name, Component)
        });
    }
    

    上面的对组件的处理挺有意思的
    看一下移动端这边的适配

    //rem.js
    //srcconfig
    em.js
    (function(d, w) {
        const doc = d.documentElement;
        function rem() {
          const width = Math.min(doc.getBoundingClientRect().width, 768);
          doc.style.fontSize = width / 7.5 + 'px';
        }
        rem();
        w.addEventListener('resize', rem);
      })(document, window);
      
    

    接下来我们来根据router.js,结合路由来看我们的页面内容

    //srcpageindex.vue
    <template>
        <div>
            <page/>
            <navigate />
        </div>
    </template>
    
    <script>
    import navigate from '../components/footer/navigate.vue'
    import page from './page/page.vue'
    
    export default {
        components:{
            page,
            navigate
        }
    }
    </script>
    <style>
    
    </style>
    
    
    

    引入了page.vue和navigate.vue

    //navigate.vue
    <template>
        <div style="height:50px;">
        <van-tabbar >
            <van-tabbar-item icon="wap-home" to="/home">首页</van-tabbar-item>
            <van-tabbar-item icon="wap-nav" to="/category" >分类</van-tabbar-item>
            <van-tabbar-item icon="cart" to="/cart" >购物车</van-tabbar-item>
            <van-tabbar-item icon="contact" to="/user/index">我的</van-tabbar-item>
        </van-tabbar>
        </div>
    </template>
    
    <script>
    import { Tabbar, TabbarItem } from "vant";
    export default {
        name:'navigate',
        components:{
            [Tabbar.name]: Tabbar,
            [TabbarItem.name]: TabbarItem,
        }
    }
    </script>
    
    
    //page.vue
    <template>
    <div :style="'background-color:'+((page.BackgroundColor==undefined||page.BackgroundColor=='')?'#fff':page.BackgroundColor)">
        <div :style="'height:'+topheight+'px'" ></div>
        <div v-for="(item,index) in page.Sections" :key="index">
            <imageAd v-if="item.Code=='ImageAd'" :data="item.ParameterDictionary"></imageAd>
            
            <imageText v-if="item.Code=='ImageText'" :data="item.ParameterDictionary"></imageText>
    
            <pageLine v-if="item.Code=='Line'"  :data="item.ParameterDictionary" ></pageLine>
    
            <whitespace v-if="item.Code=='Line'" :data="item.ParameterDictionary"  />
    
            <pageText v-if="item.Code=='Text'" :data="item.ParameterDictionary" ></pageText>
    
            <notice v-if="item.Code=='Notice'" :data="item.ParameterDictionary" ></notice>
    
            <search v-if="item.Code=='Search'" :data="item.ParameterDictionary" v-on:settopheight="settopheight($event)" ></search>
    
            <pageTitle v-if="item.Code=='Title'" :data="item.ParameterDictionary" ></pageTitle>
    
            <cube v-if="item.Code=='Cube'" :data="item.ParameterDictionary" ></cube>
    
            <product v-if="item.Code=='Product'" :data="item" ></product>
        </div>
    
    </div>
    </template>
    <script>
    import "../../assets/style/index.css";
    import whitespace from "../../components/page/whitespace.vue";
    import pageLine from "../../components/page/line.vue";
    import pageText from "../../components/page/text.vue";
    import notice from "../../components/page/notice.vue";
    import search from "../../components/page/search.vue";
    import pageTitle from "../../components/page/title.vue";
    import cube from "../../components/page/cube.vue";
    import imageAd from "../../components/page/imageAd.vue";
    import imageText from "../../components/page/imageText.vue";
    import product from "../../components/page/product.vue";
    import { GetPage } from "../../api/page.js";
    
    export default {
        name:"page",
        components:{
            whitespace,
            pageLine,
            pageText,
            notice,
            search,
            pageTitle,
            cube,
            [imageAd.name]:imageAd,
            imageText,
            product
        },
        data:function(){
            return{
                topheight:0,
                page:{},
            }
        },
        created:function(){
            GetPage().then(response=>{
                this.page=response;
            });
        },
        methods:{
            settopheight:function(value){
                this.topheight=value;
            }
        }
    }
    </script>
    

    上面的page页面实际上是由很多组件构成的,我们可以一个一个去分析组件

    //srccomponentspagewhitespace.vue
    <template>
        <div :style="style"></div>
    </template>
    
    <script>
    export default {
        name: 'whitespace',
        props: {
            data: Object,
        },
        computed: {
            style() {
                return {
                    height: (this.data.height==undefined?'30':this.data.height)+"px",
                };
            }
        }
    };
    </script>
    
    
    //srccomponentspageline.vue
    <template>
        <div :style="divstyle" ><div :style="linestyle"></div></div>
    </template>
    
    <script>
    export default {
        name: 'page-line',
        props: {
            data: Object,
        },
        computed:{
            divstyle(){
                return{
                    height:"30px",
                    position:'relative',
                    margin:'0px '+this.data.margintype+'px'
                };
            },
            linestyle(){
                return{
                    position:'absolute',
                    top:'14px',
                    '100%',
                    borderTop:'1px '+(this.data.type==undefined?'solid':this.data.type)+" "+(this.data.color==undefined?'#000':this.data.color),
                };
            }
        }
    };
    </script>
    
    
    //srccomponentspage	ext.vue
    <template>
        <div :style="style">{{data.value}}</div>
    </template>
    
    <script>
    export default {
        name:'page-text',
        props:{
            data:Object
        },
        computed:{
            style(){
                return{
                    position:'relative',
                    padding: '10px',
                    fontSize:(this.data.fontsize==undefined?'10':this.data.fontsize)+'px',
                    color:(this.data.color==undefined?'#000':this.data.color),
                    background:this.data.backgroundcolor,
                    textAlign:this.data.textalign,
                }
            }
        }
    }
    </script>
    
    
    //srccomponentspage
    otice.vue
    <template>
        <NoticeBar
        :text="data.value"
        :background="data.background"
        :color="data.color"
        />
    </template>
    
    <script>
    import { NoticeBar } from "vant";
    
    export default {
        name:'notice',
        components:{
            NoticeBar
        },
        props:{
            data:Object
        },
        computed:{
    
        }
    }
    </script>
    
    <style>
    
    </style>
    
    
    //srccomponentspagecube.vue
    <template>
    <div class="cap-cube" style="font-size:100%;100%;">
        <div v-for="(item,index) in data.images" :key="index" class="cap-cube__item" :style="''+item.imgwidth+'rem;'+item.style">
            <a :href="item.link">
                <img :src="item.src+'?w=375'" :style="''+item.imgwidth+'rem;'" />
            </a>
        </div>
        <div style="clear:both;"></div>
    </div>
    </template>
    
    <script>
    export default {
      name: "cube",
      props: {
        data: Object
      },
      created: function() {
        var gap = this.data.imagegap;
        var margin = gap / 2;
        var width = 375;
        var max = 0;
        switch (this.data.type) {
          case "1":
            max = 2;
            width = (width - margin * 2) / 2;
            break;
          case "2":
            max = 3;
            width = (width - margin * 4) / 3;
            break;
          case "3":
            max = 4;
            width = (width - margin * 6) / 4;
            break;
          case "4":
            max = 4;
            width = (width - margin * 2) / 2;
            break;
          case "5":
            max = 3;
            width = (width - margin * 2) / 2;
            break;
          case "6":
            max = 3;
            width = (width - margin * 2) / 2;
            break;
          case "7":
            max = 4;
            width = (width - margin * 2) / 2;
            break;
        }
        margin = margin / 50;
        width = width / 50;
        var imagelist = [];
    
        for (var i = 0; i < max; i++) {
          var imgwidth = width;
          var item = this.data.imagelist[i];
          var style = "";
          switch (this.data.type) {
            case "1":
              {
                if (i == 0) {
                  style = "margin-right:" + margin + "rem;";
                } else {
                  style = "margin-left:" + margin + "rem;";
                }
              }
              break;
            case "2":
              {
                if (i == 0) {
                  style = "margin-right:" + margin + "rem;";
                } else if (i == 1) {
                  style = "margin:0 " + margin + "rem;";
                } else {
                  style = "margin-left:" + margin + "rem;";
                }
              }
              break;
            case "3":
              {
                if (i == 0) {
                  style = "margin-right:" + margin + "rem;";
                } else if (i == 1 || i == 2) {
                  style = "margin:0 " + margin + "rem;";
                } else {
                  style = "margin-left:" + margin + "rem;";
                }
              }
              break;
            case "4":
              {
                if (i == 0) {
                  style =
                    "margin-right:" +
                    margin +
                    "rem;margin-bottom:" +
                    margin +
                    "rem;";
                } else if (i == 1) {
                  style =
                    "margin-left:" +
                    margin +
                    "rem;margin-bottom:" +
                    margin +
                    "rem;";
                } else if (i == 2) {
                  style =
                    "margin-right:" + margin + "rem;margin-top:" + margin + "rem;";
                } else {
                  style =
                    "margin-left:" + margin + "rem;margin-top:" + margin + "rem;";
                }
              }
              break;
            case "5":
              {
                if (i == 0) {
                  style = "margin-right:" + margin + "rem;";
                } else if (i == 1) {
                  style =
                    "margin-left:" +
                    margin +
                    "rem;margin-bottom:" +
                    margin +
                    "rem;";
                } else {
                  style =
                    "margin-left:" + margin + "rem;margin-top:" + margin + "rem;";
                }
              }
              break;
            case "6":
              {
                if (i == 0) {
                  imgwidth = width * 2;
                  style = "margin-bottom:" + margin + "rem;";
                } else if (i == 1) {
                  style =
                    "margin-right:" + margin + "rem;margin-top:" + margin + "rem;";
                } else {
                  style =
                    "margin-left:" + margin + "rem;margin-top:" + margin + "rem;";
                }
              }
              break;
            case "7":
              {
                if (i == 0) {
                  style = "margin-right:" + margin + "rem;";
                } else if (i == 1) {
                  style =
                    "margin-right:" + margin + "rem;margin-top:" + margin + "rem;";
                } else if (i == 2) {
                  imgwidth = width / 2 - margin;
                  style =
                    "margin-left:" +
                    margin +
                    "rem;margin-top:" +
                    margin +
                    "rem;margin-right:" +
                    margin +
                    "rem";
                } else {
                  imgwidth = width / 2 - margin;
                  style =
                    "margin-left:" + margin + "rem;margin-top:" + margin + "rem;";
                }
              }
              break;
          }
          item.style = style;
          item.imgwidth = imgwidth;
          imagelist.push(item);
        }
        this.data.images = imagelist;
      },
      computed: {}
    };
    </script>
    
    
    //srccomponentspageimageAd.vue
    <template>
    <div>
        <van-swipe :autoplay="3000" v-if="data.type=='1'" :style="'height:'+height+'px'"  >
            <van-swipe-item v-for="(image,index) in data.imagelist" :key="index" >
                <a :href="image.url">
                    <img  v-lazy="image.src+''" style=" 100%;" />
                </a>
            </van-swipe-item>
        </van-swipe>
         <ul  v-if="data.type=='2'">
            <li v-for="(image,index) in data.imagelist" :key="index" class="cap-image-ad__content" :style="'margin:'+data.imagegap+'px 0px;'">
                <div class="image-wrapper">
                    <a :href="image.url">
                        <img alt="" class="cap-image-ad__image" v-lazy="image.src+''" />
                    </a>
                </div>
            </li>
        </ul>
    
        <div v-if="data.type=='3'||data.type=='4'||data.type=='5'" class='cap-image-ad__image-nav' style='overflow-x:scroll;' >
            <div v-for="(item,index) in data.imagelist" :key="index" class="image-wrapper" :style="''+(data.type=='3'?'80':(data.type=='4'?'40':'20'))+'%;margin-right:'+data.imagegap+'px;'">
                <a :href="item.link" class="cap-image-ad__link cap-image-ad__link--image-nav" >
                    <div class="cap-image-ad__image">
                        <img :src="item.src+'?w=640'" style=" 100%; " />
                    </div>
                </a>
            </div>
        </div>
    </div>
    </template>
    
    <script>
    
    export default {
        name:'imageAd',
        components:{
        },
        props:{
            data:Object
        },
        data(){
            return{
                height:0
            }
        },
        created(){
            if(this.data.imagelist.length==0||this.data.type!='1'){
                return;
            }
            var that=this;
            var image =this.data.imagelist[0];
            let img = new Image()
            img.src = image.src;
            var width= window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
            img.onload = function () {
                that.height= Math.ceil(img.height/img.width * width);
            }
        }
    }
    </script>
    
    <style>
    
    </style>
    
    //srccomponentspageimageText.vue
    
    <template>
        <div :class='(data.type == "1" ? "cap-image-ad__image-nav" : "cap-image-ad__slide cap-image-ad__text-nav")' :style='"overflow-x:"+(data.showtype == "1" ? "hidden" : "scroll")+"; background-color:"+data.backgroundcolor' >
            <div v-if="data.type == '1'" v-for="(item,index)  in data.imagelist" :key="index" class="image-wrapper" :style="''+ data.width+'%; margin-right: 0px;'">
                <a :href="item.link" class="cap-image-ad__link cap-image-ad__link--image-nav" :style="'color:'+data.color">
                    <div class="cap-image-ad__image">
                        <img v-lazy="item.src+'?w=320'" style=" 100%; " />
                    </div>
                    <h3 v-if="item.title!=''" class="cap-image-ad__nav-title">{{item.title}}</h3>
                </a>
            </div>
            <a v-if="data.type=='2'" v-for="(item,index) in data.imagelist" :key="index" :href="item.link" class="text-nav-wrapper" :style="''+data.width+'%; color: '+data.color+'; background-color: '+data.backgroundcolor"><h3 class="cap-image-ad__nav-title">{{item.title}}</h3></a>
        </div>
    </template>
    
    <script>
    export default {
        name:'imageText',
        props:{
            data:Object
        },
        created:function(){
            var width = 0;
            if (this.data.showtype == "1") {
                width = 100 / this.data.imagelist.length;
            }
            else {
                width = (100 * 0.95) / (this.data.shownumber - 1);
            }
            this.data.width=width;
        }
    }
    </script>
    
    <style>
    
    </style>
    
    //srccomponentspageproduct.vue
    <template>
    <div>
        <ul :class="'cap-goods-list__container cap-goods-list__container--'+data.classname+' cap-goods-list__container--'+data.ParameterDictionary.showtype+'   '+(data.ParameterDictionary.type=='6'?'nowrap':'')" >
            <li v-if="productlist.length==0" style="100%;height:150px;border:0px;">
                <div style="100%;height:150px;"></div>
            </li>
            <li v-for="(item,index) in productlist" :key="index" :class="'cap-goods-list__wrapper  '+(data.ParameterDictionary.type=='3'?(index%3==0?'cap-goods-list__wrapper--hybrid-big ':'cap-goods-list__wrapper--hybrid-small '):'')">
                <router-link :class="'cap-goods-list__item cap-goods-list__item--'+data.classname+' '+data.ParameterDictionary.showtype+' '+data.aclass" :to="'/product/'+item.id">
                    <div class="cap-goods-list__photo">
                        <img class="cap-goods-list__img lazy lazyload" v-lazy="item.imageURL+'?w='+((data.ParameterDictionary.type=='1'||data.ParameterDictionary.type=='3')?'750':'375')" />
                    </div>
                    <div :class="'cap-goods-list__info has-title has-price '+(data.ParameterDictionary.showtype == 'card'?'has-btn':'')">
                        <h3 class="title">{{item.title}}</h3>
                        <p class="sale-info">
                            <span class="sale-price">¥ {{item.price}}</span>
                        </p>
                    </div>
                    <div v-if="data.ParameterDictionary.showtype == 'card'" class="cap-goods-list__buy-btn-wrapper cap-goods-list__buy-btn-wrapper--4">
                        <button class="cap-goods-list__buy-btn-4 van-button van-button--default van-button--small">{{data.ParameterDictionary.buttonvalue}}</button>
                    </div>
                </router-link>
            </li>
        </ul>
        <div style="clear:both;"></div>
        </div>
    </template>
    
    <script>
    import {getProduct} from "../../api/page.js";
    
    export default {
        name:'product',
        data () {
           return {
               productlist: []
           }
         },
        props:{
            data:Object
        }, 
        created:function(){
            var id=this.data.PageSectionId;
            var data=this.data;
            var classname = "big";
            var aclass = "";
            switch (data.ParameterDictionary.type) {
                case "1":
                    aclass = "cap-goods-list__item--btn1 cap-goods-list__item--ratio-3-2 cap-goods-list__item--whitespace";
                    break;
                case "2":
                    classname = "small";
                    aclass = "cap-goods-list__item--btn1 cap-goods-list__item--padding";
                    break;
                case "3":
                    classname = "hybrid";
                    aclass = "cap-goods-list__item--big cap-goods-list__item--hybrid-big cap-goods-list__item--btn1 cap-goods-list__item--padding";
                    break;
                case "4":
                    classname = "list";
                    aclass = "cap-goods-list__item--btn4 cap-goods-list__item--padding";
                    break;
                case "5":
                    classname = "three";
                    aclass = "cap-goods-list__item--btn4 cap-goods-list__item--padding";
                    break;
                case "6":
                    classname = "three";
                    break;
            }
            data.classname=classname;
            data.aclass=aclass;
            getProduct(id).then(response => {
                this.productlist=response;
            })
        }
    }
    </script>
    
    <style>
    
    </style>
    
    //srcapipage.js
    import request from "../config/request";
    
    
    export function GetPage() {
        return request({
          url: '/Page/GetPage',
          method: 'get',
        })
      }
    
    export function getProduct(id) {
        return request({
          url: '/Page/Product',
          method: 'get',
          params: { id }
        })
      }
    

    感觉好神奇,上面的那些就处理完毕数据了吗?
    看第二个页面吧

    这个页面就跟首页不一样了,所有的东西是写死的可是也暴露出来了,第一个home页面都没有看到axiox

    //srcpagecategoryindex.vue
    <template>
        <div>
            <van-search
            v-model="value"
            placeholder="请输入搜索关键词"
            show-action
            @search="onSearch"
            >
            <div slot="action" @click="onSearch">搜索</div>
            </van-search>
            <van-badge-group :active-key="activeKey" class="tab" :style="'height:'+fullHeight+'px'">
                <van-badge title="热门推荐" @click="onClick" />
                <van-badge title="手机数码" @click="onClick" />
                <van-badge title="家用电器" @click="onClick" />
                <van-badge title="电脑办公" @click="onClick" />
                <van-badge title="美妆护肤" @click="onClick" />
                <van-badge title="个护清洁" @click="onClick" />
                <van-badge title="汽车用品" @click="onClick" />
                <van-badge title="男装" @click="onClick" />
                <van-badge title="男鞋" @click="onClick" />
                <van-badge title="女装" @click="onClick" />
                <van-badge title="女鞋" @click="onClick" />
                <van-badge title="母婴童装" @click="onClick" />
                <van-badge title="图书音像" @click="onClick" />
                <van-badge title="运动户外" @click="onClick" />
                <van-badge title="食品生鲜" @click="onClick" />
            </van-badge-group>
            <div class="content" :style="''+fullWidth+'px;height:'+(fullHeight-7)+'px'" >
                <img src="https://img11.360buyimg.com/mcoss/jfs/t1/1072/23/3672/95463/5b9a0813E175891fa/e38fc2f7c2ddfec2.jpg" />
                <div class="category-div">
                    <h4>常用分类</h4>
                    <ul >
                        <li>
                          <router-link to="/search?keyword=xxxx">
                            <img src="//img12.360buyimg.com/focus/jfs/t11824/150/2263801190/3392/8e69e1b3/5a167b8cNdcf71ae5.jpg">
                            <span>蓝牙耳机</span>
                          </router-link>
                        </li>
                        <li>
                            <a >
                                <img src="//img20.360buyimg.com/focus/jfs/t13759/194/897734755/2493/1305d4c4/5a1692ebN8ae73077.jpg">
                                <span>iPhone</span>
                            </a>
                        </li>
                        <div style="clear:both"></div>
                    </ul>
                </div>
                <div class="category-div">
                    <h4>热门分类</h4>
                    <ul>
                        <li><a ><img src="//img11.360buyimg.com/focus/s140x140_jfs/t21388/146/237407622/26923/221da1b3/5b054fedN2ba90518.jpg"><span>手机</span></a></li>
                        <li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t20128/208/216721929/9242/472993da/5b05522dNa2aae1bb.png"><span>耳机</span></a></li>
                        <li><a ><img src="//img30.360buyimg.com/focus/s140x140_jfs/t21655/83/2186874549/15932/c273d29b/5b48802aN13fe73de.png"><span>剃须刀</span></a></li>
                        <li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t21715/149/246679831/16257/ddbf2036/5b0565a7N8dbc0017.png"><span>路由器</span></a></li>
                        <li><a ><img src="//img14.360buyimg.com/focus/s140x140_jfs/t1/4478/16/633/36008/5b923503E39b9dfa9/13b099f187576d8c.png"><span>月饼</span></a></li>
                        <li><a ><img src="//img10.360buyimg.com/focus/s140x140_jfs/t1/1410/32/643/38009/5b9236b2Eb02fbf02/1e7de6987578dcdd.jpg" ><span>牛奶</span></a></li>
                        <li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t1/4674/14/665/25245/5b9236bbE088d5efb/6c7c2f9857736c65.jpg"><span>男士内裤</span></a></li>
                        <li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t1/1710/26/666/26147/5b9236c3E5fd1cd42/86c6bca8f4fe1efa.png"><span>小米8</span></a></li>
                        <li><a ><img src="//img11.360buyimg.com/focus/s140x140_jfs/t1/3653/6/655/42593/5b9236caEfef6235b/9e118f12705f52bb.png"><span>大闸蟹</span></a></li>
                        <li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t23881/349/2204372862/9923/4c62864a/5b7693eeNf6883734.png"><span>三只松鼠</span></a></li>
                        <li><a ><img src="//img20.360buyimg.com/focus/s140x140_jfs/t24253/294/2182777138/4059/429945c9/5b76990bNde226fbc.png"><span>充电宝</span></a></li>
                        <li><a ><img src="//img30.360buyimg.com/focus/s140x140_jfs/t22051/318/235303191/9297/c5ea2761/5b055000N410a7553.png"><span>空调</span></a></li>
                        <li><a ><img src="//img10.360buyimg.com/focus/s140x140_jfs/t19960/243/653029866/38879/91bb398b/5b055555N9245f8aa.jpg"><span>电饭煲</span></a></li>
                        <li><a ><img src="//img12.360buyimg.com/focus/s140x140_jfs/t1/345/33/944/5582/5b9236d2E62d8da2e/99f72d51b8f195ed.jpg"><span>电话手表</span></a></li>
                        <li><a ><img src="//img30.360buyimg.com/focus/s140x140_jfs/t1/1446/14/631/8500/5b9237e5E0d1f9e16/b1a627b92323b5ed.png"><span>华为</span></a></li>
                        <div style="clear:both">
                        </div>
                    </ul>   
                </div>
            </div>
            <navigate />
        </div>
    </template>
    
    <script>
    import { Search } from "vant";
    
    export default {
      name: "userindex",
      components: {
        [Search.name]: Search
      },
      data() {
        return {
          value: "",
          activeKey: 0,
          fullHeight: document.documentElement.clientHeight - 93,
          fullWidth: document.documentElement.clientWidth - 99
        };
      },
      methods: {
        onSearch() {
          console.log(this.value);
        },
        onClick(key) {
          this.activeKey = key;
        }
      }
    };
    </script>
    
    <style lang="less">
    .tab {
      float: left;
      overflow-y: scroll;
      -webkit-overflow-scrolling: touch;
      min-height: 100%;
      .van-badge {
        padding: 15px 12px 15px 9px;
      }
      .van-badge:not(:last-child)::after {
        height: 199%;
      }
    }
    .content {
      float: left;
      overflow-y: scroll;
      -webkit-overflow-scrolling: touch;
      min-height: 100%;
      margin: 7px 7px 0;
      font-size: 12px;
      img {
         100%;
      }
      .category-div {
        margin: 19px 0px 0;
        h4 {
          font-size: 14px;
          color: #333;
        }
        ul{
            margin-top: 10px;
        }
        li {
           32.8%;
          float: left;
          text-align: center;
          img {
             60px;
            height: 60px;
          }
          span{
              font-size: 12px;
        height: 36px;
        color: #686868;
         100%;
        overflow: hidden;
        text-overflow: ellipsis;
        display: box;
        display: -webkit-box;
        display: -moz-box;
        display: -ms-box;
        display: -o-box;
        line-clamp: 2;
        -webkit-line-clamp: 2;
        -moz-line-clamp: 2;
        -ms-line-clamp: 2;
        -o-line-clamp: 2;
        box-orient: vertical;
        -webkit-box-orient: vertical;
        -ms-box-orient: vertical;
        -o-box-orient: vertical;
        word-break: break-all;
        box-align: center;
        -webkit-box-align: center;
        -moz-box-align: center;
        -ms-box-align: center;
        -o-box-align: center;
        box-pack: center;
        -webkit-box-pack: center;
        -moz-box-pack: center;
        -ms-box-pack: center;
        -o-box-pack: center;
        z-index: 2;
        position: relative;
          }
        }
      }
    }
    </style>
    

    这个里面就是很普通的布局方式,静态文件,如果要点击进去下一个路由,应该在点击的时候,进行一次数据的请求
    看一下对cart的处理

    cart页面也是前端写死数据进行渲染的,我们来看看代码

    //srcpagecartindex.vue
    <template>
      <div class="card">
        <headerNav title="购物车"/>
           <van-cell  value="编辑商品" class="head">
            <template slot="title">
              <van-checkbox v-model="checkedAll" >全选</van-checkbox>
            </template>
          </van-cell>
            
        <van-checkbox-group class="card-goods" v-model="checkedGoods">
          
          <div class="promotion-group">
            <div  v-for="(item,index) in goods"
              :key="index" class="card-goods__item"> 
              <van-checkbox :name="item.id"></van-checkbox>
    
              <product-card :product='item' :iscard='true' >
                <template slot>
                  <van-cell value="修改" >
                      <template slot="title">
                          <van-tag type="danger">促销</van-tag>
                          <span class="van-cell-text" >满60元减5元</span>
                      </template>
                  </van-cell>
                </template>
              </product-card>
            </div>
            </div>
        
          <div class="promotion-group">
            
           <van-cell  is-link class="head">
            <template slot="title">
              <van-checkbox v-model="checkedAll" >京东自营</van-checkbox>
            </template>
          </van-cell>
          
          
          <div  v-for="(item,index) in goods"
            :key="index+10" class="card-goods__item"> 
            <van-checkbox :name="item.id"></van-checkbox>
          
            <product-card :product='item' :iscard='true' >
              <template slot>
                <van-cell value="修改" >
                    <template slot="title">
                        <van-tag type="danger">促销</van-tag>
                        <span class="van-cell-text" >满60元减5元</span>
                    </template>
                </van-cell>
              </template>
            </product-card>
          </div>
          <van-cell value="去凑单" is-link class="promotion">
            <template slot="title">
              <p><van-tag type="danger">满减</van-tag>购满60元,可减5元</p>
            </template>
          </van-cell>
          <div  v-for="(item,index) in goods"
            :key="index+20" class="card-goods__item"> 
            <van-checkbox :name="item.id"></van-checkbox>
          
            <product-card :product='item' :iscard='true' >
              <template slot>
                <van-cell value="修改" >
                    <template slot="title">
                        <van-tag type="danger">促销</van-tag>
                        <span class="van-cell-text" >满60元减5元</span>
                    </template>
                </van-cell>
              </template>
            </product-card>
          </div>
            </div>
        </van-checkbox-group>
        
        <div style="height:50px;"></div>
        <van-submit-bar
          :price="totalPrice"
          :disabled="!checkedGoods.length"
          :button-text="submitBarText"
          @submit="onSubmit"
        >
        <template slot>
          <van-checkbox v-model="checkedAll" >全选</van-checkbox>
        </template>
        </van-submit-bar>
      </div>
    </template>
    
    <script>
    
    export default {
      components: {
      },
      data() {
        return {
          checkedAll:true,
          checkedGoods: ['1', '2', '3'],
          goods: [{
            id: '1',
            title: '星巴克(Starbucks)星冰乐 轻盈香草味 咖啡饮料 281ml*6瓶礼盒装低脂减糖',
            desc: '3.18kg/件',
            price: '200.00',
            quantity: 1,
            imageURL: 'https://img.yzcdn.cn/public_files/2017/10/24/2f9a36046449dafb8608e99990b3c205.jpeg',
            imageTag:'比加入时降5元',
          }, {
            id: '2',
            title: '陕西蜜梨',
            desc: '约600g',
            price: '690.00',
            quantity: 1,
            imageURL: 'https://img.yzcdn.cn/public_files/2017/10/24/f6aabd6ac5521195e01e8e89ee9fc63f.jpeg',
              gift: [
                {
                  title: "星巴克(Starbucks)星冰乐小熊吊饰星巴克(Starbucks)星冰乐小熊吊饰",
                  quantity: 2
                },
                {
                  title: "星巴克(Starbucks)星冰乐小熊吊饰星巴克(Starbucks)星冰乐小熊吊饰",
                  quantity: 1
                }
              ]
          }, {
            id: '3',
            title: '美国伽力果',
            desc: '约680g/3个',
            price: '2680.00',
            quantity: 1,
            imageURL: 'https://img.yzcdn.cn/public_files/2017/10/24/320454216bbe9e25c7651e1fa51b31fd.jpeg'
          }]
        };
      },
      computed: {
        submitBarText() {
          const count = this.checkedGoods.length;
          return '结算' + (count ? `(${count})` : '');
        },
        totalPrice() {
          return this.goods.reduce((total, item) => total + (this.checkedGoods.indexOf(item.id) !== -1 ? parseFloat(item.price): 0), 0);
        },
      },
      methods: {
        onSubmit() {
          
          this.$router.push('/order')
        }
      }
    };
    </script>
    
    <style lang="less">
    .card-goods {
      font-size: 12px;
      &__item {
        position: relative;
        .van-checkbox{
           20px;
          height: 20px;
          top: 40px;
          left: 5px;
          z-index: 1;
          position: absolute;
        }
        .additional{
           100%;
            padding-left: 15px;
        box-sizing: border-box;
        }
      }
    }
    .head{
          padding-left: 5px;
      border-bottom: 1px solid #eee;
    }
    .card{
      background: #f7f7f7;
      .van-submit-bar__bar {
          border-top: 1px solid #f7f7f7;
          .van-checkbox{
            padding-left: 5px;
          }
      }
      .promotion{
          .van-tag {
              line-height: 12px;
              margin-right: 5px;
          }
          .van-cell__title{
    
          flex: 4;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
          }
        }
        .promotion-group{
          margin-top: 10px;
          box-shadow: 5px 5px 5px #e5e5e5;
        }
    }
    
        
    </style>
    

    接下来看order页面

    <template>
      <div class="order">
         <headerNav title="确认订单"/>
         <van-cell
          center
          :border="false"
          class="contact-card"
          is-link
          to="/user/address?id=2"
        >
          <template v-if="type === 'add'">
            <strong>选择地址</strong>
          </template>
          <template v-else>
            <strong>张三 138****6520</strong>
            <div>广东省深圳市南山区科技园 </div>
          </template>
        </van-cell>
        <div style="height:15px;"></div>
        <div class="card" v-for="(product,i) in products" :key="i">
          <product-card :product='product' />
        </div>
        <div style="height:15px;"></div>
        <van-cell-group>
          <van-field
            label="留言"
            type="textarea"
            placeholder="请输入留言"
            rows="1"
            autosize
          />
        </van-cell-group>
        <div style="height:15px;"></div>
        <van-cell-group class="total">
            <van-cell title="优惠券" is-link value="抵扣¥5.00" />
        </van-cell-group>
        
        <div style="height:15px;"></div>
        <van-cell-group class="total">
            <van-cell title="商品总额" value="9.99" />
            <van-cell title="运费" value="+ 0.00" />
            <van-cell title="折扣" value="- 5.00" />
            <van-cell title="实付金额" value="4.99" style="font-weight: 700;" />
        </van-cell-group>
    
        <div style="height:50px;"></div>
        <van-submit-bar
          :price="3050"
          button-text="提交订单"
          label='实付金额:'
          @submit="onSubmit"
        />
    
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          type: "add1",
          products: [
            {
              imageURL:
                "https://img10.360buyimg.com/mobilecms/s88x88_jfs/t17572/12/840082281/351445/e1828c58/5aab8dbbNedb77d88.jpg",
              title: "良品铺子 肉肉聚汇猪肉脯 猪蹄卤 辣味小吃520g",
              desc: "0.670kg/件,肉肉聚汇520g",
              price: "59.80",
              quantity: 2
            },
            {
              imageURL:
                "https://img10.360buyimg.com/mobilecms/s88x88_jfs/t22720/128/1410375403/319576/8dbd859f/5b5e69b3Nf4f0e9e7.jpg",
              title: "元朗 鸡蛋卷 饼干糕点 中秋礼盒 广东特产680g",
              desc: "1.320kg/件",
              price: "65.80",
              quantity: 1,
              gift: [
                {
                  title: "星巴克(Starbucks)星冰乐小熊吊饰星巴克(Starbucks)星冰乐小熊吊饰",
                  quantity: 2
                },
                {
                  title: "星巴克(Starbucks)星冰乐小熊吊饰星巴克(Starbucks)星冰乐小熊吊饰",
                  quantity: 1
                }
              ]
            },
            {
              imageURL:
                "https://img10.360buyimg.com/mobilecms/s88x88_jfs/t17572/12/840082281/351445/e1828c58/5aab8dbbNedb77d88.jpg",
              title: "良品铺子 肉肉聚汇猪肉脯 猪蹄卤 辣味小吃520g",
              desc: "0.670kg/件,肉肉聚汇520g",
              price: "59.80",
              quantity: 2
            },
          ]
        };
      },
      methods: {
        onSubmit() {
          this.$toast("点击按钮");
        },
      },
      activated(){
        //根据key名获取传递回来的参数,data就是map
        this.$on('selectAddress', function(data){
            //赋值给首页的附近医院数据模型
            console.log(1);
        }.bind(this));
    },
    };
    </script>
    
    <style lang="less">
    .order {
      font-size: 14px;
      background: #f7f7f7;
      .contact-card::before {
        content: "";
        left: 0;
        right: 0;
        bottom: 0;
        height: 2px;
        position: absolute;
        background: -webkit-repeating-linear-gradient(
          135deg,
          #ff6c6c 0,
          #ff6c6c 20%,
          transparent 0,
          transparent 25%,
          #3283fa 0,
          #3283fa 45%,
          transparent 0,
          transparent 50%
        );
        background: repeating-linear-gradient(
          -45deg,
          #ff6c6c 0,
          #ff6c6c 20%,
          transparent 0,
          transparent 25%,
          #3283fa 0,
          #3283fa 45%,
          transparent 0,
          transparent 50%
        );
        background-size: 80px;
      }
      .total {
        .van-cell__value {
          color: red;
        }
      }
      
      .van-submit-bar__bar {
        border-top: 1px solid #f7f7f7;
      }
      .additional {
        .van-cell {
          padding: 0 15px;
          font-size: 12px;
        }
        .van-cell__title {
          flex: 11;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }
        .van-tag {
          line-height: 12px;
          margin-right: 5px;
        }
        
        .price {
          color: #e93b3d;
          font-size: 10px;
          span {
            font-size: 16px;
          }
        }
      }
    }
    </style>
    

    //srcpageuseraddresslist.vue
    <template>
    <div>
    
        <headerNav title="我的地址"/>
        <van-address-list
      v-model="chosenAddressId"
      :class="isSelect?'':'hideselect'"
      :list="list"
      @add="onAdd"
      @edit="onEdit"
      @select="onSelect"
    />
    </div>
    </template>
    
    <script>
    
    import { GetAddressList } from "../../../api/user.js";
    import { AddressList } from 'vant';
    export default {
        components:{
            [AddressList.name]:AddressList,
        },
        data() {
            return {
            chosenAddressId: '1',
            isSelect:false,
            list: [],
            }
        },
    
        methods: {
            onAdd() {
                this.$router.push('/user/address/edit')
            },
    
            onEdit(item, index) {
                this.$router.push('/user/address/edit?id='+item.id);
            },
            onSelect(item,index){
                if(!this.isSelect){
                    return;
                }
                this.$emit('selectAddress',item);
                this.$router.go(-1);
            }
        },
        created:function(){
            this.chosenAddressId=this.$route.query.id;
            this.isSelect=this.$route.query.id>0;
            GetAddressList().then(response=>{
                this.list=response;
            })
        }
    
    }
    </script>
    
    <style lang="less">
    .hideselect{
        .van-radio__input{
            display: none;
        }
    }
    </style>
    

    //srcpageuseraddressedit.vue
    <template>
        <div>
         <headerNav title="修改地址"/>
          <van-address-edit
          :area-list="areaList"
          :showDelete="showDelete"
          show-set-default
          @save="onSave"
          @delete="onDelete"
          :addressInfo="info"
          />
        </div>
    </template>
    
    <script>
    import areaList from '../../../data/area';
    import { GetAddressById,SaveAddress,DelAddress } from "../../../api/user.js";
    
    import { AddressEdit } from 'vant';
    export default {
        components:{
            [AddressEdit.name]:AddressEdit,
        },
        data() {
        return {
          areaList,
          showDelete:false,
          info:{},
        }
      },
    
      methods: {
        onSave(data) {
          SaveAddress(data).then(response=>{
            this.$toast('保存成功');
            this.$router.go(-1);
          })
        },
        onDelete(data) {
          DelAddress(data).then(response=>{
            this.$toast('删除成功');
            this.$router.go(-1);
          })
        },
      },
      created:function(){
        var id=this.$route.query.id;
        if(id>0){
          this.showDelete=true;
          GetAddressById(id).then(response=>{
            console.log(response);
            this.info=response;
          })
        }
      }
    
    }
    </script>
    
    <style>
    .van-picker__toolbar{
      font-size: 16px;
    }
    </style>
    

    //srcpageuserindex.vue
    //点击不同的路由跳转到不同的页面
    <template>
      <div>
        <div class="user-profile">
          <div class="user-profile-avatar">
            <a href="/#/user/info">
              <img :src="data.Avatar" alt="用户头像">
            </a>
          </div>
          <div class="user-profile-username">
            <a href="/#/user/info">
              <span class="m-nick">{{data.UserName}}</span>
            </a>  
          </div>
        </div>
    
        <van-cell-group class="user-group">
          <van-cell title="我的订单" value="查看全部订单" is-link  to="/user/order"/>
          <van-row class="user-links">
            <router-link  to="/user/order/1">
              <van-col span="6">
                <van-icon name="pending-payment">
                  <van-info :info="data.UnPayTotal"  />
                </van-icon>
                <div>待付款</div>
              </van-col>
            </router-link>
            <router-link  to="/user/order/2">
              <van-col span="6">
                <van-icon name="logistics">
                  <van-info :info="data.UnRecieveTotal"   />
                </van-icon>
                <div>待发货</div>
              </van-col>
            </router-link>
            <router-link  to="/user/order/2">
              <van-col span="6">
                <van-icon name="point-gift">
                </van-icon>
                <div>已完成</div>
              </van-col>
            </router-link>
            <router-link  to="/user/aftersale">
              <van-col span="6">
                <van-icon name="after-sale" >
                  <van-info :info="data.AfterSaleTotal"   />
                </van-icon>
                <div>售后</div>
              </van-col>
            </router-link>
          </van-row>
        </van-cell-group>
        
        <van-cell-group class="user-group">
          <van-cell title="我的服务" />
          <van-row class="user-links">
            <router-link  to="/user/coupon">
              <van-col span="6">
                <van-icon name="coupon" />
                <div>我的优惠券</div>
              </van-col>
            </router-link>
            <router-link  to="/user/favorite">
              <van-col span="6">
                <van-icon name="like-o" />
                <div>我的收藏</div>
              </van-col>
            </router-link>
            <router-link  to="/user/address">
              <van-col span="6" >
                <van-icon name="location"/>
                <div>收货地址</div>
              </van-col>
            </router-link>
          </van-row>
        </van-cell-group>
    
        <van-cell-group>
          <van-cell title="切换账号" is-link to="/login" />
        </van-cell-group>
        <navigate />
      </div>
    </template>
    
    <script>
    import { GetUserIndex } from "../../api/user.js";
    
    export default {
      data(){
        return{
          data:{}
        }
      },
      components: {
      },
      created:function(){
          GetUserIndex().then(response=>{
              this.data=response;
          });
      },
    };
    </script>
    
    <style lang="less">
    .user {
      &-profile {
            text-align: center;
            display: block;
         100%;
        height: 141px;
        background-color: #f1f5fa;
        background-repeat: no-repeat;
        background-size: 100% 100%;
        img{
               100%;
        }
        &-avatar{
              padding-top: 23px;
        padding-bottom: 5px;
    
          img{
    
           65px;
          height: 65px;
          border-radius: 50%;
          overflow: hidden;
          }
        }
        &-username{
          font-size: 20px;
        }
      }
      &-group {
        margin-bottom: .3rem;
        
        .van-cell__value{
          color: #999;
          font-size: 12px;
        }
      }
      &-links {
        padding: 15px 0;
        font-size: 12px;
        text-align: center;
        background-color: #fff;
        .van-icon {
          position: relative;
           24px;
          font-size: 24px;
        }
      }
    }
    </style>
    

    //login.vue
    <template>
        <div>
            <div class="m-logo" style="background:url(//haitao.nos.netease.com/f866dd18-12f0-4bb2-be6d-5cac85cf2627.png) center 73px no-repeat;background-size:161px;    text-align: center;
        padding: 130px 0 0;
        margin: 15px 0;"></div>
        <div style="margin:0 10px;font-size: 14px;">
            <router-link to="/login/phone">
                <van-button size="large" style="font-size: 14px;height: 42px;line-height: 42px;margin-bottom: 15px;">手机号登录</van-button>
            </router-link>
            <router-link to="/login/password">
                <van-button size="large" style="font-size: 14px;height: 42px;line-height: 42px;margin-bottom: 15px;">密码登录</van-button>
            </router-link>
            <router-link to="/login/register">
                <van-button size="large" type="primary" style="font-size: 14px;height: 42px;line-height: 42px;">手机号一键注册</van-button>
            </router-link>
        </div>
        <div class="m-thirdpart">
            <p class="tit"><span class="txt">或用以下方式登录</span></p>
            <div class="lnk">
                <van-icon name="wechat" color="#1AAD16" />
                <van-icon name="alipay" color="#7dcbeb"/>
            </div>
        </div>  
       </div>
    </template>
    
    <script>
    export default {
    
    }
    </script>
    
    <style lang="less">
    .m-thirdpart{
        padding: 40px 20px 50px;
        font-size: 12px;
        .tit{
                position: relative;
         215px;
        margin: 0 auto;
        border-bottom: 1px solid #eee;
        }
        .txt{
            position: absolute;
        left: 50%;
        top: -12px;
        margin: 0 0 0 -57px;
         114px;
        background: #fff;
        text-align: center;
        color: #999;
        font-size: 12px;
        line-height: 26px;
        }
        .lnk{
            position: relative;
        padding: 27px 0 0;
         280px;
        margin: 0 auto;
        text-align: center;
        .van-icon{
                font-size: 31px;
        margin: 0 29px;
        }
        }
    }
    </style>
    
    

    上面的内容也只是一个简单的布局,点击跳转到新的页面

    <template>
        <div>
          <headerNav title="注册"/>
          <div style="background:url(https://haitao.nos.netease.com/f866dd18-12f0-4bb2-be6d-5cac85cf2627.png) center 18px no-repeat;background-size:161px;">
              <div style="padding-top: 70px;">
                <van-cell-group>
                    <van-field
                        placeholder="请输入手机号"
                    />
                     <van-field
                        center
                        clearable
                        placeholder="请输入短信验证码"
                    >
                        <van-button slot="button" size="small" type="primary">发送验证码</van-button>
                    </van-field>
                    <van-field
                        type="password"
                        placeholder="请输入密码"
                    />
                </van-cell-group>
                <div style="margin: 10px;">
                    <van-button size="large" type="primary" style="height: 45px;line-height:45px;">注册</van-button>
                </div>
              </div>
          </div>
        </div>
    </template>
    
    <script>
    export default {
    
    }
    </script>
    
    <style>
    
    </style>
    

    这里面也是静态页面

    <template>
        <div>
          <headerNav title="登录"/>
          <div style="background:url(https://haitao.nos.netease.com/f866dd18-12f0-4bb2-be6d-5cac85cf2627.png) center 18px no-repeat;background-size:161px;">
              <div style="padding-top: 70px;">
                <van-cell-group>
                    <van-field
                        placeholder="请输入手机号"
                    />
                    <van-field
                        type="password"
                        placeholder="请输入密码"
                    />
                </van-cell-group>
                <div style="margin: 10px;">
                    <van-button size="large" type="primary" style="height: 45px;line-height:45px;">登录</van-button>
                </div>
              </div>
          </div>
        </div>
    </template>
    
    <script>
    export default {
    
    }
    </script>
    
    <style>
    
    </style>
    
    

    我觉得这个里面的很大的看点来自作者对组件的封装吧

    <template>
      <div class="goods">
         <headerNav title="商品详情"/>
        <van-swipe class="goods-swipe" :autoplay="3000">
          <van-swipe-item v-for="thumb in goods.thumb" :key="thumb">
            <img :src="thumb" >
          </van-swipe-item>
        </van-swipe>
    
        <van-cell-group>
          <van-cell>
            <span class="goods-price">{{ formatPrice(goods.price) }}</span>
            <span class="goods-market-price">{{ formatPrice(goods.market_price) }}</span>
            <div class="goods-title">{{ goods.title }}</div>
            <div class="goods-subtit">{{goods.subtitle}}</div>
          </van-cell>
          
          <van-cell   @click="onClickShowTag" class="goods-tag" >
            <template slot="title" style="font-size:10px;">
                <img src="https://haitao.nos.netease.com/ba8a4c2fdaa54f82a45261293c116af61419663676663i46n3jlh10028.png"/>
                <span >挪威品牌</span>
                <img src="https://haitao.nosdn2.127.net/13bd59e6e29a4f06b278c586629e690d.png" />
                <span >跨境商品</span>
                <van-icon name="passed" color="red" />
                <span >次日达</span>
                <van-icon name="passed" color="red" />
                <span >自提</span>
                <van-icon name="passed" color="red" />
                <span >闪电退款</span>
                <van-icon name="passed" color="red" />
                <span >前海保税仓</span>
                <van-icon name="passed" color="red" />
                <span >七天无理由退货(拆封后不支持)</span>
            </template>
          </van-cell>   
        </van-cell-group>
    
        <van-cell-group class="goods-cell-group">
          <van-cell is-link  @click="showPromotion" >
            <template slot="title">
                <span style="margin-right: 10px;">领券</span>
                <van-tag type="danger" mark  style="margin-right: 5px;">满180减30</van-tag>
                <van-tag type="danger" mark  style="margin-right: 5px;">满300减100</van-tag>
            </template>
          </van-cell>
          
          <van-cell  is-link @click="showPromotion" >
            <template slot="title">
                <span style="margin-right: 10px;">促销</span>
                <van-tag type="danger" style="margin-right: 5px;">多买优惠</van-tag>
                <van-tag type="danger" style="margin-right: 5px;">满减</van-tag>
                <van-tag type="danger" style="margin-right: 5px;">限购</van-tag>
            </template>
          </van-cell>
        </van-cell-group>
        
        <van-cell-group class="goods-cell-group">
          <van-cell  is-link @click="showSku" >
            <template slot="title">
                <span style="margin-right: 10px;">已选</span>
                <span >10件装</span>
            </template>
          </van-cell>
          
        </van-cell-group>
        
        <div class="goods-info">
            <p class="goods-info-title" >图文详情</p>
            <div v-html="goods.info"></div>
        </div>
        <van-goods-action>
            
          <van-goods-action-mini-btn icon="like-o" @click="sorry">
            收藏
          </van-goods-action-mini-btn>
          <van-goods-action-mini-btn icon="cart" @click="onClickCart">
            购物车
          </van-goods-action-mini-btn>
          <van-goods-action-big-btn @click="showSku">
            加入购物车
          </van-goods-action-big-btn>
          <van-goods-action-big-btn primary @click="showSku">
            立即购买
          </van-goods-action-big-btn>
        </van-goods-action>
        <van-actionsheet v-model="show" title="促销" style="font-size:14px;">
            
                <van-cell  is-link @click="sorry" >
                    <template slot="title">
                        <van-tag type="danger">多买优惠</van-tag>
                        <span> 满2件,总价打9折</span>
                    </template>
                </van-cell>
                <van-cell  is-link @click="sorry" >
                    <template slot="title">
                        <van-tag type="danger">满减</van-tag>
                        <span> 满100元减50元</span>
                    </template>
                </van-cell>
                <van-cell  is-link @click="sorry" >
                    <template slot="title">
                        <van-tag type="danger">限购</van-tag>
                        <span> 购买不超过5件时享受单件价¥8.00,超出数量以结算价为准</span>
                    </template>
                </van-cell>
        </van-actionsheet>
        
        <van-actionsheet v-model="showTag" title="服务说明" style="font-size:14px;">
            
                <van-cell>
                    <template slot="title">
                        <van-icon name="passed" color="red" style="margin-right: 10px;" />
                        <span >次日达</span>
                        <div style="margin-left: 24px;font-size:10px;color:#7d7d7d;">指定时间前下单,次日送达</div>
                    </template>
                </van-cell>
                <van-cell>
                    <template slot="title">
                        <van-icon name="passed" color="red" style="margin-right: 10px;" />
                        <span >自提</span>
                        <div style="margin-left: 24px;font-size:10px;color:#7d7d7d;">我们提供多种自提服务,包括自提点、自助提货柜、移动自提车等服务</div>
                    </template>
                </van-cell>
                <van-cell>
                    <template slot="title">
                        <van-icon name="passed" color="red" style="margin-right: 10px;" />
                        <span >闪电退款</span>
                        <div style="margin-left: 24px;font-size:10px;color:#7d7d7d;">签收7天内退货的,提供先退款后退货服务。</div>
                    </template>
                </van-cell>
                <van-cell>
                    <template slot="title">
                        <van-icon name="passed" color="red" style="margin-right: 10px;" />
                        <span >七天无理由退货(拆封后不支持)</span>
                        <div style="margin-left: 24px;font-size:10px;color:#7d7d7d;">七天无理由退货(拆封后不支持)</div>
                    </template>
                </van-cell>
                <van-cell>
                    <template slot="title">
                        <van-icon name="passed" color="red" style="margin-right: 10px;" />
                        <span >前海保税仓</span>
                        <div style="margin-left: 24px;font-size:10px;color:#7d7d7d;">本商品由前海保税仓发货</div>
                    </template>
                </van-cell>
        </van-actionsheet>
        <van-sku
              v-model="showBase"
              :sku="skuData.sku"
              :goods="skuData.goods_info"
              :goods-id="skuData.goods_id"
              :hide-stock="skuData.sku.hide_stock"
              :quota="skuData.quota"
              :quota-used="skuData.quota_used"
              reset-stepper-on-hide
              reset-selected-sku-on-hide
              disable-stepper-input
              :close-on-click-overlay="closeOnClickOverlay"
              :message-config="messageConfig"
              :custom-sku-validator="customSkuValidator"
              @buy-clicked="onBuyClicked"
              @add-cart="onAddCartClicked"
            />
      </div>
    </template>
    
    <script>
    import skuData from '../../data/sku';
    
    export default {
      components: {
      },
      data() {
        this.skuData = skuData;
        return {
          show:false,
          showTag:false,
          goods: {
            title: '【每日一粒益智又长高】 Lifeline Care 儿童果冻鱼油DHA维生素D3聪明长高 软糖 30粒 2件装',
            subtitle:'【品牌直采】Q弹美味,无腥味果冻鱼油,每粒含足量鱼油DHA,帮助视网膜和大脑健康发育,让你的宝宝明眼又聪明,同时补充400国际单位维生素D3,强壮骨骼和牙齿。特含DPA,让宝宝免疫力更强,没病来扰。',
            price: 2680,
            market_price:9999,
            express: '免运费',
            remain: 19,
            thumb: [
              'https://img.yzcdn.cn/public_files/2017/10/24/e5a5a02309a41f9f5def56684808d9ae.jpeg',
              'https://img.yzcdn.cn/public_files/2017/10/24/1791ba14088f9c2be8c610d0a6cc0f93.jpeg'
            ],
            info:'<p style="text-align:center;"><img src="https://haitao.nosdn2.127.net/ac19460151ee4d95a6657202bcfc653c1531470912089jjjq8ml410763.jpg" ></p><p style="text-align:center;"><img src="https://haitao.nos.netease.com/2a91cfad22404e5498d347672b1440301531470912182jjjq8mnq10764.jpg" ></p><p style="text-align:center;"><img src="https://haitao.nos.netease.com/caddd5a213de4c1cb1347c267e8275731531470912412jjjq8mu410765.jpg" ></p>',
          },
          showBase: false,
          showCustom: false,
          showStepper: false,
          closeOnClickOverlay: true,
          initialSku: {
            s1: '30349',
            s2: '1193'
          },
          customSkuValidator: (component) => {
            return '请选择xxx';
          },
          customStepperConfig: {
            quotaText: '单次限购100件',
            stockFormatter: (stock) => `剩余${stock}间`,
            handleOverLimit: (data) => {
              const { action, limitType, quota } = data;
              if (action === 'minus') {
                this.$toast('至少选择一件商品');
              } else if (action === 'plus') {
                if (limitType === LIMIT_TYPE.QUOTA_LIMIT) {
                  this.$toast(`限购${quota}件`);
                } else {
                  this.$toast('库存不够了~~');
                }
              }
            }
          },
          messageConfig: {
            uploadImg: (file, img) => {
              return new Promise(resolve => {
                setTimeout(() => resolve(img), 1000);
              });
            },
            uploadMaxSize: 3
          }
        };
      },
      methods: {
        formatPrice(data) {
          return '¥' + (data / 100).toFixed(2);
        },
        onClickCart() {
          this.$router.push('/cart');
        },
        sorry() {
          Toast('暂无后续逻辑~');
        },
        showPromotion() {
            this.show=true;
        },
        showSku(){
            this.showBase=true;
        },
        onClickShowTag(){
            this.showTag=true;
        },
        onBuyClicked(data) {
          this.$toast(JSON.stringify(data));
        },
        onAddCartClicked(data) {
          this.$toast(JSON.stringify(data));
        },
    
      }
    };
    </script>
    
    <style lang="less">
    .goods {
      padding-bottom: 50px;
      &-swipe {
        img {
           7.5rem;
          height: 7.5rem;
          display: block;
        }
      }
      &-tag{
          font-size: 12px;
            border-top: 1px solid #e5e5e5;
            span{
          margin-right: 10px;
            }
            i{
                color: red;
                margin-right: 3px;
            }
            img{
               12px;
              margin-right: 3px;
              margin-top: 6px;
          }
      }
      &-title {
            line-height: 18px;
        padding-top: 10px;
        margin-bottom: 6px;
        font-size: 14px;
        color: #333;
        font-weight: 700;
        border-top: 1px solid #f0f0f0;
      }
      &-subtit{
          font-size: 13px;
        color: #333;
        line-height: 21px;
      }
      &-price {
        color: #f44;font-size: 20px;
      }
      &-market-price {    
        text-decoration: line-through;
        margin-left: 8px;
        font-size: 13px;
        color: #999;
      }
      &-cell-group {
        margin: 15px 0;
        .van-cell__value {
          color: #999;
        }
      }
      &-info-title{
          height: 44px;line-height: 44px;text-align: center;font-size: 14px;font-weight: 700;margin: 10px;border-top: 1px solid #e5e5e5;
      }
      &-info p{
              margin: 0;
        padding: 0;
        margin-block-end: 0;
        margin-block-start: 0;
        display: grid;
      }
      &-info img{
           100%;
      }
    }
    </style>
    

    //user/order
    <template>
      <div>
        <div class="user-profile">
          <div class="user-profile-avatar">
            <a href="/#/user/info">
              <img :src="data.Avatar" alt="用户头像">
            </a>
          </div>
          <div class="user-profile-username">
            <a href="/#/user/info">
              <span class="m-nick">{{data.UserName}}</span>
            </a>  
          </div>
        </div>
    
        <van-cell-group class="user-group">
          <van-cell title="我的订单" value="查看全部订单" is-link  to="/user/order"/>
          <van-row class="user-links">
            <router-link  to="/user/order/1">
              <van-col span="6">
                <van-icon name="pending-payment">
                  <van-info :info="data.UnPayTotal"  />
                </van-icon>
                <div>待付款</div>
              </van-col>
            </router-link>
            <router-link  to="/user/order/2">
              <van-col span="6">
                <van-icon name="logistics">
                  <van-info :info="data.UnRecieveTotal"   />
                </van-icon>
                <div>待发货</div>
              </van-col>
            </router-link>
            <router-link  to="/user/order/2">
              <van-col span="6">
                <van-icon name="point-gift">
                </van-icon>
                <div>已完成</div>
              </van-col>
            </router-link>
            <router-link  to="/user/aftersale">
              <van-col span="6">
                <van-icon name="after-sale" >
                  <van-info :info="data.AfterSaleTotal"   />
                </van-icon>
                <div>售后</div>
              </van-col>
            </router-link>
          </van-row>
        </van-cell-group>
        
        <van-cell-group class="user-group">
          <van-cell title="我的服务" />
          <van-row class="user-links">
            <router-link  to="/user/coupon">
              <van-col span="6">
                <van-icon name="coupon" />
                <div>我的优惠券</div>
              </van-col>
            </router-link>
            <router-link  to="/user/favorite">
              <van-col span="6">
                <van-icon name="like-o" />
                <div>我的收藏</div>
              </van-col>
            </router-link>
            <router-link  to="/user/address">
              <van-col span="6" >
                <van-icon name="location"/>
                <div>收货地址</div>
              </van-col>
            </router-link>
          </van-row>
        </van-cell-group>
    
        <van-cell-group>
          <van-cell title="切换账号" is-link to="/login" />
        </van-cell-group>
        <navigate />
      </div>
    </template>
    
    <script>
    import { GetUserIndex } from "../../api/user.js";
    
    export default {
      data(){
        return{
          data:{}
        }
      },
      components: {
      },
      created:function(){
          GetUserIndex().then(response=>{
              this.data=response;
          });
      },
    };
    </script>
    
    <style lang="less">
    .user {
      &-profile {
            text-align: center;
            display: block;
         100%;
        height: 141px;
        background-color: #f1f5fa;
        background-repeat: no-repeat;
        background-size: 100% 100%;
        img{
               100%;
        }
        &-avatar{
              padding-top: 23px;
        padding-bottom: 5px;
    
          img{
    
           65px;
          height: 65px;
          border-radius: 50%;
          overflow: hidden;
          }
        }
        &-username{
          font-size: 20px;
        }
      }
      &-group {
        margin-bottom: .3rem;
        
        .van-cell__value{
          color: #999;
          font-size: 12px;
        }
      }
      &-links {
        padding: 15px 0;
        font-size: 12px;
        text-align: center;
        background-color: #fff;
        .van-icon {
          position: relative;
           24px;
          font-size: 24px;
        }
      }
    }
    </style>
    

    看了下作者封装的config里面的内容,还有两个觉得很有意思

    //srcconfigenv.js
    /**
     * 配置编译环境和线上环境之间的切换
     * 
     * baseUrl: 域名地址
     * routerMode: 路由模式
     * dataSources:数据源
     */
    
    let baseUrl = ''; 
    let routerMode = 'hash';
    let dataSources='local';//local=本地,其他值代表非本地
    
    
    if (process.env.NODE_ENV == 'development') {
    	baseUrl='';
    
    }else if(process.env.NODE_ENV == 'production'){
    	baseUrl = '';
    }
    
    export {
    	baseUrl,
    	routerMode,
    	dataSources,
    }
    
    //srcconfig
    equest.js
    
    import axios from 'axios'
    import {baseUrl,dataSources} from './env';
    import datas from '../data/data';
    
    
    const service =axios.create({
      baseURL: baseUrl, // api 的 base_url
      timeout: 5000, // request timeout
    });
    
    
    const servicef =function(parameter){
      if(dataSources=='local'){
        //定义回调函数和axios一致
        const promist = new Promise(function(resolve,reject){
            var data=datas[parameter.url];
            if(typeof data=='string'){
              data= JSON.parse(data);
            }
            resolve(data);
        })
        return promist;
      }
      return service(parameter);
    }
    
    
      service.interceptors.request.use(
        config => {
          // Do something before request is sent
        //   if (store.getters.token) {
        //     // 让每个请求携带token-- ['X-Token']为自定义key 请根据实际情况自行修改
        //     config.headers['X-Token'] = getToken()
        //   }
    
          return config
        },
        error => {
          // Do something with request error
          console.log(error) // for debug
          Promise.reject(error)
        }
      )
    
      // response interceptor
    service.interceptors.response.use(
        //response => response,
        /**
         * 下面的注释为通过在response里,自定义code来标示请求状态
         * 当code返回如下情况则说明权限有问题,登出并返回到登录页
         * 如想通过 xmlhttprequest 来状态码标识 逻辑可写在下面error中
         * 以下代码均为样例,请结合自生需求加以修改,若不需要,则可删除
         */
        response => {
          const res = response.data;
          if (res.ResultCode !== 200) {
            // Message({
            //   message: res.message,
            //   type: 'error',
            //   duration: 5 * 1000
            // })
            // // 50008:非法的token; 50012:其他客户端登录了;  50014:Token 过期了;
            // if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
            //   // 请自行在引入 MessageBox
            //   // import { Message, MessageBox } from 'element-ui'
            //   MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
            //     confirmButtonText: '重新登录',
            //     cancelButtonText: '取消',
            //     type: 'warning'
            //   }).then(() => {
            //     store.dispatch('FedLogOut').then(() => {
            //       location.reload() // 为了重新实例化vue-router对象 避免bug
            //     })
            //   })
            // }
            console.log(1);
            return Promise.reject('error')
          } else {
            if(typeof response.data.Tag=='string'){
              return JSON.parse(response.data.Tag);
            }else{
              return response.data.Tag;
            }
          }
        },
        error => {
          
          return Promise.reject(error)
        }
      )
      
    
      export default servicef
    

    关于我上面说的数据渲染部分的疑问,我也在向作者提issue,作者大大人很好,很热心回答我
    https://github.com/yrinleung/openshopping-vue/issues/1

    看了这个项目倒是没有别的感受,只能说,埋着头写,写,写

  • 相关阅读:
    第六章:随机化(续1)
    第六章:随机化
    PAT甲组 1010 Radix (二分)
    关于我的2019年度总结
    Codeforces 567D:One-Dimensional Battle Ships(二分)
    Codeforces 567C:Geometric Progression(DP)
    Codeforces 567B:Berland National Library(模拟)
    HDU 4790:Just Random(容斥)
    Codeforces 450C:Jzzhu and Chocolate(贪心)
    Codeforces 450E:Jzzhu and Apples(构造,数学)
  • 原文地址:https://www.cnblogs.com/smart-girl/p/11137005.html
Copyright © 2011-2022 走看看