一、请求数据
封装http
data() {
return {
list: [],
searchPrice: [
{ gt: 0, lt: 100, id: 1001 },
{ gt: 100, lt: 500, id: 1002 },
{ gt: 500, lt: 1000, id: 1003 },
{ gt: 1000, lt: 5000, id: 1004 },
{ gt: 5000, lt: 10000, id: 1005 }
]
goodsList:[]
};
},
mehtods:{
initData(){
this.axios.get("/goods/list",{params:{start:this.start,limit:this.limit}})
.then(res => {
this.list = res.data.result;
if(res.data.code==200){
this.goodsList = res.data.result;
this.total = Math.ceil(res.data.total/this.limit)*10;
}
});
}
}
mounted() {
this.initData(); //调用
}
二、分页器
<el-pagination
background
layout="prev, pager, next"
:total="total"
@current-change="getpage"
></el-pagination>
data() {
return {
...
total:10,
limit:8,
start:0
};
},
methods:{
...
getpage(page){
console.log(page)
this.start = (page-1)*this.limit;
this.initData();
}
...
}
三、升序降序
<div class="sort">
<el-button @click="handleDefault">默认</el-button>
<button @click="handleSort">排序:</button>
<p>价格:{{(sortFlag==1)?'↑':'↓'}}</p>
</div>
排序
methods:{
compareUp(value){
return(a,b)=>{
return a[value]-b[value]
}
},
compareDown(value){
return (a,b)=>{
return b[value]-a[value]
}
},
handleSort(){
this.sortFlag = (this.sortFlag==1)?-1:1
if(this.sortFlag==1){
this.goodsList.sort(this.compareUp("salePrice"))
}else{
this.goodsList.sort(this.compareDown("salePrice"))
}
},
}
恢复默认
handleDefault(){
this.initData();
}
四、价格分类
<div class="left">
<h3>通过价格搜索</h3>
<div class="price" v-for="value of searchPrice" :key="value.id">
<p @click="handlePrice(value.gt,value.lt)">{{value.gt}}--{{value.lt}}</p>
</div>
</div>
data() {
return {
searchPrice: [
{ gt: 0, lt: 100, id: 1001 },
{ gt: 100, lt: 500, id: 1002 },
{ gt: 500, lt: 1000, id: 1003 },
{ gt: 1000, lt: 5000, id: 1004 },
{ gt: 5000, lt: 10000, id: 1005 }
]
};
}
methods:{
handlePrice(gt, lt) {
this.axios({
url: "/goods/price",
methods: "get",
params: {
gt,
lt
}
}).then(res => {
if (res.data.code == 200) {
this.goodsList = res.data.result;
this.total = 10;
} else {
this.goodsList = [];
this.$message({
duration: 1000,
message: res.data.msg,
type: "warning"
});
}
});
},
}
五、加入购物车
先写后台
models 下新建一个user.js文件
var mongoose = require('./db');
var UserSchema = new mongoose.Schema({
userId:String,
userName:String,
userPwd:String,
orderList:Array,
cartList:Array,
addressList:Array
})
var Users = mongoose.model('Users',UserSchema,'users');
module.exports = Users;
routes 下新建一个users.js
const router = require('koa-router')()
const UsersModel = require('../models/user');
router.prefix('/users')
router.get('/',async ctx=> {
var data = await UsersModel.find({})
ctx.body = {
code:200,
msg:"请求成功",
total:data
};
})
router.post('/addCart',async ctx=>{
var productId = ctx.request.body;
console.log(productId)
})
module.exports = router
前台
<button class="btn" @click="addCart(item.productId)">加入购物车</button>
methods:{
addCart(productId){
this.axios({
method:"post",
url:'/users/addCart',
data:{
productId
}
}).then(res=>{
console.log(res) //就可以拿到id
})
}
}
七、登陆模块
7-1 跨域访问服务器上的cookie
//1.前端代码的配置 main.js
axios.defaults.withCredentials = true
axios.defaults.crossDomain = true;
//允许跨域访问cookie
//2.配置服务器 app.js
app.use(cors({
origin:"http://192.168.14.57:8080", //配置允许跨域的域名
credentials:true
}))
7-2 实现登陆功能
1.前端获取用户和密码
2.携带用户和密码向后台发送http请求
3.后端接收用户和密码
4.向数据库查询
5.将结果返回给前端
//1.前端获取用户和密码
//2.携带用户和密码向后台发送http请求
<el-button type="primary" @click="handleLogin">确 定</el-button>
methods:{
handleLogin(){
if(this.form.username && this.form.pass){
this.$http({
url:"/users/login",
method:"post",
data:{
userName:this.form.username,
userPwd:this.form.pass
}
}).then(res=>{
console.log(res)
})
}
}
}
//3.后端接收用户和密码 ctx.request.body
// 登陆模块
router.post('/login',async ctx=>{
var data = ctx.request.body;
})
//4.向数据库查询
router.post('/login',async ctx=>{
var data = ctx.request.body;
var res = await UsersModel.findOne(data);
//没有的时候null 有的会返回数据
console.log(res)
})
//5.将结果返回给前端
// 登陆模块
router.post('/login',async ctx=>{
var data = ctx.request.body;
var res = await UsersModel.findOne(data);
if(res){
ctx.body = {
code:"200",
msg:"登陆成功",
successName:res.userName
}
}else{
ctx.body = {
code:"400",
msg:"用户名和密码错误"
}
}
})
//前端处理代码
methods:{
handleLogin(){
if(this.form.username && this.form.pass){
this.$http({
url:"/users/login",
method:"post",
data:{
userName:this.form.username,
userPwd:this.form.pass
}
}).then(res=>{
//登陆成功
if(res.data.code==200){
this.$message({
message:res.data.msg,
duration:1000,
type:"success"
})
this.successName = res.data.result
this.dialogFormVisible = false;
}else{
//用户名和密码错误
this.$message({
duration:1000,
message:res.data.msg,
type:"error"
})
}
})
}else{
this.$message({
message:"用户名和密码不能为空",
duration:1000,
type:"error"
})
}
}
}
7-3 使用cookie记录登陆的状态
//1.登陆成功设置cookies
router.post('/login',async ctx=>{
var data = ctx.request.body;
var res = await UsersModel.findOne(data);
if(res){
ctx.cookies.set("userId",res.userId,{
maxAge:1000*60*60
})
ctx.cookies.set("userName",res.userName,{
maxAge:1000*60*60
})
...
})
//2.配置路由检查一下登陆的状态
//检查一下登陆的状态
router.get('/checkLogin',async ctx=>{
var userId = ctx.cookies.get("userId");
if(userId){
ctx.body = {
code:200,
msg:"登陆成功",
result:ctx.cookies.get("userName")
}
}else{
ctx.body = {
code:1001,
msg:"未登录"
}
}
})
//3.页面初始加载时,调用/user/checkLogin检查用户是否登陆
mounted(){
this.$http('/users/checkLogin').then(res=>{
if(res.data.code==200){
this.successName = res.data.result
}else{
this.$message({
message:"未登陆",
duration:1000,
type:"warning"
})
}
})
}
7-4 退出登陆
//1.配置路由 清除cookies
router.post('/logout',async ctx=>{
ctx.cookies.set("userId","",{
maxAge:-1
})
ctx.cookies.set("userName","",{
maxAge:-1
})
ctx.body ={
code:200,
msg:"退出登陆"
}
})
//2.前端代码
methods:{
handleLogout(){
this.$http.post('/users/logout').then(res=>{
this.$message({
message:res.data.msg,
duration:1000
})
this.successName = ""
})
}
}
7-5登录拦截
//使用中间件
//ctx.path 获取前端向后台访问的接口
app.use( async (ctx,next)=>{
console.log(ctx.path)
// 登陆才可以访问后端其他的接口
if(ctx.cookies.get("userId")){
await next()
}else{
//没有登陆的情况后端有些接口时可以访问
if(ctx.path =="/users/login" || ctx.path =="/goods/list" || ctx.path == "/users/Logout"){
await next()
}else{
ctx.body = {
code:1001,
msg:"未登陆"
}
}
}
})
八、购物车模块
8-1购物车查询
router.get('/cartList',async ctx=>{
var data = await UsersModel.findOne({});
var res = data.cartList;
ctx.body ={
code:200,
result:res
}
})
8-2购物车的删除
//后代代码
router.post('/cartList/del',async ctx=>{
var {productId} = ctx.request.body;
var userId = ctx.cookies.get("userId");
var data = await UsersModel.update({userId:userId},{$pull:{cartList:{productId:productId}}});
if(data.ok==1){
ctx.body = {
code:200,
msg:"删除成功"
}
}else{
ctx.body = {
code:1001,
msg:"删除失败"
}
}
})
//前端代码
methods:{
handleDelete(productId) {
console.log(productId);
this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
this.$http
.post("/users/cartList/del", {
productId
})
.then(res => {
console.log(res);
this.initData();
});
})
.catch(() => {});
}
}
8-3购物车的修改
//$set
//前台的代码 tips 传递item
<van-stepper
@change="onChange(item)"
v-model="item.productNum" integer />
methods:{
async onChange(item){
var {productNum,productId,checked} = item;
await this.$http.post('/users/cartList/edit',{
productNum,
productId,
checked
})
}
}
//后台代码
router.post('/cartList/edit',async ctx=>{
var {productNum,productId,checked} = ctx.request.body;
var userId = ctx.cookies.get("userId");
var data = await UsersModel.update(
{userId:userId,"cartList.productId":
productId},{$set:{
"cartList.$.productNum":productNum,
"cartList.$.checked":checked
}});
if(data.ok==1){
ctx.body ={
msg:"修改成功",
code:200
}
}
})
九、路由守卫
Tips:一定要配置再路由地址所对应的主组件
// 路由守卫
beforeRouteLeave (to,from,next) {
this.$http('/users/checkLogin').then(res=>{
if(res.data.code == 200){
next()
}else{
this.$message({
message:res.data.msg,
duration:1000
})
}
})
}
};