【vue】openshopping-vue

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

看看代码有什么乾坤
看了下package.json发现有axios和vue-lazyload
【vue】openshopping-vue_第1张图片
先看代码一层一层进去里面

//app.vue


看main.js中的
由上到下一步一步来
【vue】openshopping-vue_第2张图片

先看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
};

我们再看src\config\components.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
//src\config\rem.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,结合路由来看我们的页面内容
【vue】openshopping-vue_第3张图片

//src\page\index.vue





引入了page.vue和navigate.vue

//navigate.vue



//page.vue

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

//src\components\page\whitespace.vue



//src\components\page\line.vue



//src\components\page\text.vue



//src\components\page\notice.vue





//src\components\page\cube.vue



//src\components\page\imageAd.vue




//src\components\page\imageText.vue





//src\components\page\product.vue




//src\api\page.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 }
    })
  }

感觉好神奇,上面的那些就处理完毕数据了吗?
看第二个页面吧
【vue】openshopping-vue_第4张图片
这个页面就跟首页不一样了,所有的东西是写死的可是也暴露出来了,第一个home页面都没有看到axiox

//src\page\category\index.vue




这个里面就是很普通的布局方式,静态文件,如果要点击进去下一个路由,应该在点击的时候,进行一次数据的请求
看一下对cart的处理
【vue】openshopping-vue_第5张图片
cart页面也是前端写死数据进行渲染的,我们来看看代码

//src\page\cart\index.vue




接下来看order页面
【vue】openshopping-vue_第6张图片





【vue】openshopping-vue_第7张图片

//src\page\user\address\list.vue




【vue】openshopping-vue_第8张图片

//src\page\user\address\edit.vue




【vue】openshopping-vue_第9张图片

//src\page\user\index.vue
//点击不同的路由跳转到不同的页面




【vue】openshopping-vue_第10张图片

//login.vue





上面的内容也只是一个简单的布局,点击跳转到新的页面
【vue】openshopping-vue_第11张图片





这里面也是静态页面
【vue】openshopping-vue_第12张图片






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





【vue】openshopping-vue_第13张图片

//user/order




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

//src\config\env.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,
}
//src\config\request.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

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

转载于:https://www.cnblogs.com/smart-girl/p/11137005.html

你可能感兴趣的:(【vue】openshopping-vue)