1.项目初始化
npm -v //确认安装node基本环境
npm i vue-cli -g //-g 全局安装vue-cli
vue init webpack //使用webpack模板安装
不安装eslint,eslint用于多人开发,按照谷歌和facebook的代码标准开发。
unit --no //大公司有专门测试人员
ese --no
package-lock.json 别人不会因为版本不同而运行不了。
README.md 如何运行 关键点 项目注意事项 API接口 都写在里面。
安装:
npm i vant -S //S 用于生产环境
npm install vant --save --registry=https://registry.npm.taobao.org//可以提升速度
全局引入:main.js
import Vant from 'vant'
import 'vant/lib/vant-css/index.css'
Vue.use(Vant)
不建议全局引入整个文件,把整个组件库引入会导致打开好慢,应按需引入。
优雅的引入Vant:打包文件会减少很多,速度会加快。
npm i babel-plugin-import -D
完整:
npm install babel-plugin-import --save-dev
在.babelrc中配置plugins(插件)
"plugins": [
"transform-vue-jsx",
"transform-runtime",
["import",{"libraryName":"vant","style":true}]
]
在src/main.js里加入下面的代码:
import { Button } from 'vant'
Vue.use(Button)
有了这段代码之后,我们就可以在需要的组件页面中加入Button了.
3.移动端屏幕适配基础
rem(font size of the root element)是相对长度单位。相对于根元素(即html元素)font-size计算值的倍数。
//得到手机屏幕的宽度
let htmlWidth = document.documentElement.clientWidth || document.body.clientWidth;
//得到html的Dom元素
let htmlDom = document.getElementsByTagName('html')[0];
//大屏设备会比较难看
if(htmlWidth>750){
htmlWidth=750
}
//设置根元素字体大小
htmlDom.style.fontSize= htmlWidth/20 + 'px'; //以ip5 宽320PX 字体16PX为基准
三个基础知识:
1. 首页路由的配置:
routes: [
{path:"/",name:'ShoppingMall',component:ShoppingMall},
]
2. 建立首页组件(components):先把首页组件建立起来。插件:vue VSCode Snippets
vba生成基本框架代码
vda 生成data
3. 讲解Vant的布局方法:24格布局法
按需引入组件 mai.js
import {Button,Row,Col} from 'vant'
Vue.use(Button).use(Row).use(Col)
--vue --
5.首页搜索布局
在vue-cli使用less
npm install less less-loader --save-dev
11任务13:首页楼层效果制作
Img 外套一个 div ,把div背景色设置与图片颜色相同,然后再设置div边框,div设置为怪异盒模型。
box-sizing: border-box;
12楼层组件封装和watch使用技巧
使用组件三部曲:
导入
import floorComponent from '../component/floorComponent'
注册
components:{
floorComponent
}
使用:
封装组件:
接收数据
props:['floorData']
设置好数据:
data() {
return {
floorData0:{},
floorData1:{},
floorData2:{}
}
}
获取数据,因为是异步请求,必须监控数据,因为不会马上接收到数据
watch:{
floorData:function(val){
this.floorData0 = this.floorData[0]
this.floorData1 = this.floorData[1]
this.floorData2 = this.floorData[2]
}
}
使用方法:
watch:{
example0(curVal,oldVal){
console.log(curVal,oldVal);
}
}
13.Filter使用和代码优化
使用
引入
import {toMoney} from '@/filter/moneyFilter.js'
调用:
filters:{
moneyFilter(money){
return toMoney(money)
}
}
--moneyFilter.js--
export function toMoney(money){
let newMoney = money
if(newMoney){
newMoney = newMoney.toFixed(2)
}else{
newMoney = 0;
newMoney = newMoney.toFixed(2)
}
return newMoney
}
=====优化后======>
export function toMoney(money=0){
return money.toFixed(2)
}
14.首页热卖模块的Van-list组件使用
//对单个商品抽出来做组件
import hotgoodComponent from '../component/hotgoodComponent'
components:{
goodsInfo:hotgoodComponent
},
---hotgoodComponent.vue---
v-lazy="goodsImage" width="90%" />
import {toMoney} from '@/filter/moneyFilter.js'
export default {
props:['goodsImage','goodsName','goodsPrice','goodsId'],
filters:{
moneyFilter(money){
return toMoney(money)
} },
15.服务接口API配置文件制作
把要请求的接口提出来做成一个文件serviceAPI.config.js
const BASEURL = "https://www.easy-mock.com/mock/5ae2eeb23fbbf24d8cd7f0b6/SmileVue/"
const LOCALURL = "http://localhost:3000/"
const URL ={
getShopingMallInfo : BASEURL+'index', //商城首页所有信息
getGoodsInfo : BASEURL+'getGoodsInfo',
registerUser : LOCALURL+'user/register', //用户注册接口
login : LOCALURL+'user/login', //用户登录接口
getDetailGoodsInfo : LOCALURL+'goods/getDetailGoodsInfo', //获取商品详情
getCateGoryList : LOCALURL+'goods/getCateGoryList', //得到大类信息
getCateGorySubList : LOCALURL+'goods/getCategorySubList', //得到小类信息
getGoodsListByCategorySubID : LOCALURL+'goods/getGoodsListByCategorySubID', //得到小类商品信息
}
module.exports = URL //暴露url对象出去
调用:
import url from '@/serviceAPI.config.js'
axios({
url:url.getShopingMallInfo,
method:"get"
}).then(...)
Koa2 前端服务器
新建service目录,启动一个最基本的服务
const Koa = require("koa")
const app = new Koa();
app.use(async(ctx)=>{
ctx.body = "hello,world"
})
app.listen(3000);
console.log("app is start")
Mongodb
1.安装 3.4 版本
2.设置环境变量
C:\Program Files\MongoDB\Server\3.4\bin
Robo 3T
建立连接
Mongoose是一个开源的封装好的实现Node和MongoDB数据通讯的数据建模库
Mongoose的安装
npm install mongoose --save
==service/database/init.js==
const mongoose = require('mongoose')
const db = "mongodb://localhost/smile-db" //创建一个smile-db的数据库
exports.connect = ()=>{
//连接数据库
mongoose.connect(db)
let maxConnectTimes = 0
return new Promise((resolve,reject)=>{
//把所有连接放到这里//增加数据库监听事件
mongoose.connection.on('disconnected',()=>{
console.log('***********数据库断开***********')
if(maxConnectTimes<3){ //当失败,尝试3次连接
maxConnectTimes++
mongoose.connect(db)
}else{
reject()
throw new Error('数据库出现问题,程序无法搞定,请人为修理......')
}
})
mongoose.connection.on('error',err=>{
console.log('***********数据库错误***********')
if(maxConnectTimes<3){
maxConnectTimes++
mongoose.connect(db)
}else{
reject(err)
throw new Error('数据库出现问题,程序无法搞定,请人为修理......')
}
})
//链接打开的时
mongoose.connection.once('open',()=>{
console.log('MongoDB connected successfully')
resolve()
})
})
}
===========service/index.js
const { connect } = require('./database/init.js')
;(async () =>{
await connect()
})()
18.Mongoose的Schema建模介绍
Schema,他相当于MongoDB数据库的一个映射。Schema是一种以文件形式存储的数据库模型骨架,无法直接通往数据库端,也就是说它不具备对数据库的操作能力。Schema是以key-value形式Json格式的数据。
在/servcie/database/文件夹下新建一个schema文件夹,然后新建一个User.js文件
const mongoose = require('mongoose') //引入Mongoose
const Schema = mongoose.Schema //声明Schema
let ObjectId = Schema.Types.ObjectId //声明Object类型
//创建我们的用户Schema
const userSchema = new Schema({
UserId:ObjectId,
userName:{unique:true,type:String},
password:String,
createAt:{type:Date,default:Date.now()},
lastLoginAt:{type:Date,default:Date.now()}
})
//发布模型
mongoose.model('User',userSchema)
19.载入Schema和插入查出数据
schema建立好以后,需要我们载入这些数据库,当然最好的方法就是在后台服务已启动的时候就把载入做好,所以我们在service/init.js里作这件事,然后在index.js里直接执行。
直接在service\init.js 先引入一个glob和一个resolve
首先安装glob
npm install glob --save
const glob = require('glob')
const {resolve} = require('path')
了解两个引入的模块用法后,我们就可以一次性引入所有的Schema文件了。
exports.initSchemas = () =>{
glob.sync(resolve(__dirname,'./schema/','**/*.js')).forEach(require)
}
使用了glob.sync同步引入所有的schema文件,然后用forEach的方法require(引入)进来。这比你一条条引入要优雅的多。
插入一条数据
====index.js=======
const mongoose = require('mongoose')
const {connect , initSchemas} = require('./database/init.js')
我们直接在service/index.js的立即执行函数里插入一条User数据
;(async () =>{
await connect()
initSchemas()
const User = mongoose.model('User')
let oneUser = new User({userName:'jspang',password:'123456'})
oneUser.save().then(()=>{
console.log('插入成功')
})
})()
let users = await User.findOne({}).exec()
console.log('------------------')
console.log(users)
console.log('------------------')
exec() 方法用于检索字符串中的正则表达式的匹配。
RegExpObject.exec(string)
19.打造安全的用户密码加密机制
加密处理
密码的加密有很多种加密算法,比如我们使用的MD5加密或者hash256加密算法,其实他们都是hash的算法。就是把你的密码进行一次不可逆的编译,这样就算别人得到了这个密码值,也不能进行直接登录操作。
我们可以通过(http://www.atool.org/hash.php) 网站,直观的看一下加密的算法。
加盐处理
有了加密的处理,我们的密码就安全多了,但是有用户的密码设置的太过简单,很好进行暴力破解或者用彩虹表破解,这时候感觉我们的密码又不堪一击了。这时候我们要使用加盐技术,其实就是把原来的密码里,加入一些其他的字符串,并且我们可以自己设置加入字符串的强度。
把加盐的数据库密码进行hash处理后,再存入数据库就比较安全了。
简介: bcrypt是一种跨平台的文件加密工具。bcrypt 使用的是布鲁斯·施内尔在1993年发布的 Blowfish 加密算法。由它加密的文件可在所有支持的操作系统和处理器上进行转移。它的口令必须是8至56个字符,并将在内部被转化为448位的密钥。
首先是用npm 进行安装
npm instal --save bcrypt
引入bcrypt
const bcrypt = require('bcrypt')
然后是用pre每次进行保存时都进行加盐加密的操作。
const SALT_WORK_FACTOR = 10//加密强度
/每次存储数据时都要执行
userSchema.pre('save', function(next){
//let user = this
console.log(this)
bcrypt.genSalt( SALT_WORK_FACTOR,(err,salt)=>{
if(err) return next(err)
bcrypt.hash(this.password,salt, (err,hash)=>{
if(err) return next(err)
this.password = hash
next()
})
})
})
20.注册页面
vue的路由配置文件 router/index.js
import Register from '@/components/pages/Register'
export default new Router({
routes: [
{path: '/',name: 'ShoppingMall',component: ShoppingMall},
{path: '/register',name: 'Register',component: Register},
]
})
--Register.vue--
<template>
<div>
<van-nav-bar
title="用户注册"
left-text="返回"
left-arrow
@click-left="goBack"
/>
<div class="register-panel">
<van-field
v-model="username"
label="用户名"
icon="clear"
placeholder="请输入用户名"
required
@click-icon="username = ''"
/>
<van-field
v-model="password"
type="password"
label="密码"
placeholder="请输入密码"
required
/>
<div class="register-button">
<van-button type="primary" size="large">马上注册van-button>
div>
div>
div>
template>
export default {
data() {
return {
username: '',
password: '',
}
},
methods: {
goBack() {
this.$router.go(-1)
}
},
}
21.Koa2的用户操作的路由模块化
安装路由中间件
npm install koa-router --save
新建一个appApi的文件夹
--service/appApi/User.js--
const Router = require ('koa-router')
let router = new Router()
router.get('/',async(ctx)=>{
ctx.body="这是用户操作首页"
})
router.get('/register',async(ctx)=>{
ctx.body="用户注册接口"
})
module.exports=router;
--service/idnex.js--
const Router = require('koa-router')
//引入我们的user.js模块
let user = require('./appApi/user.js')
//装载所有子路由
let router = new Router();
router.use('/user',user.routes())
//加载路由中间件
app.use(router.routes())
app.use(router.allowedMethods())
22.打通注册用户的前后端通讯
Post 请求中间件:
npm install --save koa-bodyparser
---service/index.js---
const bodyParser = require('koa-bodyparser')
app.use(bodyParser());
前端的axios请求处理
---register.vue---
<van-button type="primary" @click="axiosRegisterUser" size="large">马上注册van-button>
import axios from 'axios'
在methods属性里,写入如下方法
axiosRegisterUser(){
axios({
url: url.registerUser,
method: 'post',
data:{
username:this.username,
password:this.password
}
})
.then(response => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
}
koa2支持跨域请求
安装koa2-cors中间件
npm install --save koa2-cors
const cors = require('koa2-cors')
app.use(cors())
---service/appApi/user.js----
router.post('/register',async(ctx)=>{
console.log(ctx.request.body)
ctx.body= ctx.request.body
})
23.用户注册数据库操作
-----service/appApi/user.js-----
const mongoose = require('mongoose')
router.post('/register',async(ctx)=>{
const User = mongoose.model('User')
let newUser = new User(ctx.request.body)
await newUser.save().then(()=>{
ctx.body={
code:200,
message:'注册成功'
}
}).catch(error=>{
ctx.body={
code:500,
message:error
}
})
})
import { Toast } from 'vant'
axiosRegisterUser(){
axios({
url: url.registerUser,
method: 'post',
data:{
userName:this.username,
password:this.password
}
})
.then(response => {
console.log(response)
//如果返回code为200,代表注册成功,我们给用户作Toast提示
if(response.data.code == 200){
Toast.success('注册成功')
}else{
console.log(response.data.message)
Toast.fail('注册失败')
}
console.log(response.data.code)
})
.catch((error) => {
Toast.fail('注册失败')
})
}
24.注册的防重复提交
方法:设置vant-button 的loading属性
openLoading: false, //是否开启用户的Loading
axios({
url: url.registerUser,
method: 'post',
data:{
userName:this.username,
password:this.password
}
})
.then(response => {
console.log(response)
//如果返回code为200,代表注册成功,我们给用户作Toast提示
if(response.data.code == 200){
Toast.success('注册成功')
this.$router.push('/')
}else{
console.log(response.data.message)
Toast.fail('注册失败')
this.openLoading=false
}
})
.catch((error) => {
Toast.fail('注册失败')
this.openLoading=false
})
25.登录的服务端业务逻辑代码
需要在Shema中制作一个比对的实例方法,这个方法就是比对我们加盐加密后的密码的。在service/database/schema/User.js下增加下面的代码:
userSchema.methods = {
//密码比对的方法
comparePassword:(_password,password)=>{
return new Promise((resolve,reject)=>{
bcrypt.compare(_password,password,(err,isMatch)=>{
if(!err) resolve(isMatch)
else reject(err)
})
})
}
}
上面的代码声明了一个实例方法,方法叫做comparePassword,然后传递两个参数,一个是客户端密码,一个是数据库取出来的密码。用bcrypt提供的compare方法就可以比对,最后包装成Promise返回就可以了。
进入service/appApi/user.js,增加一个login路由,并在路由内写入业务逻辑代码。
/*登录的实践 */
router.post('/login',async(ctx)=>{
//得到前端传递过来的数据
let loginUser = ctx.request.body
console.log(loginUser)
let userName = loginUser.userName
let password = loginUser.password
//引入User的model
const User = mongoose.model('User')
//查找用户名是否存在,如果存在开始比对密码
await User.findOne({userName:userName}).exec().then(async(result)=>{
console.log(result)
if(result){
//console.log(User)
//当用户名存在时,开始比对密码
let newUser = new User() //因为是实例方法,所以要new出对象,才能调用
await newUser.comparePassword(password,result.password)
.then( (isMatch)=>{
//返回比对结果
ctx.body={ code:200, message:isMatch}
})
.catch(error=>{
//出现异常,返回异常
console.log(error)
ctx.body={ code:500, message:error}
})
}else{
ctx.body={ code:200, message:'用户名不存在'}
}
}).catch(error=>{
console.log(error)
ctx.body={ code:500, message:error }
})
})
26.登录的前端交互效果制作和登录状态存储
--Login.vue--
axiosLoginUser(){
this.openLoading=true;
axios({
url:url.login,
method: 'post',
data:{
userName:this.username,
password:this.password
}
})
.then(response=>{
if(response.data.code==200 && response.data.message){ //判断状态和验证结果true
new Promise((resolve,reject)=>{
localStorage.userInfo= {userName:this.username}//设置本地存储
setTimeout(()=>{resolve()},500)//认为延迟,因为localStoage没回调函数
}).then(()=>{
Toast.success('登录成功')
this.$router.push('/')
}).catch(err=>{ //抛出promise错误
Toast.fail('登录状态保存失败')
console.log(err)
})
}else{
Toast.fail('登录失败')
this.openLoading = false;
}
})
.catch((error)=>{ //抛出请求的错误
Toast.fail('登录失败')
this.openLoading=false
})
}
created(){ //加载时检查是否保持了用户,有则表示已经登陆
if(localStorage.userInfo){
Toast.success('您已经登录过了')
this.$router.push('/')
}}
27.商品详细数据的提纯操作
在service文件夹下,新建一个fsJson.js的文件使用node的fs模块,可以轻松把文件读取到程序中,然后进行便利,把有用的数据提取出来,写入到一个新的数组中
const fs = require('fs')
fs.readFile('.goods.json', 'utf8', function(err, data){
let newData= JSON.parse(data)
let i=0
let pushData=[]
newData.RECORDS.map(function(value,index){
if(value.IMAGE1!=null){
i++
console.log(value.NAME)
pushData.push(value)
}
})
console.log(i)
console.log(pushData)
});
fs.writeFile('./newGoods.json',JSON.stringify(pushData),function(err){
if(err) console.log('写文件操作失败');
else console.log('写文件操作成功');
});
28.批量插入商品详情数据到MongoDB中
建立servic/database/schema/Goods.js文件,然后根据我们的数据表结构建立模型
const mongoose = require('mongoose') //引入Mongoose
const Schema = mongoose.Schema //声明Schema
let ObjectId = Schema.Types.ObjectId //声明Object类型
const goodsSchema = new Schema({
ID:{unique:true,type:String},
GOODS_SERIAL_NUMBER:String,
SHOP_ID:String,
SUB_ID:String,
GOOD_TYPE:Number,
STATE:Number,
NAME:String,
ORI_PRICE:Number,
PRESENT_PRICE:Number,
AMOUNT:Number,
DETAIL:String,
BRIEF:String,
SALES_COUNT:Number,
IMAGE1:String,
IMAGE2:String,
IMAGE3:String,
IMAGE4:String,
IMAGE5:String,
ORIGIN_PLACE:String,
GOOD_SCENT:String,
CREATE_TIME:String,
UPDATE_TIME:String,
IS_RECOMMEND:Number,
PICTURE_COMPERSS_PATH:String
},{
collections:'Goods'
})
mongoose.model('Goods',goodsSchema)
新建一个service/appApi/goods.js以后关于商品的操作就都在这个api文件中编写了
const Koa = require('koa')
const app = new Koa()
const Router = require ('koa-router')
let router = new Router()
const mongoose = require('mongoose')
const fs = require('fs')
router.get('/insertAllGoodsInfo',async(ctx)=>{
fs.readFile('./goods.json','utf8',(err,data)=>{
data=JSON.parse(data)
let saveCount=0
const Goods = mongoose.model('Goods')
data.map((value,index)=>{
console.log(value)
let newGoods = new Goods(value)
newGoods.save().then(()=>{
saveCount++
console.log('成功'+saveCount)
}).catch(error=>{
console.log('失败:'+error)
})
})
})
ctx.body="开始导入数据"
})
module.exports=router;
let goods = require('./appApi/goods.js')
router.use('/goods',goods.routes())
运行一下了http://localhost:3000/goods/insertAllGoodsInfo,运行结束后,可以到数据库看一下插入情况
29.商品大类的Shema建立和导入数据库
const mongoose = require('mongoose') //引入Mongoose
const Schema = mongoose.Schema //声明Schema
const categorySchema = new Schema({
ID:{unique:true,type:String},
MALL_CATEGORY_NAME:{type:String},
IMAGE:{type:String},
TYPE:{type:Number},
SORT:{type:Number},
COMMENTS:{type:String}
})
mongoose.model('Category',categorySchema)
1. 用fs读取category.json的数据
2. 把数据进行循环存入数据库。
router.get('/insertAllCategory',async(ctx)=>{
fs.readFile('./data_json/category.json','utf8',(err,data)=>{
data=JSON.parse(data)
let saveCount=0
const Category = mongoose.model('Category')
data.RECORDS.map((value,index)=>{
console.log(value)
let newCategory = new Category(value)
newCategory.save().then(()=>{
saveCount++
console.log('成功'+saveCount)
}).catch(error=>{
console.log('失败:'+error)
})
})
})
ctx.body="开始导入数据
})
然后访问http://localhost:3000/goods/insertAllCategory,数据就可以顺利插入到数据库里
30.商品子类的Shema建立和导入数据库
const mongoose = require('mongoose') //引入Mongoose
const Schema = mongoose.Schema //声明Schema
const categorySubSchema = new Schema({
ID:{unique:true,type:String},
MALL_CATEGORY_ID:{type:String},
MALL_SUB_NAME:{type:String},
COMMENTS:{type:String},
SORT:{type:Number}
})
mongoose.model('categorySubSchema',categorySubSchema)//'CategorySub'表名,数据库里会自动加上S
router.get('/insertCategory_sub',async(ctx)=>{
fs.readFile("./data_json/category_sub.json","utf8",(err,data)=>{
data=JSON.parse(data)
let saveCount=0
const Categorysub = mongoose.model('categorySubschema') //把Category这个表模块引过来
data.RECORDS.map((value,index)=>{
let newCategorysub = new Categorysub(value)//new一个Category,并把value对象传进去
newCategorysub.save().then(()=>{
saveCount++
console.log('成功'+saveCount)
}).catch(error=>{
console.log('失败'+error)
})
})
})
ctx.body="开始导入Category数据"
})
module.exports = router
直接在service/appApi/goods.js里,新编写一个路由业务逻辑,并用findeOne的形式查找出一条商品数据
router.post('/getDetailGoodsInfo',async(ctx)=>{ //**获取商品详情信息的接口
try{
let goodsId = ctx.request.body.goodsId
const Goods = mongoose.model('Goods')
console.log(goodsId)
let result= await Goods.findOne({ID:goodsId}).exec()
ctx.body={code:200,message:result}
}catch(error){
ctx.body={code:500,message:error}
}
})
新建/src/components/pages/Goods.vue文件 测试接口运行情况,
data(){
return{
goodsId:"775e575ce28a4f89b1dfe2c99eb08ae7",//先用一个数据测试
}
},
created(){
this.getInfo()
},
methods: {
getInfo() {
axios({
url:url.getDetailGoodsInfo,
method:"post",
data:{ goodsId:this.goodsId,}
})
.then(response =>{
console.log(response)
})
.catch(err=>{
console.log(err)
})
}
}
设置路由
import Goods from '@/components/pages/Goods'
routes: [
{path:"/goods",name:"Goods",component:Goods}
]
32.商品详情页路由的制作和参数的传递
------hotgoodComponent.vue------
修改这个文件主要是让它具有跳转能力和传递参数的能力:
1. 在这个组件里我们新加入一个props,接受goodsId.
2. 编写一个页面跳转的方法,这里起名为goGoodsPage
3. 绑定单击事件进行跳转@click='goGoodsPage'
props:["goodsImage","goodsName","goodsPrice","goodsId"],//添加goodsId methods:{ goGoodsPage(){ this.$router.push({name:'Goods',query:{goodsId:this.goodsId}}) //编程式路由 } } 父组件上添加:goodsId="item.goodsId"这个传值
点击热门商品就会跳转到:http://localhost:8080/#/goods?goodsId=fb0f913950944b66a97ae262ad14609a 33.商品详情的页面模板编写 --Good.vue--
title="商品详情" left-text="返回" left-arrow @click-left="onClickLeft" class="navbar-con" /> :src="goodsInfo.IMAGE1" width="100%" /> 暂无评论
import axios from "axios" import url from '@/serviceAPI.config.js' import {Toast} from 'vant' import {toMoney} from '@/filter/moneyFilter.js' export default { data(){ return{ goodsId:"", goodsInfo:{}, } }, filters:{ moneyFilter(money){ return toMoney(money) } }, created(){ this.goodsId = this.$route.query.goodsId this.getInfo() }, methods: { getInfo() { axios({ url:url.getDetailGoodsInfo, method:"post", data:{ goodsId:this.goodsId, } }) .then(response =>{ if(response.data.code== 200 && response.data.message){//一定要多判断,状态为200,而且有数据存在 this.goodsInfo= response.data.message }else{ Toast('服务器错误,数据获取失败') } }) .catch(err=>{ console.log(err) }) }, onClickLeft(){ this.$router.go(-1) //顶部左侧后退 }, }, }
34.商品类别页后台接口编写 //读取大类分类接口 router.get("/getCategoryList",async(ctx)=>{ try{ const Category = mongoose.model("Category") let result = await Category.find().exec() ctx.body={ code:200, message:result } }catch(err){ console.log({code:500,message:err}) } }) //读取小类分类接口 router.post("/getCategorySubList",async (ctx)=>{ try{ let categoryId = ctx.request.body.categoryId const CategorySub = mongoose.model("categorySubschema") //let cateoryId = 2 let result = await CategorySub.find({MALL_CATEGORY_ID:cateoryId}).exec() ctx.body={code:200,message:result} //页面返回 }catch(err){ console.log({code:500,messate:err}) } }) /**根据类别获取商品列表 */ router.get('/getGoodsListByCategorySubID',async(ctx)=>{ try{ //let categorySubId = ctx.request.body.categoryId let categorySubId = '2c9f6c946016ea9b016016f79c8e0000' //测试使用,真正获取是改成POST const Goods = mongoose.model('Goods') let result = await Goods.find({SUB_ID:categorySubId}).exec() ctx.body={code:200,message:result} }catch(err){ ctx.body={code:500,message:err} } }) 34.商品类别页的前端制作 import CategoryList from '@/components/pages/CategoryList' Vue.use(Router) export default new Router({ routes: [ {path: '/',name: 'ShoppingMall',component: ShoppingMall}, {path: '/register',name: 'Register',component: Register}, {path: '/login',name: 'Login',component: Login}, {path: '/Goods',name: 'Goods',component: Goods}, {path: '/CategoryList',name: 'CategoryList',component: CategoryList}, ] }) 新建:CategoryList.vue import axios from 'axios' import url from '@/serviceAPI.config.js' getCategory() { axios({ url:url.getCategoryList, method:'get', }) .then(response=>{ console.log(response) if(response.data.code == 200 && response.data.message ){ }else{ Toast('服务器错误,数据取得失败') } }) .catch(error=>{ console.log(error) }) } 在声明周期里加入getCategory方法 created(){ this.getCategory(); }, -------CategoryList.vue---------- {{item.MALL_CATEGORY_NAME}}
data() { return { category: [], //在data属性里注册category变量为数组类型 categoryIndex:0,//li的颜色索引 } }, methods: { getCategory() { axios({ url:url.getCateGoryList, method:'get', }) .then(response=>{ if(response.data.code == 200 && response.data.message ){ this.category = response.data.message //绑定数据 }else{ Toast('服务器错误,数据取得失败') } }) .catch(error=>{ console.log(error) }) }, clickCategory(index){ this.categoryIndex=index //点击时改变li的颜色索引 }, }, ----css--- .categoryActice{ background-color: #fff; } 36.右侧小分类制作:一二级分类的联动效果制作 @click="clickCategory(index,item.ID)" //点击传入小类 :class="{categoryActice:categoryIndex==index}" v-for="(item , index) in category" :key="index"> {{item.MALL_CATEGORY_NAME}}
//用Vant的Tabs组建实现联动
data() { return { category: [], categoryIndex:0, categorySub:[], //小类类别 active:0, //激活标签的值 } }, //根据大类ID读取小类类别列表 getCategorySubByCategoryID(categoryId){ axios({ url:url.getCateGorySubList, method:'post', data:{categoryId} }) .then(response=>{ console.log(response) if(response.data.code==200 && response.data.message){ this.categorySub=response.data.message this.active=0 } }) .catch(error=>{ console.log(error) }) }, clickCategory(index,categoryId){ //点击时获取小类ID this.categoryIndex=index this.getCategorySubByCategoryID(categoryId) //传给getCategorySubByCategoryID } //刚进入页面就显示第一个小类ID created(){ this.getCategory() this.getCategorySubByCategoryID(1) } v-model="loading" :finished="finished" @load="onLoad" > {{item}}
//上拉加载方法 先用数字模拟一整行,测试结果 onLoad(){ setTimeout(()=>{ for(let i=0;i<10;i++){ this.goodList.push(this.goodList.length+1) } this.loading=false; if (this.goodList.length >= 40) { this.finished = true; } },500) }, mounted(){ let winHeight = document.documentElement.clientHeight this.$refs.leftNav.style.height=winHeight -46-50 +'px' //操作dom this.$refs.listdiv.style.height=winHeight -90-50 +'px' //给与滚动的高度 //document.getElementById("list-div").style.height=winHeight -90-50 +'px' }, //给与基本样式 .list-item{ border-bottom: 1px solid #f0f0f0; background-color: #fff; line-height:100px; } #list-div{ overflow: scroll; } 配置列表页路由
//在template部分利用li标签把数据循环出来