使用VUE+Vant组件库实现小米商城app
1 cd到某个文件夹,在命令窗口输入 vue create xiaomi创建vue项目2 在vscode中打开项目 xaomi,可以看到以下项目结构node_modules 包与依赖存放位置public根模板文件src项目源文件.gitigonore当文件用git方式上传(git忽略文件)babel.config....
·
1 cd到某个文件夹,在命令窗口输入 vue create xiaomi
创建vue项目
2 在vscode中打开项目 xaomi,可以看到以下项目结构
- node_modules 包与依赖存放位置
public 根模板文件
src 项目源文件
.gitigonore 当文件用git方式上传(git忽略文件)
babel.config.js ES6转es5配置文件
package.json 项目配置文件
README.md 项目说明文件
yarn.lock yarn安装相关锁定文件 - src文件目录说明
assets 项目资源目录
components 项目组件存放地方
router 路由
store 项目数据
views 项目的页面
App.vue 项目的根组件
main.js 项目的根js
3 在views文件夹中创建5个组件,分别对应购物车,用户,分类,主页,产品详情页
部分源码如下:
####Cart.vue
<script>
// 在nodemodules中的文件可以直接导入,不用指定路径
import jsonp from 'jsonp'
import bus from '../bus.js'
import {mapState,mapMutations,mapGetters} from 'vuex'
export default {
data(){return {
cart:[],
}},
created(){
this.getCart();
// this.getWeather();
// this.getC();
bus.$emit("tabevent",false)
},
computed:{
// 循环cart改为循环goods,因为goodsNum统计的是goods中的商品数量
...mapState(["goods"]),
...mapGetters(["goodsNum"]),
// 价格是自定义属性,而goods和goodsnum是映射过来的属性
totalPrice:function(){
var price = 0;
this.goods.forEach(item => {
// price+=item.price;
// 假数据是没有select属性,也没有num属性。只有name和price属性
//所以想要显示价格,必须使用真数据,必须在进入购物车之前就调用getCart()方法
if(item.select){
//必须是被选择的商品
price+=item.num*item.price;
}
});
return price;
}
},
beforeRouteLeave(to,from,next){
// 离开的时候也要提交一个事件
bus.$emit("tabevent",true);
// this.$parent.showTab=true;
next();
},
methods: {
...mapMutations(["delCart"]),
getCart(){
this.$http.get("http://bigr.apnzi.com/cart.py")
// this.$http.get("/static/mock/cart.json")
.then(res=>{
//我们需要的数据在响应对象的data中
// console.log(res.data);
// console.log(res);
this.cart = res.data;
})
},
},
}
</script>
Home.vue
<template>
<div class="home">
<div class="row header">
<a href="#/"><img src="../assets/logo.png" alt="" height="22"></a>
<input type="text" class="col">
<a href="#/user"><img src="../assets/user.png" alt="" height="26"></a>
</div>
<div class="subheader">
<!-- <span v-for="item in tabs" :key="item.page_id">
{{item.name}}
</span> -->
<van-tabs v-model="active" swipeable background="#f0f0f0">
<van-tab v-for="item in tabs" :key="item.page_id" :title="item.name">
{{item.name}}
</van-tab>
</van-tabs>
</div>
<div class="content full has-subheader">
<!-- //轮播图 -->
<!-- <img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/36b5b151fe94bc6f0024231b9797cbfc.jpg?thumb=1&w=720&h=360" width="100%" alt=""> -->
<van-swipe :autoplay="3000" indicator-color="#f30" :height="200">
<van-swipe-item v-for="(item, index) in gallery" :key="index">
<img v-lazy="item.img_url" width="100%" />
</van-swipe-item>
</van-swipe>
<!-- //子分类A -->
<div class="row">
<div class="col" v-for="item in subCategoryA" :key="item.img_url">
<img :src="item.img_url" alt="" width="100%">
</div>
</div>
<!-- 子分类B -->
<div class="row">
<div class="col" v-for="item in subCategoryB" :key="item.img_url">
<img :src="item.img_url" alt="" width="100%">
</div>
</div>
<div class="row" v-if="productA.length">
<div class="col-50">
<img :src="productA[0].img_url" width="100%" alt="">
</div>
<div class="col-50">
<div class="clear">
<img :src="productA[1].img_url" width="100%" alt="">
</div>
<div>
<img :src="productA[2].img_url" width="100%" alt="">
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:'home',
data(){
return{
tabs:[],//分类信息
gallery:[],
subCategoryA:[],
subCategoryB:[],
productA:[],
active:'a',
}},
created(){
this.getPage();
},
methods:{
getPage(){
this.$http({
url:'http://bigr.apnzi.com/page.py',
method:"GET"
})
.then(res=>{
if(res.data.code==0){
this.tabs=res.data.data.tabs;
this.gallery=res.data.data.data.sections[0].body.items;
this.subCategoryA=res.data.data.data.sections[1].body.items;
this.subCategoryA=res.data.data.data.sections[2].body.items;
this.productA=res.data.data.data.sections[4].body.items;
console.log(this.productA);
}else{
alert(res.data.result)
}
})
}
},
components:{
}
}
</script>
4配置路由
index.js
const routes = [
{
path: '/',
name: 'home',
component: Home,
meta:{keep:true}
},
{
path: '/cart',
name: 'cart',
component: Cart
},
{
path: '/product/:id',
name: 'product',
component: Product
},
{
path: '/user',
name: 'user',
component: User
},
{
path: '/category',
name: 'category',
//想要缓存哪个组件,就加个keep属性,在app.vue进行判断
meta:{keep:true},
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/Category.vue')
}
]
5 根组件App.vue的配置
app.vue
<template>
<div id="app">
<div class="content full" :class="{'has-footer':showTab}">
<!-- <keep-alive :include="keepAlive" >
<router-view/>
</keep-alive> -->
<keep-alive>
<router-view v-if="$route.meta.keep"/>
</keep-alive>
<router-view v-if="!$route.meta.keep"/>
</div>
<div class="tabs row footer tac" v-if="showTab">
<!-- <router-link to="/" class="col"> {{$store.state.goods}}</router-link> | -->
<router-link to="/" class="col">首页</router-link> |
<router-link to="/category" class="col">分类</router-link>
<router-link to="/cart" class="col">购物车({{goodsNum}})</router-link>
<router-link to="/user" class="col">我的</router-link>
</div>
</div>
</template>
<script>
import bus from "./bus.js";
import {mapState,mapGetters,mapActions} from 'vuex';
// map映射 通过映射 成为computed 里面一个属性
export default {
// 监听一个事件
created() {
bus.$on("tabevent",(data)=>{
console.log("tabevent",data);
this.showTab = data;
});
this.getCart()
},
data(){return {
showTab:true,
}},
computed:{
"goods":function(){
return this.$store.state.goods;
},
//map映射可以把store中的属性或者方法变成当前组件的属性或方法
// ...mapState(["goods"]),
...mapGetters(["goodsNum"])
},
methods:{
//action映射必须写在methods中
...mapActions(["getCart"])
}
}
6 进入项目文件启动项目
cd xxxxx/xiaomi
yarn serve
浏览器打开 http://localhost:8080
7成功
8总结
该vue项目使用vuex实现组件之间的数据共享和自动更新(购物车金额随着数量自动更新),同时使用vant组件库完成了菜单栏,轮播图等前端的一些布局,同时通过vue的全局路由守卫实现了登录注册的路由权限判断,除此以外还是用了js-cookie来存储cookie,实现了登录保持和注销,数据是组件通过axios发送ajax请求从后台获取(js存在同源策略,所以我在自己的后台访问小米的接口再进行转发,设置allow-origin="*"),由于篇幅有限代码只写了一部分,需要完整项目源码练手的朋友可以留下邮箱
更多推荐
已为社区贡献1条内容
所有评论(0)