参考大神Vue连接MSSQL Server数据库 vue怎么连接mysql数据库_mob6454***627440的技术博客_51CTO博客的博文,点赞!
1.安装Vue3 :
- C:\Users\David>vue create shopping
c:\vue create shopping
1.选 Manually select features
2.按 空格键 选
(*) Babel
(*) TypeScript
( ) Progressive Web App (PWA) Support
(*) Router
>(*) Vuex
( ) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing
3.选 3.x
4.选 Use class-style ***ponent syntax? (y/N) 按y
5.选 Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? (Y/n) Y
6.Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) Y
7.ESLint with error prevention only 按enter
8.Lint on save 按enter
9.In dedicated config files 按enter
10.Save this as a preset for future projects? (y/N) 按N
生成shopping项目。
- 安装插件,如下:
C:\Users\David>npm install axios flexible less-loader mysql express --save
"dependencies": {
"axios": "^1.6.7",
"core-js": "^3.8.3",
"express": "^4.18.2",
"flexible": "^0.1.20",
"less-loader": "^12.2.0",
"lib-flexible": "^0.3.2",
"mysql": "^2.18.1",
"vant": "^4.8.5",
"vue": "^3.2.13",
"vue-class-***ponent": "^8.0.0-0",
"vue-property-decorator": "^9.1.2",
"vue-router": "^4.0.3",
"vuex": "^4.0.0"
},
安装后:
2.Vue3前端
- 前端接口封装
|-- utils
|-- server.ts
|-- request.ts
- server.ts 文件:这里面有Toast坑,下面代码 Toast 死到里面出不来了。
//请求拦截
Service.interceptors.request.use((config)=>{
//请求成功发送
Toast({
type:'loading',
message: '加载中...'
})
return config
},(error)=>{
console.log(error)
})
主要的原因是vant从3版本更新到4版本。调用代码差异导致。参考了大神:vant报错 Uncaught TypeError: Toast is not a function_typeerror: util.showerrortoast is not a function-CSDN博客 博文
所以把更改引用1: import { showToast,closeToast } from 'vant'; 2 把引用方法给成 showToast,closeToast 成功!
如下:
import axios from 'axios'
import { showToast,closeToast } from 'vant';
//创建请求实例
const Service = axios.create({
timeout:5000,
baseURL: '/api', //'http://127.0.0.1:3000', //process.env.VUE_APP_BASE_API,
headers:{
'Content-Type':'application/json;charset:utf-8'
}
})
//请求拦截
Service.interceptors.request.use((config)=>{
//请求成功发送
showToast({
type:'loading',
message: '加载中...'
})
return config
},(error)=>{
console.log(error)
})
//相应拦截
Service.interceptors.response.use((response)=>{
console.log(response)
closeToast();
if(response.status == 200){
return response
}else{
showToast(response.data.message || "网络出错!")
return response.data
}
},()=>{
closeToast();
})
//暴露实例
// export default Service
//暴露方法
interface configType{
url:string,
data?:any /*,
headers?:any */
}
export const put = (config:configType)=>{
return Service({
...config,
method:'put',
data:JSON.stringify(config.data)
})
}
export const post = (config:configType)=>{
return Service({
...config,
method:'post',
data:config.data
})
}
export const get = (config:configType)=>{
return Service({
...config,
method:'get',
params:config.data
})
}
//删除请求不能data传参
export const del = (config:configType)=>{
return Service({
...config,
method:'delete'
})
}
- request.ts 文件:
import {get,del,put,post} from './server'
export const loginApi = (data:any)=>{
/* return put({
url:"/user/query",
data
}) */
return get({
url:"/user/login",
data
})
}
export const registApi = (data:any)=>{
return put({
url:"/user/register",
data
})
}
- 前端login.vue文件
<template>
<div class="login_wrap">
<img class="bg_img" src="../assets/image/pic_1242x2688.jpg" alt="">
<div class="form_wrap">
<img class="ch_img" src="../assets/image/3.jpg" alt="">
<!-- <van-cell-group> -->
<van-field class="login_input" v-model="userName" placeholder="请输入用户名" />
<!-- <van-field v-model="defaultValue" label="标题" placeholder="提示性文字" /> -->
<!-- </van-cell-group> -->
<!-- <van-cell-group> -->
<van-field class="login_input" v-model="password" placeholder="请输入密码" />
<!-- </van-cell-group> -->
<van-button type="primary" v-if="LoginStatus==1" @click="handleLogin">登录</van-button>
<van-button type="primary" v-if="LoginStatus==2" @click="handleRegister">注册</van-button>
<p class="form_login_reg" @click="handleChangeStatus">
{{LoginStatus==1?"去 注册":"去 登陆"}}
</p>
</div>
</div>
</template>
<script>
import {Vue,Options} from 'vue-class-***ponent'
import {loginApi,registApi} from '@/utils/request'
import {Toast} from 'vant'
@Options({})
export default class login extends Vue{
userName = ''
password = ''
//LoginStatus码 1:表示登录 2:表示注册
LoginStatus = 1
handleChangeStatus(){
this.LoginStatus = this.LoginStatus == 1 ? 2 : 1
}
handleLogin(){
loginApi({
"username":this.userName,
"password":this.password
})
console.log('用户名:'+this.userName +' 密码:'+this.password)
}
handleRegister(){
registApi({
"userName":this.username,
"password":this.password
}).then((res)=>{
console.log('注册信息:',res)
if(res.code == 200){
Toast('注册成功!')
}
})
}
}
</script>
3.Vue3后端+postman工具测试
- 后端目录结构
|-- server
|-- api
|-- userApi.js
|-- goodsApi.js
|-- db.js
|-- index.js
|-- sqlMap.js
- db.js为数据库连接配置
//db.js为数据库连接配置
// 数据库连接配置db.js
module.exports = {
mysql: {
host: '127.0.0.1', //mysql连接ip地址
user: 'root',
password: 'root', //mySql用户名密码
database: 'mbg', //mySql数据库名
port: '3306' //mysql连接端口
}
}
- api文件夹下 userApi.js 是为与数据库的各个表连接接口,每一个子文件为一个数据库中一个表
//api文件夹为与数据库的各个表连接接口,每一个子文件为一个数据库中一个表
//userApi.js
var models = require('../db')
var express = require('express')
var router = express.Router()
var mysql = require('mysql')
var $sql = require('../sqlMap')
// 连接数据库
var conn = mysql.createConnection(models.mysql)
conn.connect()
var jsonWrite = function (res, ret) {
if (typeof ret === 'undefined') {
res.json({
code: '1',
msg: '操作失败'
})
} else {
res.json(ret)
}
}
module.exports = router
- sqlMap.js 是后端操作数据库的指令文件
//sqlMap.js
var sqlMap = {
// 用户
admin_user: {
add: 'insert into t_user(username,password) values(?, ?)',
delete: 'delete from t_user where id = ?',
all: 'select * from t_user',
queryByName:'select * from t_user where username = ?'
},
module.exports = sqlMap;
- index.js用来定义与监听后端服务器
//index.js用来定义与监听后端服务器
// node 后端服务器
const userApi = require('./api/userApi');
const fs = require('fs');
const path = require('path');
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
// 后端api路由
app.use('/api/user', userApi);
// 监听端口
app.listen(3000);
console.log('su***ess listen at port:3000......');
- 在server的目录下,执行:node index.js
PS C:\Users\David\VueProject\shoppingProject\src\server> node index
su***ess listen at port:3000......
代码没问题,会输出:su***ess listen at port:3000......
postman设置:
- Hearders输入参数
- Body输入参数
{
"host": "localhost",
"user": "root",
"password": "root",
"database": "mbg"
}
- Params输入参数
- 关键点是:输入链接网址是什么?
//index.js 下面的 /api/user
app.use('/api/user', userApi);
// 监听端口
app.listen(3000);
//userApi.js 下面的 /query
router.get('/login', (req, res) => {
//综上postman上的地址:http://localhost:3000/api/user/query?username=lucy
//index.js下面的 /api/user
app.use('/api/user', userApi);
// 监听端口
app.listen(3000);
//userApi.js 下面的 /query
router.get('/login', (req, res) => {
//综上postman上的地址:http://localhost:3000/api/user/query?username=lucy
PS C:\Users\David\VueProject\shoppingProject\src\server> node index
su***ess listen at port:3000......
{ username: 'lucy' }
[
RowDataPacket {
id: 1,
username: 'lucy',
password: '123',
email: '123@126.***'
}
]
- 遇到Vue3中用到params传值时,发现传值失败,并给出一个报错Discarded invalid param(s) "XXX" when navigating.
参考了大神:Vue3中路由传值使用params传值失败报错_discarded invalid param(s) "id" when navigating.-CSDN博客博文,深受启发。利用history.state解决问题
navBar.vue 设置
this.router.push({
name:'goodsList',
state:{
key:this.searchValue
}
})
<template>
<div>
<van-nav-bar fixed placeholder>
<template #title>
<van-search v-model="searchValue" placeholder="请输入搜索关键词"
@search="handleSearch"/>
<!-- @search="divSearch" -->
</template>
</van-nav-bar>
</div>
</template>
<script lang="ts">
import {Vue,Options} from 'vue-class-***ponent'
//安装vue-property-decorator
import {Prop,Emit} from 'vue-property-decorator'
import {useRouter,useRoute} from 'vue-router'
import {useStore} from 'vuex'
@Options({})
export default class tabBar extends Vue{
// store = useStore()
router = useRouter()
searchValue = ''
handleSearch = ():void=>{
//输入的值传给父组件,同时在父组件声明一个方法,且绑定子组件,子组件触发把数据传递给父组件
// this.searchValue
this.divSearch()
// console.log('navBar框数据',this.searchValue)
this.router.push({
name:'goodsList',
state:{
key:this.searchValue
}
})
}
@Emit() //使用Emit触发父组件,跟父组件的名字要一致
divSearch():string{
console.log('emit数据',this.searchValue)
return this.searchValue
}
}
</script>
<style lang="less" scoped>
:deep .van-nav-bar__title{
max-width: 100%;
width: 100%;
}
</style>
goodsList.vue:
key = history.state.key as string
this.searchParams.goodsName = this.key
<template>
<div class="">
<h3>商品列表</h3>
<NavBar @divSearch="handleSearch" />
<TabBar />
</div>
</template>
<script lang="ts">
import {Options,Vue} from 'vue-class-***ponent'
import { useRouter,useRoute } from 'vue-router'
import { useStore } from 'vuex';
import TabBar from '@/***ponents/tabBar.vue';
import NavBar from '@/***ponents/navBar.vue';
import {goodsListType} from '@/utils/interface'
import {getGoodsSearchApi} from '@/utils/request'
type paramsType = {
goodsName:string,
currentPage:number,
size:number
}
@Options({
***ponents:{
TabBar,
NavBar
}
})
export default class goodsDes extends Vue{
searchParams:paramsType = {
goodsName:'',
currentPage:1,
size:5
}
goodsList:goodsListType[] = []
store = useStore()
route = useRoute()
key = history.state.key as string
handleSearch(val?:string):void{
// this.key = val
//判断当前页面navBar有参数,则this.searchParams.goodsName = val
val ? (this.searchParams.goodsName = val):null
// this.searchParams.goodsName = history.state.key
//搜索对应商品
getGoodsSearchApi(this.searchParams).then((res:any)=>{
console.log('2.商品数据',res)
})
}
//
public mounted(): void {
//输入navBar 路由页面传过来的key值
this.searchParams.goodsName = this.key
this.handleSearch()
}
}
</script>
4.数据库:建立本地数据库