由于之前数据、主页全部放在Home.vue中,不能够实现复用,于是,现在进行拆分,拆分出数据主体(user.vue),侧边栏(aside),顶部栏(Header),这样就可以实现复用,并且可以通过路由实现跳转
1、Aside.vue
- 把侧边栏拿出来
Aside.vue
<template>
<el-menu :default-openeds="['1', '3']" style="min-height:100%;overflow-x:hidden"
background-color="rgb(48,65,86)"
text-color="#fff"
active-text-color="ffd04b"
:collapse-transition="false"
:collapse="isCollapse"
router
class="el-menu-vertical-demo"
>
<div style="height:60px;line-height:60px;text-align:center">
<img src="../assets/logo.png" alt="" style="width:20px;position:relative;top:5px;margin-right: 5px;">
<b style="color:#ccc" v-show="logoTextShow">后台管理系统</b>
</div>
<el-menu-item index="/">
<template slot="title">
<i class="el-icon-house"></i>
<span slot="title">主页</span>
</template>
</el-menu-item>
<el-submenu index="2">
<template slot="title">
<i class="el-icon-menu"></i>
<span slot="title">系统管理</span>
</template>
<el-menu-item index="/user">
<i class="el-icon-s-custom"></i>
<span slot="title">用户管理</span>
</el-menu-item>
</el-submenu>
</el-menu>
</template>
<script>
export default {
name:"Aside",
props:{
isCollapse:Boolean,
logoTextShow:Boolean
}
}
</script>
<style scoped>
</style>
- 在Manager.vue中使用
<!-- 侧边栏 -->
<el-aside :width="sideWidth+'px'" style="background-color: rgb(238, 241, 246);height: 100%;" >
<Aside :isCollapse="isCollapse" :logoTextShow="logoTextShow" ></Aside>
</el-aside>
<script>
import Aside from '@/components/Aside.vue'
export default {
name:'Manage',
components: {Aside},
</script>
- 这样就做到把一些共同的样式拆分出来,并且在页面中引用
- 下面把Header.vue拆出来也是一样
2、Header.vue
- 把顶部栏提取出来
Header.vue
<template>
<div style="font-size: 12px;line-height:60px;display: flex;">
<div style="flex:1;font-size:18px">
<span :class="collapseBtnClass" style="cursor:pointer" @click="collapse"></span>
<el-breadcrumb separator="/" style="display:inline-block;margin-left: 10px;">
<el-breadcrumb-item :to="'/'">首页</el-breadcrumb-item>
<el-breadcrumb-item>{{currentPathName}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-dropdown style="width:70px;cursor:pointer" >
<span>ForU</span><i class="el-icon-arrow-down" style="margin-left:5px"></i>
<el-dropdown-menu slot="dropdown" style="width:100px; text-align:center">
<el-dropdown-item style="font-size:14px;padding:5px 0">个人信息</el-dropdown-item>
<el-dropdown-item style="font-size:14px;padding:5px 0">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
export default{
name:"Header",
props:{
collapseBtnClass:String,
collapse:Function
},
computed:{
currentPathName(){
return this.$store.state.currentPathName; //需要监听的数据
}
},
watch:{
currentPathName(newVal,oldVal) {
console.log(newVal)
}
}
}
</script>
<style scoped>
</style>
- 在Manage.vue中引用
<el-header style="border-bottom: 1px solid #ccc">
<Header :collapseBtnClass="collapseBtnClass" :collapse="collapse"></Header>
</el-header>
<script>
import Aside from '@/components/Aside.vue'
export default {
name:'Manage',
components: {Header},
</script>
3、User.vue
- 把用户数据提取出来,单独做成一个vue,User,实现点击用户管理跳转到User路由
User.vue
<template>
<div>
<div style="padding:10px 0">
<el-input style="width:200px" placeholder="请输入用户名" suffix-icon="el-icon-search" v-model="username"></el-input>
<el-input style="width:200px" placeholder="请输入邮箱" suffix-icon="el-icon-message" class="ml-5" v-model="email"></el-input>
<el-input style="width:200px" placeholder="请输入地址" suffix-icon="el-icon-position" class="ml-5" v-model="address"></el-input>
<el-button class="ml-5" type="primary" @click="load">搜索</el-button>
<el-button type="warning" @click="reset">重置</el-button>
</div>
<div style="margin:10px 0">
<el-button type="primary" @click="handleAdd">新增<i class="el-icon-circle-plus-outline"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定要删除这些内容吗?"
@confirm="delBatch"
>
<el-button type="danger" slot="reference">批量删除<i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
<el-button type="primary">导入<i class="el-icon-top"></i></el-button>
<el-button type="primary">导出<i class="el-icon-bottom"></i></el-button>
</div>
<el-table :data="tableData" border stripe :header-cell-calss-name="'headerBg'" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="ID" width="80"></el-table-column>
<el-table-column prop="username" label="用户名" width="140"></el-table-column>
<el-table-column prop="nickname" label="昵称" width="120"></el-table-column>
<el-table-column prop="email" label="邮箱" ></el-table-column>
<el-table-column prop="phone" label="电话" ></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope" >
<el-button type="success" @click="handleUpdate(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定要删除吗?"
@confirm="handleDelete(scope.row.id)"
>
<el-button type="danger" slot="reference">删除<i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<div style="padding:10px 0">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[2, 4, 6, 10]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
<el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
<el-form label-width="80px" size="small">
<el-form-item label="用户名" >
<el-input v-model="form.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="昵称" >
<el-input v-model="form.nickname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="邮箱" >
<el-input v-model="form.email" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="电话" >
<el-input v-model="form.phone" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="地址" >
<el-input v-model="form.address" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default{
name:"User",
data() {
return {
tableData:[],
total: 0 ,
pageNum:1,
pageSize:2,
username:"",
email:"",
address:"",
form:{},
dialogFormVisible:false,
multipleSelection:[]
}
},
created(){
this.load()
},
methods:{
load(){
this.request.get("/user/page",{
params:{
pageNum:this.pageNum,
pageSize:this.pageSize,
username:this.username,
email:this.email,
address:this.address
}
}).then(res=>{
console.log(res)
this.tableData=res.records
this.total=res.total
})
},
save(){
this.request.post("/user",this.form).then(res=>{
if(res){
this.$message.success("保存成功!")
this.dialogFormVisible=false
this.load()
}else{
this.$message.error("保存失败!")
}
})
},
handleAdd(){
this.dialogFormVisible=true
this.form={}
},
handleUpdate(row){
this.form={...row}
this.dialogFormVisible=true
},
handleDelete(id){
this.request.delete("/user/" + id).then(res=>{
if(res){
this.$message.success("删除成功!")
this.load()
}else{
this.$message.error("删除失败!")
}
})
},
delBatch(){
let ids=this.multipleSelection.map(v=>v.id) //把对象数组转化为id数组【1,2,3】
request.post("/user/del/batch",ids).then(res=>{
if(res){
this.$message.success("批量删除成功!")
this.load()
}else{
this.$message.error("批量删除失败!")
}
})
},
handleSelectionChange(val){
this.multipleSelection=val
},
reset(){
this.username=""
this.email=""
this.address=""
this.load()
},
handleSizeChange(pageSize){
this.pageSize=pageSize
this.load()
},
handleCurrentChange(pageNum){
this.pageNum=pageNum
this.load()
}
}
}
</script>
<style>
.headerBg{
background: #eee!important;
}
</style>
- 在manage.vue中使用路由控制
<el-main>
<!-- 页面主体 -->
<!-- 表示当前页面的子路由(在children中设置)会在router-view里面展示 -->
<router-view />
</el-main>
- 去注册路由
router/index.js
import store from '../store';
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
component: () => import('../views/Manage.vue'),
redirect:"/home",
children:[
{
path:'home',
name:'首页',
component:()=>import('../views/Home.vue')
},
{
path: 'user',
name:'用户管理',
component: () => import('../views/User.vue')
}
]
},
{
path: '/about',
name: 'About',
component: ()=>import('../views/AboutView.vue')
}
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
//路由守卫
router.beforeEach((to,from,next)=>{
localStorage.setItem("currentPathName",to.name) //设置当前路由名称
store.commit("setPath")
next()
})
export default router
用户管理和首页均为Manage的子路由,一打开localhost:8080,首先会redirect到/home,也就是首页。点击用户管理的时候,因为**<el-menu-item index=“/user” ** 所以会跳转到user路由,即显示数据
4、完整Vue代码
- components/Aside.vue
<template>
<el-menu :default-openeds="['1', '3']" style="min-height:100%;overflow-x:hidden"
background-color="rgb(48,65,86)"
text-color="#fff"
active-text-color="ffd04b"
:collapse-transition="false"
:collapse="isCollapse"
router
class="el-menu-vertical-demo"
>
<div style="height:60px;line-height:60px;text-align:center">
<img src="../assets/logo.png" alt="" style="width:20px;position:relative;top:5px;margin-right: 5px;">
<b style="color:#ccc" v-show="logoTextShow">后台管理系统</b>
</div>
<el-menu-item index="/">
<template slot="title">
<i class="el-icon-house"></i>
<span slot="title">主页</span>
</template>
</el-menu-item>
<el-submenu index="2">
<template slot="title">
<i class="el-icon-menu"></i>
<span slot="title">系统管理</span>
</template>
<el-menu-item index="/user">
<i class="el-icon-s-custom"></i>
<span slot="title">用户管理</span>
</el-menu-item>
</el-submenu>
</el-menu>
</template>
<script>
export default {
name:"Aside",
props:{
isCollapse:Boolean,
logoTextShow:Boolean
}
}
</script>
<style scoped>
</style>
- components/Header.vue
<template>
<div style="font-size: 12px;line-height:60px;display: flex;">
<div style="flex:1;font-size:18px">
<span :class="collapseBtnClass" style="cursor:pointer" @click="collapse"></span>
<el-breadcrumb separator="/" style="display:inline-block;margin-left: 10px;">
<el-breadcrumb-item :to="'/'">首页</el-breadcrumb-item>
<el-breadcrumb-item>{{currentPathName}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-dropdown style="width:70px;cursor:pointer" >
<span>ForU</span><i class="el-icon-arrow-down" style="margin-left:5px"></i>
<el-dropdown-menu slot="dropdown" style="width:100px; text-align:center">
<el-dropdown-item style="font-size:14px;padding:5px 0">个人信息</el-dropdown-item>
<el-dropdown-item style="font-size:14px;padding:5px 0">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<script>
export default{
name:"Header",
props:{
collapseBtnClass:String,
collapse:Function
},
computed:{
currentPathName(){
return this.$store.state.currentPathName; //需要监听的数据
}
},
watch:{
currentPathName(newVal,oldVal) {
console.log(newVal)
}
}
}
</script>
<style scoped>
</style>
- router/index.js
import store from '../store';
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
component: () => import('../views/Manage.vue'),
redirect:"/home",
children:[
{
path:'home',
name:'首页',
component:()=>import('../views/Home.vue')
},
{
path: 'user',
name:'用户管理',
component: () => import('../views/User.vue')
}
]
},
{
path: '/about',
name: 'About',
component: ()=>import('../views/AboutView.vue')
}
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
//路由守卫
router.beforeEach((to,from,next)=>{
localStorage.setItem("currentPathName",to.name) //设置当前路由名称
store.commit("setPath")
next()
})
export default router
- store/index.js
import store from '../store';
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/',
component: () => import('../views/Manage.vue'),
redirect:"/home",
children:[
{
path:'home',
name:'首页',
component:()=>import('../views/Home.vue')
},
{
path: 'user',
name:'用户管理',
component: () => import('../views/User.vue')
}
]
},
{
path: '/about',
name: 'About',
component: ()=>import('../views/AboutView.vue')
}
];
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
//路由守卫
router.beforeEach((to,from,next)=>{
localStorage.setItem("currentPathName",to.name) //设置当前路由名称
store.commit("setPath")
next()
})
export default router
- views/Home.vue
<template>
<div>
<h1>这是主页</h1>
</div>
</template>
<script>
export default{
name:"Home"
}
</script>
- views/Manage.vue
<template>
<el-container style="height: 100vh; border: 1px solid #eee">
<!-- 侧边栏 -->
<el-aside :width="sideWidth+'px'" style="background-color: rgb(238, 241, 246);height: 100%;" >
<Aside :isCollapse="isCollapse" :logoTextShow="logoTextShow" ></Aside>
</el-aside>
<el-container>
<!-- 菜单栏 -->
<el-header style="border-bottom: 1px solid #ccc">
<Header :collapseBtnClass="collapseBtnClass" :collapse="collapse"></Header>
</el-header>
<el-main>
<!-- 页面主体 -->
<!-- 表示当前页面的子路由(在children中设置)会在router-view里面展示 -->
<router-view />
</el-main>
</el-container>
</el-container>
</template>
<script>
import Aside from '@/components/Aside.vue'
import Header from '@/components/Header.vue'
export default {
name:'Manage',
components: {Aside,Header},
data() {
return {
collapseBtnClass:'el-icon-s-fold' ,
isCollapse:false,
sideWidth:200 ,
logoTextShow:true
}
},
methods:{
collapse(){ //点击收缩按钮触发
this.isCollapse=!this.isCollapse
if(this.isCollapse){ //收缩
this.sideWidth=64
this.collapseBtnClass='el-icon-s-unfold'
this.logoTextShow=false
}else{ //展开
this.sideWidth = 200
this.collapseBtnClass='el-icon-s-fold'
this.logoTextShow=true
}
}
}
}
</script>
- views/User.vue
<template>
<div>
<div style="padding:10px 0">
<el-input style="width:200px" placeholder="请输入用户名" suffix-icon="el-icon-search" v-model="username"></el-input>
<el-input style="width:200px" placeholder="请输入邮箱" suffix-icon="el-icon-message" class="ml-5" v-model="email"></el-input>
<el-input style="width:200px" placeholder="请输入地址" suffix-icon="el-icon-position" class="ml-5" v-model="address"></el-input>
<el-button class="ml-5" type="primary" @click="load">搜索</el-button>
<el-button type="warning" @click="reset">重置</el-button>
</div>
<div style="margin:10px 0">
<el-button type="primary" @click="handleAdd">新增<i class="el-icon-circle-plus-outline"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定要删除这些内容吗?"
@confirm="delBatch"
>
<el-button type="danger" slot="reference">批量删除<i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
<el-button type="primary">导入<i class="el-icon-top"></i></el-button>
<el-button type="primary">导出<i class="el-icon-bottom"></i></el-button>
</div>
<el-table :data="tableData" border stripe :header-cell-calss-name="'headerBg'" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55"></el-table-column>
<el-table-column prop="id" label="ID" width="80"></el-table-column>
<el-table-column prop="username" label="用户名" width="140"></el-table-column>
<el-table-column prop="nickname" label="昵称" width="120"></el-table-column>
<el-table-column prop="email" label="邮箱" ></el-table-column>
<el-table-column prop="phone" label="电话" ></el-table-column>
<el-table-column prop="address" label="地址"></el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope" >
<el-button type="success" @click="handleUpdate(scope.row)">编辑 <i class="el-icon-edit"></i></el-button>
<el-popconfirm
class="ml-5"
confirm-button-text='确定'
cancel-button-text='我再想想'
icon="el-icon-info"
icon-color="red"
title="您确定要删除吗?"
@confirm="handleDelete(scope.row.id)"
>
<el-button type="danger" slot="reference">删除<i class="el-icon-remove-outline"></i></el-button>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<div style="padding:10px 0">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageNum"
:page-sizes="[2, 4, 6, 10]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
<el-dialog title="用户信息" :visible.sync="dialogFormVisible" width="30%">
<el-form label-width="80px" size="small">
<el-form-item label="用户名" >
<el-input v-model="form.username" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="昵称" >
<el-input v-model="form.nickname" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="邮箱" >
<el-input v-model="form.email" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="电话" >
<el-input v-model="form.phone" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="地址" >
<el-input v-model="form.address" autocomplete="off"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default{
name:"User",
data() {
return {
tableData:[],
total: 0 ,
pageNum:1,
pageSize:2,
username:"",
email:"",
address:"",
form:{},
dialogFormVisible:false,
multipleSelection:[]
}
},
created(){
this.load()
},
methods:{
load(){
this.request.get("/user/page",{
params:{
pageNum:this.pageNum,
pageSize:this.pageSize,
username:this.username,
email:this.email,
address:this.address
}
}).then(res=>{
console.log(res)
this.tableData=res.records
this.total=res.total
})
},
save(){
this.request.post("/user",this.form).then(res=>{
if(res){
this.$message.success("保存成功!")
this.dialogFormVisible=false
this.load()
}else{
this.$message.error("保存失败!")
}
})
},
handleAdd(){
this.dialogFormVisible=true
this.form={}
},
handleUpdate(row){
this.form={...row}
this.dialogFormVisible=true
},
handleDelete(id){
this.request.delete("/user/" + id).then(res=>{
if(res){
this.$message.success("删除成功!")
this.load()
}else{
this.$message.error("删除失败!")
}
})
},
delBatch(){
let ids=this.multipleSelection.map(v=>v.id) //把对象数组转化为id数组【1,2,3】
request.post("/user/del/batch",ids).then(res=>{
if(res){
this.$message.success("批量删除成功!")
this.load()
}else{
this.$message.error("批量删除失败!")
}
})
},
handleSelectionChange(val){
this.multipleSelection=val
},
reset(){
this.username=""
this.email=""
this.address=""
this.load()
},
handleSizeChange(pageSize){
this.pageSize=pageSize
this.load()
},
handleCurrentChange(pageNum){
this.pageNum=pageNum
this.load()
}
}
}
</script>
<style>
.headerBg{
background: #eee!important;
}
</style>
- 这些就是所有的前端代码,慢慢的调试,慢慢的找错误,最后一定可以达到这样的页面效果。
5、store/index.js
- 因为使用到了监听,如果没有store这个文件夹的,可以下载一个vuex
npm install vuex --save
- 创建一个文件夹 store
- 在store里创建文件 index.js
index.js
import Vue from "vue";
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store(
{
state:{
currentPathName:''
},
mutations:{
setPath(state){
state.currentPathName=localStorage.getItem("currentPathName")
}
}
}
)
export default store
- 在main.js中引入
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui'
import "element-ui/lib/theme-chalk/index.css"
import './assets/global.css'
import request from "@/utils/request"
import store from './store'
Vue.config.productionTip = false
Vue.use(ElementUI,{size:"mini"});
Vue.prototype.request=request
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')