命名视图
一个路由对应多个视图的变化,每个视图对应不同的组件
- App.vue 抽离底部组件 components/footer.vue
- App.vue 添加第二个视图,设置name属性,配置路由规则时则可以选择要不要底部
- 修改router/index.js的路由规则
首页列表点击进入产品的详情
设计详情页面以及添加路由
- 详情页根据 /detail/proid proid为产品的id,依据产品的id不同获取不同的数据,渲染页面。 这时采用动态路由
动态路由匹配
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:
- 改造详情的路由,增加标识
声明式跳转
<router-link to=""></router-link>
- 偏向JS的写法
<router-link :to="'/detail/'+item.proid"></router-link>
正确的
<router-link :to="{ name: 'detail', params: { proid: item.proid }}" ></router-link>
编程式跳转
this.$router.push / replace / go ()
- 偏向JS的写法
- Vue 推荐的写法
- 演变写法
详情页面获取参数请求数据
- 获取路由的参数信息
- 当匹配到一个路由时,参数值会被设置到
this.$route.params
,可以在每个组件内使用
this.$route.params
- 封装获取产品详情数据的接口
- 详情页面请求数据
- 渲染详情页面
- 添加加入购物车组件 vant GoodsAction
- 修改详情头部
- 返回上一页
- 点击加入购物车 ---- 必须等登陆 — 注册
注册功能
- 个人中心页面添加 注册登录 入口
? 如果未登录显示等和注册按钮,如果是已登录 显示的个人的信息 - 完成注册表单
- 注册头
- 注册表单
- 复制注册的页面 至 登陆页面 ,修改标识为登录
- 完成注册功能 — 将数据提交给后端,后端校验有没有该用户,没有完成注册,注册成功 跳转到登陆页面(一定是替换)
- 封装注册接口的方法 api/index.js
- 注册页面完成业务逻辑
登陆功能
- 封装登陆接口 api/index.js
- 登录页面完成业务逻辑
加入购物车
后端代码
-
设计购物车的集合 admin-app/sql/col/carts.js
-
设计加入购物车的业务逻辑
admin-app/api/cart.js
-
封装更新数据库的方法
admin-app/sql/index.js
-
购物车接口引入数据库完成业务逻辑
var express = require('express');
var router = express.Router();
var sql = require('./../sql')
var Cart = require('./../sql/col/carts')
var Pro = require('./../sql/col/pros')
var uuid = require('node-uuid')
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('购物车相关接口');
});
/**
* @api {post} api/cart/add 加入购物车
* @apiDescription 加入购物车
* @apiGroup cart
* @apiParam { string } userid 用户ID
* @apiParam { string } proid 产品id
* @apiParam { number } num 产品数量 (默认为1)
* @apiSuccessExample { json } Success-Response:
* res.send({
* code: '804',
* message: '完善购物车信息'
* })
* {
* code: '200',
* message: '加入购物车成功'
* }
* @apiSampleRequest /api/cart/add
* @apiVersion 1.0.0
*/
router.post('/add', function(req, res, next) {
// 获取前端提交的数据 post
let { proid, userid, num } = req.body // 这里绝对不能用const
num = num * 1 || 1 // 给nun 设置默认值为一,并转类型位num
// 如果当前用户数据库中有该商品,直接数量相加,如果没有,添加新数据
// 1 判断前端是否传了 proid userid 没传直接返回
if ( !userid || !proid ) {
res.send({
code : '804',
msg : '完善购物车信息'
})
return
}
// 2 如果当前的用户,数据库中有该商品,那么你的数量直接加num即可,否则直接添加一条新的记录
sql.find(Cart , {userid , proid} , {_id:0} ).then(data1 => {
if ( data1.length > 0 ) {
// 已有该商品。调用修改方法,数量递增
// { $inc: { num: num } } 将数据库中的num字段自增num
// { $set: { num: 10 }} // 设置num值为10
// $set: { flag: 1 } } 必为选中
sql.update(Cart, {userid , proid}, {$inc: { num }, $set: { flag: 1 }})
.then( () => {
res.send({
code : '200',
msg : '加入购物车成功'
})
})
} else {
// 没有该商品,调用增加数据方法,添加该商品信息
// 先通过proid 查找购物车中该商品所需的必要信息
sql.find(Pro, {proid}, {_id: 0}).then(data2 => {
const { brand, proname, proimg, desc, rating, price} = data2[0]
const insertObj = {
cartid : 'cart_' + uuid.v1(),
userid,
proid,
brand,
proname,
proimg,
desc,
rating,
price,
flag : 1, // 该flag为是否被选中,与商品信息flag是否热销不一样
num
}
// 插入数据库
sql.insert(Cart, insertObj).then(() => {
res.send({
code: '200',
message: '加入购物车成功'
})
})
})
}
})
});
module.exports = router;
- 生成接口文档
apidoc -i api/ -o public/apidoc
- 测试加入购物车接口
- 编写 查看购物车接口
/**
* @api {get} api/cart 查询购物车
* @apiDescription 查询购物车
* @apiGroup cart
* @apiParam { string } userid 用户ID
* @apiSuccessExample { json } Success-Response:
* res.send({
* code: '805',
* message: '请携带用户信息'
* })
* {
* code: '200',
* message: '查询购物车成功'
* }
* @apiSampleRequest /api/cart
* @apiVersion 1.0.0
*/
router.get('/', function(req, res, next) {
// 获取get请求中的userid
const { userid } = req.query
// 通过userid获取购物车中的数据
// 判断userid是否存在
if (!userid) {
res.send({
code: '805',
msg: '请携带用户信息'
})
} else {
sql.find(Cart, { userid }, { _id: 0 } ).then(data => {
res.send({
code: '200',
msg: '获取购物车信息',
len: data.length,
data: data
})
})
}
});
前端代码
详情页面加入购物车
- 封装加入购物车的接口
查看购物车
- 封装接口
- 查看购物车业务逻辑
<template>
<div class="box">
<header class="header">
<van-nav-bar
title="购物车"
left-arrow
@click-left="$router.go(-1)"
>
</van-nav-bar>
</header>
<div class="content">
<h3 v-if="flag">您的购物车空空如也,请添加商品</h3>
<div class="cartlist" v-if="!flag">
<van-card
:num="item.num"
:price="item.price"
:desc="item.desc"
:title="item.proname"
:thumb="item.proimg"
v-for="item of cartlist"
currency='¥'
:key="item.proid"
>
<div slot="tags">
<van-tag plain type="danger">{{ item.brand }}</van-tag>
</div>
<div slot="footer">
<van-button size="mini">+</van-button>
<van-button size="mini">-</van-button>
</div>
</van-card>
</div>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import { getCartData } from '@/api'
import { Toast, Card, Tag, Button, NavBar } from 'vant'
Vue.use(Toast)
Vue.use(Card)
Vue.use(Tag)
Vue.use(Button)
Vue.use(NavBar)
export default {
data () {
return {
flag: true,
cartlist: []
}
},
mounted () {
const loginState = localStorage.getItem('loginState')
if (loginState) {
const userid = localStorage.getItem('userid')
getCartData({ userid }).then(res => {
if (res.data.len > 0) {
this.flag = false
this.cartlist = res.data.data
}
})
} else {
Toast('请先登录')
this.$router.push('/login')
}
}
}
</script>