- 本期任务是编写数据用户管理页面(Users)。
- 编写数据景点管理页面(Tours)页面。
- 编写数据个人设置页面(Profile)页面。
1 编写用户管理页面
修改Users.vue:
<template>
<div class="users-container">
<el-card class="box-card">
<div slot="header" class="header">
<span>用户管理</span>
<el-button style="float: right; " type="primary" @click="handleAddUser">添加用户</el-button>
</div>
<el-table :data="users" style="width: 100%">
<el-table-column prop="id" label="ID" width="50"></el-table-column>
<el-table-column prop="name" label="姓名" width="180"></el-table-column>
<el-table-column prop="email" label="邮箱"></el-table-column>
<el-table-column label="操作" width="180">
<template slot-scope="scope">
<el-button @click="handleEditUser(scope.row)" type="text" size="small">编辑</el-button>
<el-button @click="handleDeleteUser(scope.row)" type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog title="添加用户" :visible.sync="dialogVisible">
<el-form :model="form">
<el-form-item label="姓名" :label-width="formLabelWidth">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="邮箱" :label-width="formLabelWidth">
<el-input v-model="form.email"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSaveUser">保存</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
users: [
{ id: 1, name: '张三', email: '[email protected]' },
{ id: 2, name: '李四', email: '[email protected]' },
{ id: 3, name: '王五', email: '[email protected]' }
],
dialogVisible: false,
form: {
name: '',
email: ''
},
formLabelWidth: '80px'
};
},
methods: {
handleAddUser() {
this.dialogVisible = true;
this.form = { name: '', email: '' };
},
handleEditUser(user) {
this.dialogVisible = true;
this.form = { ...user };
},
handleDeleteUser(user) {
this.users = this.users.filter(u => u.id !== user.id);
},
handleSaveUser() {
if (this.form.id) {
// Edit existing user
const index = this.users.findIndex(u => u.id === this.form.id);
if (index !== -1) {
this.$set(this.users, index, { ...this.form });
}
} else {
// Add new user
const newUser = { ...this.form, id: this.users.length + 1 };
this.users.push(newUser);
}
this.dialogVisible = false;
}
}
};
</script>
<style scoped>
.users-container {
padding: 20px;
}
.header{
display: flex;
justify-content: space-between;
align-items: center;
}
</style>
效果:
2 编写景点管理页面
新建Tours.vue:
<template>
<div class="tours-container">
<el-card class="box-card">
<div slot="header" class="header">
<span>旅游景点管理</span>
<el-button type="primary" @click="handleAddTour">添加景点</el-button>
</div>
<el-table :data="tours" style="width: 100%">
<el-table-column prop="name" label="景点名称" width="180"></el-table-column>
<el-table-column prop="alias" label="别名" width="180"></el-table-column>
<el-table-column prop="reviewCount" label="评论数" width="100"></el-table-column>
<el-table-column prop="rating" label="评分" width="100"></el-table-column>
<el-table-column prop="featuredReview" label="精选评论"></el-table-column>
<el-table-column prop="country" label="国家" width="120"></el-table-column>
<el-table-column prop="city" label="城市" width="120"></el-table-column>
<el-table-column label="操作" width="180">
<template slot-scope="scope">
<el-button @click="handleEditTour(scope.row)" type="text" size="small">编辑</el-button>
<el-button @click="handleDeleteTour(scope.row)" type="text" size="small">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<el-dialog title="编辑景点" :visible.sync="dialogVisible">
<el-form :model="form">
<el-form-item label="景点名称" :label-width="formLabelWidth">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="别名" :label-width="formLabelWidth">
<el-input v-model="form.alias"></el-input>
</el-form-item>
<el-form-item label="评论数" :label-width="formLabelWidth">
<el-input v-model="form.reviewCount" type="number"></el-input>
</el-form-item>
<el-form-item label="评分" :label-width="formLabelWidth">
<el-input v-model="form.rating" type="number"></el-input>
</el-form-item>
<el-form-item label="精选评论" :label-width="formLabelWidth">
<el-input v-model="form.featuredReview"></el-input>
</el-form-item>
<el-form-item label="国家" :label-width="formLabelWidth">
<el-input v-model="form.country"></el-input>
</el-form-item>
<el-form-item label="城市" :label-width="formLabelWidth">
<el-input v-model="form.city"></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSaveTour">保存</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
tours: [
{ id: 1, name: '东京迪士尼度假区', alias: 'Tokyo Disney Resort', reviewCount: 1500, rating: 4.8, featuredReview: '非常美丽的景点', country: '日本', city: '东京' },
{ id: 2, name: '东京塔', alias: 'Tokyo Tower', reviewCount: 2500, rating: 4.9, featuredReview: '历史悠久,气势恢宏', country: '日本', city: '东京' },
{ id: 3, name: '三鹰之森吉卜力美术馆', alias: 'Ghibli Museum', reviewCount: 1800, rating: 4.7, featuredReview: '象征自由的地标', country: '日本', city: '东京' }
],
dialogVisible: false,
form: {
name: '',
alias: '',
reviewCount: 0,
rating: 0,
featuredReview: '',
country: '',
city: ''
},
formLabelWidth: '100px'
};
},
methods: {
handleAddTour() {
this.dialogVisible = true;
this.form = { name: '', alias: '', reviewCount: 0, rating: 0, featuredReview: '', country: '', city: '' };
},
handleEditTour(tour) {
this.dialogVisible = true;
this.form = { ...tour };
},
handleDeleteTour(tour) {
this.tours = this.tours.filter(t => t.id !== tour.id);
},
handleSaveTour() {
if (this.form.id) {
const index = this.tours.findIndex(t => t.id === this.form.id);
if (index !== -1) {
this.$set(this.tours, index, { ...this.form });
}
} else {
const newTour = { ...this.form, id: this.tours.length + 1 };
this.tours.push(newTour);
}
this.dialogVisible = false;
}
}
};
</script>
<style scoped>
.tours-container {
padding: 20px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
.dialog-footer {
text-align: right;
}
</style>
效果:
3 编写个人设置页面
新建Profile.vue:
<template>
<div class="profile-settings">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>个人设置</span>
</div>
<el-form :model="form" label-width="100px" :rules="rules" ref="profileForm">
<el-form-item label="用户名" prop="username">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input v-model="form.age" type="number"></el-input>
</el-form-item>
<el-form-item label="职业" prop="profession">
<el-input v-model="form.profession"></el-input>
</el-form-item>
<el-form-item label="签名" prop="signature">
<el-input type="textarea" v-model="form.signature"></el-input>
</el-form-item>
<el-form-item label="地址" prop="address">
<el-input v-model="form.address"></el-input>
</el-form-item>
<el-form-item label="手机" prop="phone">
<el-input v-model="form.phone"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">保存</el-button>
<el-button @click="onReset">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
form: {
username: '',
age: '',
profession: '',
signature: '',
address: '',
phone: '',
email: ''
},
rules: {
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
age: [
{ required: true, message: '请输入年龄', trigger: 'blur' }
],
profession: [
{ required: true, message: '请输入职业', trigger: 'blur' }
],
phone: [
{ required: true, message: '请输入手机号码', trigger: 'blur' },
{ pattern: /^1[3456789]\d{9}$/, message: '手机号码格式不正确', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
]
}
};
},
methods: {
onSubmit() {
this.$refs.profileForm.validate((valid) => {
if (valid) {
alert('保存成功');
} else {
console.log('error submit!!');
return false;
}
});
},
onReset() {
this.$refs.profileForm.resetFields();
}
}
};
</script>
<style scoped>
.profile-settings {
padding: 20px;
}
</style>
效果:
4 修改router文件
修改router/index.js ,优化了一下之前的导入方式改为使用箭头函数来动态引入,这样项目消耗的资源更少:
const routes = [
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
component:()=> import('@/views/Dashboard'),
name: 'Dashboard'
},
{
path: 'users',
component:()=> import('@/views/Users'),
name: 'Users'
},
{
path: 'profile',
component:()=> import('@/views/Profile'),
name: 'Users'
},
{
path: 'tours',
component:()=> import('@/views/Tours'),
name: 'Tours'
}
// 其他子路由
]
},
// 其他路由
];
5 修改Layout.vue
由于新增了页面,因此菜单也需要修改
<el-menu-item index="/dashboard" @click="navigateTo('/dashboard')">
<i class="el-icon-s-marketing"></i>
数据驾驶舱</el-menu-item>
<el-menu-item index="/tours" @click="navigateTo('/tours')">
<i class="el-icon-s-promotion"></i>
景点管理</el-menu-item>
<el-menu-item index="/users" @click="navigateTo('/users')">
<i class="el-icon-s-custom"></i>
用户管理</el-menu-item>
<el-menu-item index="/profile" @click="navigateTo('/profile')">
<i class="el-icon-s-tools"></i>
个人设置</el-menu-item>
前端整体效果:
6 美化按钮,自定义按钮的颜色
为了酷炫(帅是一辈子的事),我们修改el-button=primary的配色为黑金色,
在assets/styles下新建global.css:
/* 全局覆盖 Element UI 按钮样式 */
.el-button--primary {
background-color: #545c64 !important; /* 黑色背景 */
border-color: #000000 !important; /* 黑色边框 */
color: #ffd04b !important; /* 金色文字 */
}
.el-button--primary:hover, .el-button--primary:focus {
background-color: #333333 !important; /* 深黑色背景 */
border-color: #333333 !important; /* 深黑色边框 */
color: #ffd04b !important; /* 金色文字 */
}
在main.js中引入上述文件
import './assets/styles/global.css'; // 引入全局样式覆盖文件
修改后的按钮效果:
7 修复BUG
-
打开对话框可以明显发现页面右侧会有抖动
导致这个问题的原因是页面body样式有一个margin 8px的样式,修改方法也是非常简单,在index.html中修改:
<body style="margin: 0;">
-
菜单栏边缘有一侧白色的边距,这个是由于我们之前设置container的时候有一个1px 的边框颜色,使用深色的菜单栏背景就能看出来了,所以删掉下面的样式:
.container{ height: 100vh; /*border: 1px solid #eee;*/ }
-
菜单栏active的问题,我们点击用户管理,然后再刷新页面,发现激活的菜单栏变成数据驾驶舱了,其实就是
activeIndex
这个变量刷新页面后变成初始值了,所以修改方式也非常简单,在页面加载完成后给他赋予当前的路由就可以了: -
mounted() { console.log('当前路径:', this.$route.path) this.activeIndex = this.$route.path },