前言
第一次使用Vue3+TS+Vite完全独立开发一个管理系统,加上也是第一次完全自己独立搭建后端,算得上是一个全栈项目了吧。数据库选择了mongodb,后端框架使用express。这个系列算记录自己踩的坑提醒以后的自己。
后端注意事项
1. 后端搭建过程
命令行输入mongod启动mongodb数据库,配合MongoDBCompass图形化管理工具插入数据。
npm i express 安装 express框架(网上查阅到npm i 在某个版本之后与 npm i -S 的效果是一样的,待验证,目前看来是一样的。)
在后端目录文件夹中创建app.js作为启动项目的入口文件。
const express = require('express')
const app = express()
const categoryRouter = require('./router/category')
const articleRouter = require('./router/articleList')
app.use(categoryRouter).use(articleRouter)
app.listen(8000, ()=>{
console.log('api server running at 8000 port')
})
在与 app.js同级目录下创建三个目录,分别为用于管理路由的router,用来处理管理路由回调函数的router_handler,以及用于放置初始连接数据库的db目录。
db目录下创建index文件,暴露如下代码
var MongoClient = require("mongodb").MongoClient;
var url = "mongodb://localhost:27017/myblog";
async function database_conn() {
let conn = await MongoClient.connect(url);
const db = conn.db('myblog')
return db
}
module.exports = database_conn
最终暴露的是一个返回数据库的函数。
在router_handler中创建管理路由回调函数的文件,以获取分类列表为例。
先调用从db目录下获取的创建数据库的函数,const 一个常量db来存储。然后连接集合,使用mongodb的查找API,获取结果,把结果返回给请求。然后分别暴露这些函数,注意此处是使用分别暴露,因为这里需要暴露多个函数。
const database_conn = require('../db/index')
exports.getCategory = async (req, res) => {
const db = await database_conn()
let result = await db.collection('category').find().toArray()
res.send({
message: '获取分类列表成功',
data: result
})
console.log('获取分类列表成功了')
}
在router目录下建立管理category的路由
调用express.Router()创建路由,设置路由url对应的回调函数,回调函数从router_handler文件夹下获取
const express = require('express')
const router = express.Router()
const categoryHandler = require('../router_handler/category')
router.get('/categorylist', categoryHandler.getCategory)
module.exports = router
回到前面的app文件中,使用use函数调用路由中间件,完成搭建。
2. axios发送请求与express 接受req参数的坑。
axios发送get请求所携带的参数是params,发送post请求携带的参数应该是data。
express搭建的服务器中,接受get请求发送的params参数是在req.query中。
而使用post发送data参数的时候,express必须配置bodyParser.json()和bodyParser.urlencoded()中间件,才能解析出req.body。
前端注意事项
1. 前端设置proxy代理遇到的坑
在vite项目中设置proxy代理是在vite.config.ts文件夹下
plugins中,Components字段的用途是按需加载antd组件库
server字段的用途:port设置监听的端口号
proxy字段设置代理。
注意前端在使用axios发请求的时候不要携带http://localhost:8000 这样的域名,这样proxy就不会转发了。
勘误:不是不要携带域名,是携带的域名并非端口8000。
在在vue-cli或者vite项目中,proxy的作用是启动一个代理服务器,这个服务器的端口号跟项目端口号一致,例如前端项目端口号为3000,那么代理服务器的端口号也为3000。前端项目发送请求应该发到代理服务器的url,也就是与自身相同的url而非8000端口号。不写域名的情况下,会自动发送到这个代理服务器,因此不写也是可以的。如果写的话就必须写正确,即 http://localhost:3000。
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite';
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
Components({
resolvers: [AntDesignVueResolver()],
}),
],
server:{
port: 3000,
proxy:{
'/api':{
target: 'http://localhost:8000',
changeOrigin: true,
rewrite: (path) => path.replace(/^/api/, ""),
}
}
}
})
2. 前端sideBar侧边栏目录高亮的坑
使用antd组件的侧边栏,遇到需要通过非点击侧边栏的方式跳转路由的时候,侧边栏的高亮并不会跟随路由变化。
此时可以使用watch监听route,当route改变的时候,改变selectedKeys。
watch(route,(newValue, oldValue)=>{
switch (route.path) {
case '/':
selectedKeys.value = ['1']
break
case '/article/list':
selectedKeys.value = ['2']
break
case '/article/write':
selectedKeys.value = ['3']
break
case '/article/category':
selectedKeys.value = ['4']
break
case '/tags':
selectedKeys.value = ['5']
break
default:
break
}
})
这里还有个小注意点:Vue的watch侦听器只能侦听响应式变量或者对象,不能直接去侦听响应式对象的具体属性,例如这里不能直接侦听route.path,只能侦听route。
3. 前端编辑文章页面
使用antd组件的时候 要在选择器组件前面加上label,需要把选择器组件用a-form-item组件包裹在一起,然后在a-form-item中加入label属性
<a-form-item
style="margin-top: 30px"
label="文章分类"
>
<a-select
@change="change"
style="width: 1200px; "
@focus="focus"
>
<a-select-option v-for="item in categories" :key="item._id" :value="item.cateName">{{
item.cateName
}}
</a-select-option>
</a-select>
</a-form-item>
注意这里select组件绑定的change函数,这里的change函数是底层定义过的,因此不需要传参。定义好的函数中第一个参数就是获取到的value值。
const change = (value: string) => {
console.log(value)
}
在这里复习一遍Vue中给绑定事件传参的原则。
如果不需要给绑定事件的函数传参,那么@click后面的只需要写函数名,不需要写括号,在实现的函数中第一个参数就是获取dom元素。
如果需要给绑定的事件传参又需要获取dom元素,那么第一个参数写成 $event,后面传入需要传入的实参,实现的函数中第一个是$event对应的形参,后面的是传入的实参对应的形参。
<a-select @click="click($event, '123')"></a-select>
----------------------------------------------------------------------------
//e对应的就是$event,value对应的就是传入的字符串实参123
const click = (e:HTMLElement, value:string)=>{
console.log('这是元素dom', e, value)
}
4. Vue3嵌套路由和Vite的坑 && Pinia的使用
在用vite构建项目并使用路由懒加载的情况下,页面的加载可能会较慢。
写嵌套路由的时候,children属性可能没有提示。
在路由定义文件下(src/router/index.ts)使用pinia时,需要把pinia实例初始化在beforeEnter属性中,也就是路由守卫中。