技术栈
1.vue
2.express
3.mongodb
项目完成步骤
1.vuecli初始化前端项目模板
指令:vue init [template-name] [project-name]
eg:vue init webpack vuecliTest
2.express初始化后端项目模板
- npm init 创建一个npm的package.json配置文件
- npm i express –save 安装express并将其保存到依赖列表中
- npm i express-generator -g 使用全局方式安装 Express 应用生成器
- express [appName] 在安装了 express 的文件夹中快速生成 Express 应用
3.托管代码
- 在github上新建一个仓库(不要初始化)
- 创建本地仓库,先git init,然后git add . ,最后git commit -m “message”
- 远程连接,先git remote add origin git@server-name:path/repo-name.git
(eg:git remote add origin git@github.com:Winnie-bear/Canvas-learn.git) 然后 git push -u origin master 最后 git push origin master 推送最新修改
4.数据库
在后端项目文件夹中新建一个models文件夹,用来装所需的Schema文件
在routes文件下新建一级路由的文件,文件当中可以编写二级路由的代码,同时还需要修改app.js中的代码
例如:在routes文件夹下新建goods.js文件,则/goods是一级路由1
2var goodsRouter=require('./routes/goods');
app.use('/goods',goodsRouter);
连接数据库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const url = "mongodb://mallAdmin:winniebear98813@127.0.0.1:27017/mall?authSource=mall"
//连接数据库
mongoose.connect(url,{ useNewUrlParser: true });
//连接不上的时候
mongoose.connection.on('disconnected',()=>{
console.log('MongoDB connected fail');
})
//连接错误的时候
mongoose.connection.on('error',err=>{
console.log(err)
})
//连接打开的时候
mongoose.connection.once('open',()=>{
console.log('MongoDB Connected successfully!')
})数据库连接成功后方可操作数据库,注意要引入models文件夹下所需的Schema文件
前端代码简析
1.通用组件部分(components文件下)
模态框
语法点:slot、props、$emit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36//核心代码,通过slot进行插值
<div class="md-modal modal-msg md-modal-transition" v-bind:class="{'md-show':mdShow}">
<div class="md-modal-inner">
<div class="md-top">
<button class="md-close" @click="closeModal">Close</button>
</div>
<div class="md-content">
<div class="confirm-tips">
<!-- 提示信息插槽 -->
<slot name="message"></slot>
</div>
<div class="btn-wrap">
<!-- 按钮插槽 -->
<slot name="btnGroup"></slot>
</div>
</div>
</div>
</div>
//父子组件之间的传值和触发父组件上的事件
<script>
export default{
//接收父组件的传值
props:["mdShow"],
data(){
return{
msg:'hello vue'
}
},
methods:{
closeModal(){
//触发父组件的close事件
this.$emit("close");
}
}
}
</script>面包屑导航
知识点:slot
1
2
3
4
5
6
7
8
9
10
11
12
13<template>
<section class="bread">
<div class="bread-wrap">
<nav class="">
<a href="/">
Home
</a>
<!-- 插槽,每个页面显示的当前页不一样 -->
<slot></slot>
</nav>
</div>
</section>
</template>页首
知识点:vuex
app.js1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20import Vuex from 'vuex'
Vue.use(Vuex);
const store =new Vuex.Store({
state:{
nickName:'',
cartCount:0
},
//更改vuex的store中的状态,s不能掉
mutations:{
updateUserInfo(state,nickName){
state.nickName=nickName;
},
updateCartCount(state,cartCount){
state.cartCount+=cartCount;
},
initCartCount(state,cartCount){
state.cartCount=cartCount;
}
}
});NavHeader.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14import {mapState} from 'vuex'
computed: {
//映射this.nickName为this.$store.state.nickName,...扩展运算符,将一个数组转为用逗号分隔的参数序列
...mapState(['nickName','cartCount']);
},
getCartCount(){
axios.get('/users/getCartCount').then((response)=>{
let res=response.data;
if(res.status=='0'){
//触发mutations中注册的方法
this.$store.commit('initCartCount',parseInt(res.result));
}
})
}页尾
(分别对应Modal.vue、 NavBread.vue、 NavHeader.vue、NavFooter.vue)
2.显示页面部分(在views文件夹下)
- 产品列表页面
购物车页面
知识点:computed 计算属性
关键点:- computed 会搜集并记录依赖
- 依赖发生了变化才会重新计算 computed ,由于 computed 是有缓存的,所以当依赖变化之后,第一次访问 computed 属性的时候,才会计算新的值
- 记录的响应式属性都在当前实例范畴内
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22computed:{
checkAllFlag:function(){
return this.checkedCount==this.cartList.length;
},
checkedCount:function(){
var i=0;
this.cartList.forEach((item)=>{
if(item.checked=='1') i++;
});
return i;
},
totalPrice:function(){
var sum=0;
this.cartList.forEach((item)=>{
//被选中的商品才算入总价
if(item.checked=='1'){
sum+=parseFloat(item.salePrice)*parseInt(item.productNum);
}
});
return sum;
}
},
选择地址页面
订单确认页面
知识点:编程式路由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22payMent(){
//$route为当前的router对象,可以获取name、path、query、params等
var addressId=this.$route.query.addressId;
//通过接口将支付以后产生的订单保存到数据库
axios.post('/users/payMent',{
addressId:addressId,
orderTotal:this.orderTotal
}).then((response)=>{
//跳转到下一个页面需要携带数据
let res=response.data;
if(res.status=='0')
{
//$router为VueRouter实例,全局路由对象,任何页面都可以调用 push(), go()等方法
this.$router.push({
path:'/orderSuccess',
query:{
orderId:res.result.orderId,
}
});
}
})
}订单成功页面
知识点:动态路由
1
2
3
4
5
6<div class="btn-l-wrap">
<router-link class="btn btn--m" to="/cart">Cart List</router-link>
</div>
<div class="btn-r-wrap">
<router-link class="btn btn--m" to="/">Goods List</router-link>
</div>(分别对应GoodsList.vue、 Cart.vue、 Address.vue、OrderConfirm.vue、OrderSuccess.vue)
后端代码简析
1./goods显示商品接口
查询商品列表数据
router.get(‘/list’,function(req,res,next){ … });
添加到购物车
router.post(‘/addCart’,function(req,res,next){ … });
2./users用户登录及后续操作接口
- 登陆接口
- 登出接口
- 登录校验接口
- 获取购物车接口
- 购物车删除接口
- 修改购物车接口
- 全选接口
- 获取地址列表接口
- 设置默认地址接口
- 删除地址接口
- 支付产生订单接口
- 根据订单Id查询订单信息接口
- 获取购物车的商品数量接口
3.登录拦截
/server/app.js1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//登录拦截
app.use(function(req,res,next){
//用户登录以后,每次请求都会带上cookie
if(req.cookies.userId){
next();
}else{
//设置未登录状态时的白名单,req.originalUrl包含参数,req.path不包含参数
if(req.originalUrl=='/users/login'||req.originalUrl=='/users/logout'||req.path=='/goods/list')
{
next();
}else{
res.json({
status:'10001',
msg:'当前未登录',
result:''
});
}
}
})
数据库代码简析
定义所需的schema文件即可,每一个Schema都会映射到MongoDB的一个collection上。Schema定义了collection里documents的模板(或者说是框架)。最后要把Schema编译成model,才可以操作数据库。
1.productSchema
2.userSchema
小心脚下有坑!
1.进入mongo终端之前要mongod配置服务器
2.mongoimport之前要退出mongo的环境
3.mongodb设置了用户认证以后,mongoexport和mongoimport时要进行认证,需要输入三条认证信息
mongoimport -u winnie -p=winniebear98813 –authenticationDatabase=admin -d mall -c users –file /usr/local/mallData/dumall-users
4.express中app.js定义一级路由,路由文件里面定义二级路由
5.开启mongodb本地服务的时候要用系统管理员的身份运行cmd
6.本地运行项目最好把数据库建在本地,远程访问数据库需要修改远程数据库的配置文件
7.角色授权分两种,一种是直接在当前库中创建用户并授予相关权限。如admin库中创建admin用户。另一种情况是
将在admin中创建的用户授予操作其他库的权限,相关授权命令如下:
#授予角色:db.grantRolesToUser( “userName” , [ { role: “”, db: “” } ])
8.用接口返回数据库查找结果,输入url时,查询参数一定要带上,否则会报toString undefined
9.修改服务器代码时,一定要重新启动。前端访问后端接口时,后端接口一定要开启
10.保存用户信息,一是通过接口校验,二是通过vuex
11.nginx测试的时候,一定要开启服务器的端口才能访问!!!!!
12.部署后端代码的时候要有package.json 并且可以通过vi bin/www检查是否修改成功,然后cnpm i 安装依赖,xshell必须在后端代码的目录下才可以安装package.json中的依赖
lsof -i :加数字 查询端口占用情况
13.修改mongodb的配置文件后要 mongod –config重新设置一遍
14.通过域名文件夹形式访问前端代码,必须在dist/static/index.html修改assetsPublicPath的路径
15.使用mongoose远程连接,需要修改mongodb.conf中的bind_ip
16.windows系统,先mongo连接数据库,然后use admin进入admin数据库,db.auth认证数据库
17.collection无法导入文件的时候,可能是没有readWrite权限
看这里!
代码详情请见:
电子商城
写在最后的话
第一次写项目总结,多有不足,请多见谅!