1.起步
1.1.前言
这篇文档是跟随腾讯课堂课程:前端教程vuex实现管理系统,给自己写的课堂随笔,仅作记录作用。建议先去vuex官网了解一些基本知识再开始。
本文档可能会出现数据对不上的问题,原因是视频中有不断更改数据,所以后面会对之前的数据库或者页面元素作出调整。然后我自己尝试解决了部分工具版本上的问题,很多地方记录的不详尽,推荐看视频。
主要用到的工具/包有:vue, vuex, npm, nodemon, mysql, element-ui, axios
1.2.初始化项目
-
打开项目位置文件夹,在地址栏输入cmd打开当前目录的控制台,输入以下代码:
vue init webpack vuexms
-
继续在控制台输入指令以安装相关包:
cd vuexms npm i
-
试着运行我们的初始项目:
npm run dev
控制台表明我们的项目运行在了http://localhost:8080,打开就能看到默认的初始界面。
1.3.个性化
- 打开
vuexms\src\App.vue
,这是我们项目的路由出口,同时删掉<template>
中的img
标签和<style>
中的所有内容:
<!-- 这是默认的主页面logo图 -->
<img src="./assets/logo.png">
-
打开
vuexms\src\components\HelloWorld.vue
,这是路由指示的主界面,删除<template>
中的标签。同时,将文件名改为我们需要的login.vue
,然后更改src\router\index.js
中的相关代码。import Vue from 'vue' import Router from 'vue-router' // 引入组件 import login from '@/components/login' // 注册路由 Vue.use(Router) // 导出路由 export default new Router({ routes: [ { path: '/login', name: 'login', component: login } ] })
2.实现登录页
2.1.使用Element
官网地址:Element
-
切换回控制台,
Ctrl+C
暂时停止服务器。npm i element-ui -S
-
找到
src
目录 下的main.js
,添加以下代码// 引入 import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; // 注册 Vue.use(ElementUI);
-
测试是否注册成功,在
login.vue
中加入以下代码,重启服务器:npm run dev
,如果页面中正常加载出了按钮表示注册成功。<el-button>按钮</el-button>
2.2.使用组件
在
element-ui
官网找到合适的表单登录组件,分别将里面的HTML
代码和Javascript
代码放到对应页面,我们这里是login.vue
。-
我们会加入
css
代码让页面更加美观,在这之前应该重置样式来避免一些错误。可以在static
中新建css
文件夹,然后放入合适的reset.css
,然后再在index.html
中引入:<!-- reset.css --> <link rel="stylesheet" href="./static/css/reset.css">
-
自定义数据和样式。
2.3.axios
安装:
npm i axios -S
在main.js
中引入:
// 引入 axios
import axios from 'axios'
// 挂载到 Vue 的原型上
Vue.prototype.axios = axios
在login.vue
中检测:
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 确认是否能打印出信息
console.log(this.axios)
} else {
console.log('error submit!!');
return false;
}
});
},
向后台发送数据并得到响应:
this.axios.post('/api/checklogin', {
username: _this.loginForm.username,
password: _this.loginForm.password
})
.then(response => {
console.log('接收后端响应的数据')
})
2.4.express搭建服务器
实现登录,需要从服务器获取数据,所以我用 express 搭建了一个。
-
确保全局安装了 express,4.X 后的版本需要安装 express-generator。
npm install -g express npm install -g express-generator
在环境变量中添加 path: <u>C:\Users\admin\AppData\Roaming\npm</u>。
-
项目同级目录打开cmd工具:
express server -e cd server npm install
-
打开 server 中的 app.js 添加:
// 监听端口 app.listen(888, () => { console.log('888端口的服务器已经启动...') })
在 server\routes\index.js 中设置:
// 接收请求 router.post('/checklogin', (req, res) => { // 接收用户名和密码 let { username, password} = req.body; console.log(username, password) // 发送响应 res.send('服务器数据') })
因为是跨域请求,在 vuexms\config\index.js 中设置:
proxyTable: { '/api': { target: 'http://localhost:888', // 接口的域名 changeOrigin: true, // 如果是跨域请求,需要配置此项 pathRewrite: { '/api': '' } } }
项目控制台重启项目
npm run dev
服务器控制台启动服务器
node app
-
打开项目页面,输入帐号密码提交后检查服务器控制台和网页响应数据:
至此说明项目和服务器已经联通了,接下来需要比对数据库进行登录验证。
2.5.连接数据库
首先我们需要创建一个数据库,在 计算机 -> 管理 -> 服务 中启动 mysql,新开一个 cmd 控制台窗口:
-
连接mysql
mysql -hlocalhost -uroot -proot
-
新建数据库
show databases; create database vuexms; use vuexms;
-
新建表
create table users ( id int primary key auto_increment, username varchar(50), password varchar(50), realname varchar(50), age int, idType varchar(50) ); desc users;
-
插入数据
insert into users(username, password, realname, age, idType) value('xiaoyao', '123456', '李逍遥', '20', '00001'); insert into users(username, password, realname, age, idType) value('linger', '123456', '赵灵儿', '18', '00002'); select * from users;
然后通过 node 连接数据库:
-
在服务器控制台安装mysql包
npm i mysql -S
-
在 server\routes 路径下新建 conn.js 文件:
// 引入mysql var mysql = require('mysql') // 创建连接 var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', database : 'vuexms' }); // 暴露出去 module.exports = connection
-
在同路径的 index.js 中:
// 引入连接数据库模块 const connection = require('./conn') // 连接数据 connection.connect(() => { console.log('数据库连接成功!') }) router.post('/checklogin', (req, res) => { ... // 执行sql查询 const sqlStr = `select * from users where username='${username}' and password='${password}'` connection.query(sqlStr, (err, data) => { if(err) { console.log(err) }else { res.send(data) } }) })
-
重启服务器,会显示数据库连接成功。提交表单,在 Response 中可以看到发送回来的 data:
-
渲染页面,在 login.vue 中
.then(response => { if(response.data.length) { console.log('接收后端响应的数据', response.data[0].username) _this.$message({ message: '恭喜你,登录成功!', type: 'success' }) }else { _this.$message.error('请检查用户名或密码') } })
3.保存登录数据
3.1.vue异步加载组件
继续在 login.vue 中
.then(response => {
if(...){
...
// 跳转到首页
_this.$router.push('/index')
}
...
})
那么我们需要在 vuexms\src\components 增加一个页面组件 index.vue
<template>
<h1>index</h1>
</template>
...
在路由中配置,并将引入的方式改为异步加载
// 引入组件
// import login from '@/components/login'
// import index from '@/components/index'
// 异步加载
const login = () => import('@/components/login')
const index = () => import('@/components/index')
export default new Router({
routes: [
...
{
path: '/',
name: 'index',
component: index
}
]
})
3.2存入登录用户数据
-
安装 vuex 包,在项目控制台:
npm i vuex -S
-
在 src 目录下新建 vuex 文件夹然后新建 store.js 文件:
// 引入 vuex import Vue from 'vue' import Vuex from 'vuex' // 注册 vue Vue.use(Vuex) // 状态 const state = { userinfo: JSON.parse(localStorage.getItem('userinfo')) } // mutations 用于操作 state const mutations = { // 保存用户数据 SAVE_USERINFO (state, userinfo) { // 把用户数据放到本地存储实现持久化 localStorage.setItem('userinfo', JSON.stringify(userinfo)) state.userinfo = userinfo console.log('赋值后的用户信息:' , state.userinfo) } } // 创建 store 仓库暴露出去 export default new Vuex.Store({ state, mutations })
-
在 src\main.js 中
... import store from './vuex/store' ... new Vue({ ... store, })
-
login.vue
.then(response => { if(...){ ... // 把当前用户数据存入 state _this.$store.commit('SAVE_USERINFO', response.data[0]) ... _this.$router.push('/') } ... })
-
index.vue 主页调用
<template> ... <p>用户信息:{{ $store.state.userinfo }}</p> ... </template>
4.主页
4.1.样式
在 element 中选个喜欢的 container 组件样式粘贴到 components\index.vue 组件中,进行修改调整
4.2.路由跳转
简单添加几个其余的页面组件,例如:userlist.vue, useradd.vue, passwordedit.vue。重要的是实现路由跳转,而在 element-ui 中有 router 属性可以帮助我们节省步骤。
首先,确定需要进行跳转的样式模块,也就是页面左侧的导航栏,在元素中加入 router 属性:
<el-menu :default-openeds="['1']" router>
然后试着点击导航栏目录,网页地址会加上 el-menu-item 元素的 index 属性的值。
然后,在 router\index.js 中:
// 引入
const home = () => import('@/components/home')
const userlist = () => import('@/components/userlist')
const useradd = () => import('@/components/useradd')
const passwordedit = () => import('@/components/passwordedit')
...
routes: [
...
{
path: '/',
redirect: '/home',
name: 'index',
component: index,
children: [
{
path: '/home',
name: 'home',
component: home
},
{
path: '/userlist',
name: 'userlist',
component: userlist
},
{
path: '/useradd',
name: 'useradd',
component: useradd
},
{
path: '/passwordedit',
name: 'passwordedit',
component: passwordedit
},
]
4.3.获取state数据
想要在默认页面得到展示当前用户的一些数据,就要从 state 中获取,vuex 提供了一种更加简单的方式来帮助我们获取到数据,在 components\home.vue 中:
// 引入 mapState
import {mapState} from 'vuex'
export default {
computed: {
// 辅助函数 获取 state 数据
...mapState({
// userinfo: this.$store.state.userinfo
userinfo: state => state.userinfo
})
}
}
5.用户列表页
5.1.触发actions异步获取数据
在 vuexms\src\vuex\store.js 中发起请求:
// 引入 axios
import axios from 'axios'
...
const state = {
...
userList: []
}
const mutations = {
...
// 获取全局的用户数据
GET_USERLIST (state, userList) {
state.userList = userList
}
}
// 定义 actions 异步的主要是 commit mutations,由 mutations 来改变状态
const actions = {
GET_USERLIST({ commit }) {
// 使用 Promise,其他页面可以通过 .then 的方式来保证页面渲染前得到数据
return new Promise((resolve, reject) => {
axios.get('/api/getuserlist').then(response => {
// console.log('获取用户数据列表', response.data)
commit('GET_USERLIST', response.data)
resolve()
})
})
}
}
export default new Vuex.Store({
state,
mutations,
actions
})
在服务端 server\routes\index.js 响应:
// 接收获取用户列表的请求
router.get('/getuserlist', (req, res) => {
// 查询数据库 把当前素有用户数据返回给前端
const sqlStr = 'select * from users'
connection.query(sqlStr, (err, data) => {
if(err) {
throw err
}else {
res.send(data)
}
})
})
检查是否传回数据,在 vuexms\src\components\userlist.vue 中:
created() {
this.$store.dispatch('GET_USERLIST').then(() => {
console.log(this.$store.state.userList)
})
}
5.2.渲染页面
继续操作 userlist.vue 文件:
// 引入辅助函数
import {mapState, mapActions} from 'vuex'
// 删除之前的假数据
data() {
return {
tableData: []
}
},
created() {
// 以下方式冗长不擅于管理
// this.$store.dispatch('GET_USERLIST').then(() => {
// // console.log(this.$store.state.userList)
// // 把全局的 userlist 赋值给 tableData
// // this.tableData = this.$store.state.userList
// })
this.getUserList().then(() => {
this.tableData = this.userList
})
},
methods: {
...mapActions({
getUserList: 'GET_USERLIST'
}),
},
computed: {
...mapState({
userList: state => state.userList
})
}
5.3.过滤
为了使用 getters 属性,在复制本页面用户列表添加到下方,并改为目标用户表,我们做过滤出年龄大于20岁的用户列表这个操作:
data() {
return {
tableData: [],
newtableData: []
};
},
created() {
this.getUserList().then(() => {
...
this.newtableData = this.userList.filter(v => v.age > 20)
});
}
把需要获取的数据定义成全局的,但是效果不变,在 vuex\store.js 中:
// 定义全局共享属性 getter
const getters = {
vipUsers: state => state.userList.filter(v => v.age > 20)
}
export default new Vuex.Store({
...
getters
})
回到 userlist.vue 文件:
created() {
this.getUserList().then(() => {
...
// this.newtableData = this.userList.filter(v => v.age > 20)
this.newtableData = this.$store.getters.vipUsers
});
}
使用 mapGetters 辅助函数使编写更简洁:
import { mapState, mapActions, mapGetters} from "vuex";
...
created() {
this.getUserList().then(() => {
...
this.newtableData = this.vipUsers
});
}
...
computed: {
...mapGetters(['vipUsers']),
...
}
到此,对 vuex 的重要属性就基本都使用了,也搭好了一个简单的管理系统模板。
我有意将它具化成较详尽的资产管理系统,等完成以后发布出来。