前端知识总结,讲师列表前端实现
es6和vue基础知识点
es6语法新特性博客链接
vue基础知识点博客链接
axios博客链接
npm,webpack博客链接
vue-element-admin
而vue-element-admin是基于element-ui 的一套后台管理系统集成方案。
功能:https://panjiachen.github.io/vue-element-admin-site/zh/guide/#功能
GitHub地址:https://github.com/PanJiaChen/vue-element-admin
项目在线预览:https://panjiachen.gitee.io/vue-element-admin
安装
# 解压压缩包
# 进入目录
cd vue-element-admin-master
# 安装依赖
npm install
# 启动。执行后,浏览器自动弹出并访问http://localhost:9527/
npm run dev
vue-admin-template
ueAdmin-template是基于vue-element-admin的一套后台管理系统基础模板(最少精简版),可作为模板进行二次开发。
GitHub地址:https://github.com/PanJiaChen/vue-admin-template
建议:你可以在 vue-admin-template 的基础上进行二次开发,把 vue-element-admin当做工具箱,想要什么功能或者组件就去 vue-element-admin 那里复制过来
# 解压压缩包
# 进入目录
cd vue-admin-template-master
# 安装依赖
npm install
# 启动。执行后,浏览器自动弹出并访问http://localhost:9528/
npm run dev
前端项目的创建和基本配置
将vue-admin-template-master重命名为guli-admin
修改端口号
config/index.js中修改
port: 9528,
关闭语法检查
config/index.js中修改
useEslint: false
项目的目录结构
├── build // 构建脚本
├── config // 全局配置
├── node_modules // 项目依赖模块
├── src //项目源代码
├── static // 静态资源
└── package.jspon // 项目信息和依赖配置
src
├── api // 各种接口
├── assets // 图片等资源
├── components // 各种公共组件,非公共组件在各自view下维护
├── icons //svg icon
├── router // 路由表
├── store // 存储
├── styles // 各种样式
├── utils // 公共工具,非公共工具,在各自view下维护
├── views // 各种layout
├── App.vue //***项目顶层组件***
├── main.js //***项目入口文件***
└── permission.js //认证入口
运行项目
npm run dev
修改模拟登录
前端
config下的dev.env.js的 BASE_API的路径换成本地
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
// BASE_API: '"https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin"',
BASE_API: '"http://localhost:8001"'
})
src/api/login.js的路径换成接口的路径
export function login(username, password) {
return request({
url: '/eduservice/user/login',
method: 'post',
data: {
username,
password
}
})
}
export function getInfo(token) {
return request({
url: '/eduservice/user/info',
method: 'get',
params: {
token }
})
}
export function logout() {
return request({
url: '/eduservice/user/logout',
method: 'post'
})
}
后端
EduLoginController
@RestController
@RequestMapping("/eduservice/user")
@Api(tags="登录管理")
@CrossOrigin
public class EduLoginController {
//login
@PostMapping("/login")
public ResultVo login(){
return ResultVo.ok().data("token","admin");
}
//info
@GetMapping("/info")
public ResultVo info(){
return ResultVo.ok().data("roles","[admin]").data("name","admin").data("avatar","https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif");
}
}
启动前端和后端
跨域问题
解决跨域问题
在接口上面添加
@CrossOrigin
讲师列表前端实现
创建路由页面
在src/views 下新建edu/teacher 文件夹
并新建 list.vue save.vue
list.vue
<template>
<div class="app-container">
讲师列表
</div>
</template>
add.vue
<template>
<div class="app-container">
讲师添加
</div>
</template>
添加路由
在src/router/index.js 添加
{
path: '/teacher',
component: Layout,
redirect: '/teacher/table',
name: '讲师管理',
meta: {
title: '讲师管理', icon: 'example' },
children: [
{
path: 'list',
name: '讲师列表',
component: () => import('@/views/edu/teacher/list'),
meta: {
title: '讲师列表', icon: 'table' }
},
{
path: 'save',
name: '添加讲师',
component: () => import('@/views/edu/teacher/save'),
meta: {
title: '添加讲师', icon: 'tree' }
}
]
},
定义teacher.js
在src/api下创建 edu/teacher.js
import request from '@/utils/request'
export default{
//讲师列表(条件查询分页)
//current 当前页 limit每页记录数 teacherQuery条件对象
getTeacherListPage(current,limit,teacherQuery){
return request({
url: `/eduservice/teacher/pageTeacherCondition/${
current}/${
limit}`, //这里用的是es6的``不是单引号
method: 'post',
//teacherQuery条件对象,后端使用RequestBody获取数据
//data表示把对象转换json进行传递到接口
data: teacherQuery
})
}
}
初始化vue组件
src/views/edu/teacher/list.vue
<template>
<div class="app-container">
讲师列表
</div>
</template>
<script>
//引入teacher.js
import teacher from '@/api/edu/teacher'
export default {
//写核心代码
data(){
//定义变量和初始值
return{
}
},
created(){
//页面渲染之前执行,一般调用methods定义的方法
},
methods:{
//创建具体的方法,调用teacher.js定义的方法
}
}
</script>
定义data
data(){
//定义变量和初始值
return{
list:null, //查询之后接口返回的集合
page:1, //当前页
limit:10, //每页记录数
total:0, //总记录数
teacherQuery:{
} //条件封装对象
}
定义methods
methods:{
//创建具体的方法,调用teacher.js定义的方法
//讲师列表方法
getList(){
teacher.getTeacherListPage(this.page,this.limit,this.teacherQuery)
.then(response =>{
// console.log(response.data.rows)
this.list=response.data.rows;
this.total=response.data.total;
})
.catch(error => {
console.log(error)//请求失败
})
}
}
完整版
<template>
<div class="app-container">
讲师列表
</div>
</template>
<script>
//引入teacher.js
import teacher from '@/api/edu/teacher'
export default {
//写核心代码
data(){
//定义变量和初始值
return{
list:null, //查询之后接口返回的集合
page:1, //当前页
limit:10, //每页记录数
total:0, //总记录数
teacherQuery:{
} //条件封装对象
}
},
created(){
//页面渲染之前执行,一般调用methods定义的方法
this.getList()
},
methods:{
//创建具体的方法,调用teacher.js定义的方法
//讲师列表方法
getList(){
teacher.getTeacherListPage(this.page,this.limit,this.teacherQuery)
.then(response =>{
// console.log(response.data.rows)
this.list=response.data.rows;
this.total=response.data.total;
})
.catch(error => {
console.log(error)//请求失败
})
}
}
}
</script>
表格渲染
<!-- 表格 -->
<el-table
:data="list"
border
fit
highlight-current-row>
<el-table-column
label="序号"
width="70"
align="center">
<template slot-scope="scope">
{
{ (page - 1) * limit + scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="name" label="名称" width="80" />
<el-table-column label="头衔" width="80">
<template slot-scope="scope">
{
{ scope.row.level===1?'高级讲师':'首席讲师' }}
</template>
</el-table-column>
<el-table-column prop="intro" label="资历" />
<el-table-column prop="gmtCreate" label="添加时间" width="160"/>
<el-table-column prop="sort" label="排序" width="60" />
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<router-link :to="'/teacher/edit/'+scope.row.id">
<el-button type="primary" size="mini" icon="el-icon-edit">修改</el-button>
</router-link>
<el-button type="danger" size="mini" icon="el-icon-delete" @click="removeDataById(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
分页
<!-- 分页 -->
<el-pagination
:current-page="page"
:page-size="limit"
:total="total"
style="padding: 30px 0; text-align: center;"
layout="total, prev, pager, next, jumper"
@current-change="getList"/>
修改getList方法
因为默认current是1,只能查第一页,
methods:{
//创建具体的方法,调用teacher.js定义的方法
//讲师列表方法
getList(page=1){
this.page = page
teacher.getTeacherListPage(this.page,this.limit,this.teacherQuery)
.then(response =>{
// console.log(response.data.rows)
this.list=response.data.rows;
this.total=response.data.total;
})
.catch(error => {
console.log(error)//请求失败
})
}
}
并且 @current-change=“getList”/>里面不要加参数,封装好了,会自己帮忙传
查询表单
注意:
element-ui的 date-picker组件默认绑定的时间值是默认世界标准时间,和中国时间差8小时
设置 value-format=“yyyy-MM-dd HH:mm:ss” 改变绑定的值
<!--查询表单-->
<el-form :inline="true" class="demo-form-inline">
<el-form-item>
<el-input v-model="teacherQuery.name" placeholder="讲师名"/>
</el-form-item>
<el-form-item>
<el-select v-model="teacherQuery.level" clearable placeholder="讲师头衔">
<el-option :value="1" label="高级讲师"/>
<el-option :value="2" label="首席讲师"/>
</el-select>
</el-form-item>
<el-form-item label="添加时间">
<el-date-picker
v-model="teacherQuery.begin"
type="datetime"
placeholder="选择开始时间"
value-format="yyyy-MM-dd HH:mm:ss"
default-time="00:00:00"
/>
</el-form-item>
<el-form-item>
<el-date-picker
v-model="teacherQuery.end"
type="datetime"
placeholder="选择截止时间"
value-format="yyyy-MM-dd HH:mm:ss"
default-time="00:00:00"
/>
</el-form-item>
<el-button type="primary" icon="el-icon-search" @click="getList()">查询</el-button>
<el-button type="default" @click="resetData()">清空</el-button>
</el-form>
清空功能
清空表单输入条件数据
查询所有的数据
resetData(){
//表单输入项数据清空
this.teacherQuery={
}
//查询所有讲师数据
this.getList();
}
删除讲师
定义api
src/api/edu/teacher.js
//删除讲师
deleteTeacherById(id){
return request({
url: `/eduservice/teacher/${
id}`,
method: 'delete'
})
}
定义methods
src/views/edu/teacher/list.vue
使用MessageBox 弹框组件
removeDataById(id){
this.$confirm('此操作将永久删除讲师记录, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
//点击确定,执行then方法
//调用删除的方法
teacher.deleteTeacherById(id)
.then(response =>{
//删除成功
//提示信息
this.$message({
type: 'success',
message: '删除成功!'
});
//回到列表页面
this.getList(this.page)
})
}) //点击取消,执行catch方法
}
添加讲师
定义api
src/api/edu/teacher.js
//添加讲师
addTeacher(teacher){
return request({
url:'/eduservice/teacher/addTeacher',
method:'post',
data: teacher
})
}
初始化组件
src/views/edu/teacher/save.vue
<template>
<div class="app-container">
讲师添加
<el-form label-width="120px">
<el-form-item label="讲师名称">
<el-input v-model="teacher.name" />
</el-form-item>
<el-form-item label="讲师排序">
<el-input-number
v-model="teacher.sort"
controls-position="right"
:min="0"
/>
</el-form-item>
<el-form-item label="讲师头衔">
<el-select v-model="teacher.level" clearable placeholder="请选择">
<el-option :value="1" label="高级讲师" />
<el-option :value="2" label="首席讲师" />
</el-select>
</el-form-item>
<el-form-item label="讲师资历">
<el-input v-model="teacher.career" />
</el-form-item>
<el-form-item label="讲师简介">
<el-input v-model="teacher.intro" :rows="10" type="textarea" />
</el-form-item>
<!-- 讲师头像:TODO -->
<el-form-item>
<el-button
:disabled="saveBtnDisabled"
type="primary"
@click="saveOrUpdate"
>保存</el-button
>
</el-form-item>
</el-form>
</div>
</template>
js
<script>
import teacherApi from '@/api/edu/teacher'
export default {
data(){
return {
teacher:{
name: '',
sort: 0,
level: 1,
career: '',
intro: '',
avatar: ''
},
saveBtnDisabled: false // 保存按钮是否禁用,
}
},
created(){
},
methods:{
saveOrUpdate(){
//添加
this.saveTeacher()
},
//添加讲师的方法
saveTeacher(){
teacherApi.addTeacher(this.teacher)
.then((response) => {
//提示信息
this.$message({
type: 'success',
message: '添加成功!'
});
//回到列表页面 ,路由跳转
this.$router.push({
path:'/teacher/list'})
}).catch((err) => {
});
}
}
}
</script>
修改讲师
通过路由跳转数据回显页面,再由路由index页面添加路由,并且是隐藏路由
添加和修改是同一个页面
隐藏路由
:id 是占位符
hidden: true 是隐藏
{
path: 'edit/:id',
name: '修改讲师',
component: () => import('@/views/edu/teacher/save'),
meta: {
title: '修改讲师',
noCache: 'tree'
},
hidden: true
}
路由跳转
<router-link :to="'/teacher/edit/'+scope.row.id">
<el-button type="primary" size="mini" icon="el-icon-edit">修改</el-button>
</router-link>
数据回显
在表单页面实现数据回显
在 src/api/edu/teacher.js
getTeacherInfoById(id) {
return request({
url: `/eduservice/teacher/${
id}`,
method: 'get',
})
}
页面调用回显
因为添加和修改页面使用save页面
区别添加还是修改,只有修改时候查询数据回显
判断路径里面是否有讲师id值,如果有id值修改,没有id值直接添加
根据路径是否有id决定回显
created() {
//判断路径有id值,做修改
if (this.$route.params && this.$route.params.id) {
//从路径获取id值
const id = this.$route.params.id;
this.getInfo(id);
}
},
修改讲师
在 src/api/edu/teacher.js
//修改讲师
updateTeacher(teacher) {
return request({
url: '/eduservice/teacher/updateTeacher',
method: 'put',
data: teacher
})
},
updateTeacherInfo() {
teacherApi
.updateTeacher(this.teacher)
.then((response) => {
//提示信息
this.$message({
type: "success",
message: "修改成功!",
});
//回到列表页面 ,路由跳转
this.$router.push({
path: "/teacher/list" });
})
.catch((err) => {
});
},
saveOrUpdate
saveOrUpdate() {
//判断修改还是添加
//根据teacher是否有id
if (!this.teacher.id) {
//添加
this.saveTeacher();
} else {
//修改
this.updateTeacherInfo();
}
}
问题bug
如果先点了讲师列表里面的修改,再点击添加讲师,会发现,数据回显还是会存在
表单页面还是现实修改回显的数据,正确 效果应该是表单数据清空
vue-router导航切换 时,如果两个路由都渲染同个组件,组件会重(chong)用,
组件的生命周期钩子(created)不会再被调用, 使得组件的一些数据无法根据 path的改变得到更新
因此:
1、我们可以在watch中监听路由的变化,当路由变化时,重新调用created中的内容
2、在init方法中我们判断路由的变化,如果是修改路由,则从api获取表单数据,
如果是新增路由,则重新初始化表单数据
完整版
<template>
<div class="app-container">
讲师添加
<el-form label-width="120px">
<el-form-item label="讲师名称">
<el-input v-model="teacher.name" />
</el-form-item>
<el-form-item label="讲师排序">
<el-input-number
v-model="teacher.sort"
controls-position="right"
:min="0"
/>
</el-form-item>
<el-form-item label="讲师头衔">
<el-select v-model="teacher.level" clearable placeholder="请选择">
<el-option :value="1" label="高级讲师" />
<el-option :value="2" label="首席讲师" />
</el-select>
</el-form-item>
<el-form-item label="讲师资历">
<el-input v-model="teacher.career" />
</el-form-item>
<el-form-item label="讲师简介">
<el-input v-model="teacher.intro" :rows="10" type="textarea" />
</el-form-item>
<!-- 讲师头像:TODO -->
<el-form-item>
<el-button
:disabled="saveBtnDisabled"
type="primary"
@click="saveOrUpdate"
>保存</el-button
>
</el-form-item>
</el-form>
</div>
</template>
<script>
import teacherApi from "@/api/edu/teacher";
export default {
data() {
return {
teacher: {
name: "",
sort: 0,
level: 1,
career: "",
intro: "",
avatar: "",
},
saveBtnDisabled: false, // 保存按钮是否禁用,
};
},
watch: {
$route(to, from) {
this.init();
},
},
created() {
this.init();
},
methods: {
init() {
//判断路径有id值,做修改
if (this.$route.params && this.$route.params.id) {
//从路径获取id值
const id = this.$route.params.id;
this.getInfo(id);
} else {
//路径没有id值,做添加
//清空表单
this.teacher = {
};
}
},
//根据讲师id查询方法
getInfo(id) {
teacherApi.getTeacherInfoById(id).then((response) => {
this.teacher = response.data.teacher;
});
},
saveOrUpdate() {
//判断修改还是添加
//根据teacher是否有id
if (!this.teacher.id) {
//添加
this.saveTeacher();
} else {
//修改
this.updateTeacherInfo();
}
},
//添加讲师的方法
saveTeacher() {
teacherApi
.addTeacher(this.teacher)
.then((response) => {
//提示信息
this.$message({
type: "success",
message: "添加成功!",
});
//回到列表页面 ,路由跳转
this.$router.push({
path: "/teacher/list" });
})
.catch((err) => {
});
},
updateTeacherInfo() {
teacherApi
.updateTeacher(this.teacher)
.then((response) => {
//提示信息
this.$message({
type: "success",
message: "修改成功!",
});
//回到列表页面 ,路由跳转
this.$router.push({
path: "/teacher/list" });
})
.catch((err) => {
});
},
},
};
</script>