本项目是 学习Bilibili 全栈之巅 视频教程相关源码和体会
https://gitee.com/blaunicorn/node-vue-wangzherongyao
持续更新中…
2.6 父类子类增删改查
2.6.1 编辑页面添加选择父类按钮
<template>
<div>
...
<el-form-items label="上级分类">
<el-select v-model="model.parent">
//上级分类选择,label是显示的内容,value是实际保存的值
<el-option v-for="item in parents" :key="item._id" :label="item.name" :value="item._id"></el-option>
</el-select>
</el-form-items>
</div>
</template>
<script>
export default {
data(){
return{
parents: []
}
},
methods:{
async fetchParents(){
const res = await this.$http.get(`/categories`)
this.parents = res.data
}
},
created(){
this.fetchParents()
}
}
</script>
2.6.2 列表页显示父级分类
<el-table-column prop="parent.name" label="上级分类"></el-table-column>
2.6.3 server端模型中添加parent字段
//数据库里面的ID叫Objectid,ref表示关联的模型
parent:{type:mongoose.SchemaTypes.ObjectId,ref:'Category'}
2.6.4 修改后端接口
// populate关联取出
router.get('/categories',async(req,res)=>{
const items = await Category.find().populate('parent').limit(10)
res.send(items)
})
2.7 后端通用CRUD,如果使用,需要保证通用性稳定性和拓展性
2.7.1 添加mergeParams(server\routes\admin\index.js)
//合并URL参数,将父级的参数合并到router里面
const router = express.Router({
mergeParams: true
})
2.7.2 动态获取接口地址并在请求对象上挂载Model属性(server\routes\admin\index.js)
// 动态获取接口地址:resource,中间件处理请求模板
app.use('/admin/api/rest/:resource',async(req,res,next)=>{
const modelName = require('inflection').classify(req.params.resource)
// req.Model是在请求对象上挂载Model属性
req.Model = require(`../../models/${modelName}`)
next()
},router)
2.7.3 后端完整接口代码如下(server\routes\admin\index.js)
module.exports = app =>{
const express = require('express')
const router = express.Router({
//合并URL参数,将父级的参数合并到router里面
mergeParams: true
})
// 增
router.post('/',async(req,res)=>{
const model = await req.Model.create(req.body)
res.send(model)
})
// 改
router.put('/:id',async(req,res)=>{
const model = await req.Model.findByIdAndUpdate(req.params.id,req.body)
res.send(model)
})
//删
router.delete('/:id',async(req,res)=>{
const model = await req.Model.findByIdAndDelete(req.params.id,req.body)
res.send({
success: true
})
})
// 查,populate关联取出
router.get('/',async(req,res)=>{
// const items = await req.Model.find().populate('parent').limit(10)
const queryOptions = {}
if(req.Model.modelName === 'Category'){
queryOptions.populate = 'parent'
}
const items = await req.Model.find().setOptions(queryOptions).limit(10)
res.send(items)
})
router.get('/:id',async(req,res)=>{
const model = await req.Model.findById(req.params.id)
res.send(model)
})
// 动态获取接口地址:resource,中间件处理请求模板
app.use('/admin/api/rest/:resource',async(req,res,next)=>{
// 通用接口的类名转换成数据库一致的方法使用是inflection,把小写的复数名称改成大写开头的单数类名(也可以用lodash去尝试)
const modelName = require('inflection').classify(req.params.resource)
// req.Model是在请求对象上挂载Model属性
req.Model = require(`../../models/${modelName}`)
next()
},router)
ps 通用接口的类名转换成数据库一致的方法使用是inflection,把小写的复数名称改成大写开头的单数类名(也可以用lodash去尝试)
2.7.3 修改前端admin请求接口
//请求接口前面加上/rest(admin\src\views\CategoriesEdit.vue)
//编辑/新建页
this.$http.put(`/rest/categories/${this.id}`,this.model)
this.$http.post('/rest/categories',this.model)
const res = await this.$http.get(`/rest/categories/${this.id}`)
const res = await this.$http.get(`/rest/categories`)
//列表页(admin\src\views\CategoriesList.vue)
const res = await this.$http.get('/rest/categories')
await this.$http.delete(`/rest/categories/${row._id}`)
当通用接口做完后,其他的items和heros的接口也就比较简单了。