今天是个美好的日子,因为今天又想到了一个新的项目——XMall商城。
特此记录项目开发全过程
商城官网传送门 http://xmall.exrick.cn/#/home
本项目目录基于Vue-cli脚手架搭建
vue create xmallshop
项目依赖选择了vueRouter、VueX,在搭建完成后安装了如下依赖包:
"axios": "^0.21.1",
"core-js": "^3.6.5",
"element-ui": "^2.15.1",
"less-loader": "^5.0.0",
"node-sass": "^4.13.0",
"sass-loader": "^8.0.0",
"vue": "^2.6.11",
"vue-lazyload": "^1.3.3",
"vue-router": "^3.2.0",
"vuex": "^3.4.0"
然后。分析了一下路由结构,创建项目完以后第一件事肯定是分配路由啦,观察了一下官网发现顶部双级导航栏在切换导航菜单时始终保持,因此Mheader(导航栏)作为了一个component公共路由,再把导航栏里每个菜单单独分配了一个路由,如图
路由划分如下:
const routes = [
{
path:'/',
redirect:'/home',
component:Home
},
{
path:'/home',
component:Home
},
{
path:'/goods',
component:Goods
},
{
path:'/thanks',
component:Thanks
},
{
path:'/login',
component:Login
},
{
path:'/user',
component:User
},
{
path:'/cart',
component:Cart
}
]
路由分配完毕,今天的任务是首页(/home)的页面设计,第一部分是轮播图用的element-UI的组件,很方便所以也没有单独创建组件,直接在home.vue里贴上去了。
<!-- 轮播图 -->
<div class="banner">
<el-carousel indicator-position="outside" height='480px'>
<el-carousel-item v-for="(item,index) in banner" :key="index">
<img class = "img1 a" v-if="item.picUrl" :src = "item.picUrl">
<img class = "img2 a" v-if="item.picUrl2" :src = "item.picUrl2">
<img class = "img3 a" v-if="item.picUrl3" :src = "item.picUrl3">
</el-carousel-item>
</el-carousel>
</div>
<!-- 轮播图over -->
关于轮播图里的图片数据以及接下来卡片、列表里的数据是从官网拿的接口,在本地创了JSON文件,再用node.js访问导出接口后交给前端去get请求的,后端接口导出部分如下:
const fs = require('fs');
module.exports = {
devServer:{
before(app,serve){
app.get('/api/goods/home',(req,res)=>{
fs.readFile('./db/home.json','utf8',(err,data)=>{
if(!err){
res.json(JSON.parse(data));
}
})
})
app.get('/api/goods/allgoods',(req,res)=>{
fs.readFile('./db/allgoods.json','utf8',(err,data)=>{
if(!err){
res.json(JSON.parse(data));
}
})
})
}
}
}
测试接口用了postman,真的很好用也很方便,总比在控制台里看要舒服很多。
今天用到了api/goods/home的接口,首页里的所有数据都是从这里得到的,包括了轮播图URL以及各种商品的信息、价格。值得一提的是在前端接口请求一般都会在vcreated钩子函数中请求,原因是所有DOM生成完毕后可直接渲染。
关于接口的请求,用到的则是axios,由于请求比较频繁一直会用到,因此我在项目VUE全局里自定义了一个$http用于请求。
Vue.prototype.$http = axios;
请求方式如下:
async created () {
const res = await this.$http.get("/api/goods/home");
if(res.data.code === 200){
this.result = res.data.result;
this.banner = res.data.result[0].panelContents;
console.log(this.banner);
}
console.log(res);
},
接下来页面中商品列表及卡片仔细观察其实结构是类似的,只需要v-for循环渲染即可,由于每一板块在json数据中有判断,如热门活动的item.type为1、周边品牌的item.type为2等等。因此循环渲染就完事。
并且有很多相同样式的卡片定义了卡片组件MShelf方便公用。
<div v-for = "(item,index) in result" :key="index">
<!-- item.type为1时是热门活动 -->
<div class="activity-panel" v-if="item.type==1">
<el-row>
<el-col class="content" :span="8" v-for="(o,index) in item.panelContents" :key="index" width="305px">
<el-card :body-style="{ padding: '0px'}">
<img :src="o.picUrl" class="i">
<a href="#" class="cover-link"></a>
</el-card>
</el-col>
</el-row>
</div>
<!-- 热门活动渲染over -->
<section class="w mt30 clearfix" v-if="item.type==2">
<m-shelf :title="item.name">
<div slot = "content" class = "hot">
<mall-goods v-for = "(o,index) in item.panelContents" :key="index" :goods="o"></mall-goods>
</div>
</m-shelf>
</section>
<section class="w mt30 clearfix" v-if="item.id==2||item.id==10||item.id==3" :style="watchStyle(item.id)">
<m-shelf :title="item.name">
<div slot = "content" class="floors">
<div class="imgbanner" v-for="(o,index) in item.panelContents" :key="index" v-show="o.type==2||o.type==3">
<a href="#" class="cover-link"></a>
<img :src="o.picUrl">
</div>
<mall-goods v-for="y in item.panelContents" :key="y.id" v-show="y.type==0" :goods="y"></mall-goods>
</div>
</m-shelf>
</section>
</div>
</div>
最后的底部与导航栏一样,在菜单的切换时都会存在,因此创建了一个Footer组件在每个路由组件中存放。
明天继续加油吧…
学习前端真的很快乐,有兴趣不怕学不会,休息~