es6 and vue basic knowledge points
es6 syntax new features blog link
vue basics blog link
axios blog link
npm, webpack blog link
vue-element-admin
Vue element admin is a background management system integration scheme based on element UI.
Function: https://panjiachen.github.io/vue-element-admin-site/zh/guide/# function
GitHub address: https://github.com/PanJiaChen/vue-element-admin
Project online preview: https://panjiachen.gitee.io/vue-element-admin
install
# Unzip the package # Enter directory cd vue-element-admin-master # Installation dependency npm install # Start. After execution, the browser automatically pops up and accesses http://localhost:9527/ npm run dev
vue-admin-template
Ueadmin template is a set of basic templates (at least simplified version) of background management system based on Vue element admin, which can be used as a template for secondary development.
GitHub address: https://github.com/PanJiaChen/vue-admin-template
Suggestion: you can carry out secondary development on the basis of Vue admin template, take Vue element admin as a toolbox, and copy what functions or components you want from Vue element admin
# Unzip the package # Enter directory cd vue-admin-template-master # Installation dependency npm install # Start. After execution, the browser automatically pops up and accesses http://localhost:9528/ npm run dev
Front end project creation and basic configuration
Rename Vue admin template master to Guli admin
Modify port number
Modify in config/index.js
port: 9528,
Turn off syntax checking
Modify in config/index.js
useEslint: false
Directory structure of the project
├── build // Build script ├── config // Global configuration ├── node_modules // Project dependent module ├── src //Project source code ├── static // Static resources └── package.jspon // Project information and dependency configuration
src ├── api // Various interfaces ├── assets // Pictures and other resources ├── components // Various public components and non-public components are maintained under their own view s ├── icons //svg icon ├── router // Routing table ├── store // storage ├── styles // Various styles ├── utils // Public tools and non-public tools are maintained under their own view s ├── views // Various layout s ├── App.vue //***Project top-level components*** ├── main.js //***Project entry file*** └── permission.js //Authentication entry
Run project
npm run dev
Modify simulated Login
front end
Base of dev.env.js under config_ Change the path of API to local
module.exports = merge(prodEnv, { NODE_ENV: '"development"', // BASE_API: '"https://easy-mock.com/mock/5950a2419adc231f356a6636/vue-admin"', BASE_API: '"http://localhost:8001"' })
Replace the path of src/api/login.js with the path of the interface
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' }) }
back-end
EduLoginController
@RestController @RequestMapping("/eduservice/user") @Api(tags="Login management") @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"); } }
Start front end and back end
Cross domain problem
Solve cross domain problems
Add on the interface
@CrossOrigin
Front end implementation of instructor list
Create routing page
Create a new edu/teacher folder under src/views
And create a new list.vue save.vue
list.vue
<template> <div class="app-container"> Instructor list </div> </template>
add.vue
<template> <div class="app-container"> Instructor add </div> </template>
Add route
Add in src/router/index.js
{ path: '/teacher', component: Layout, redirect: '/teacher/table', name: 'Instructor management', meta: { title: 'Instructor management', icon: 'example' }, children: [ { path: 'list', name: 'Instructor list', component: () => import('@/views/edu/teacher/list'), meta: { title: 'Instructor list', icon: 'table' } }, { path: 'save', name: 'Add instructor', component: () => import('@/views/edu/teacher/save'), meta: { title: 'Add instructor', icon: 'tree' } } ] },
Define teacher.js
Create edu/teacher.js under src/api
import request from '@/utils/request' export default{ //Instructor list (condition query page) //Current current page limit records per page teacherQuery condition object getTeacherListPage(current,limit,teacherQuery){ return request({ url: `/eduservice/teacher/pageTeacherCondition/${current}/${limit}`, //The ` ` of es6 is used here, not a single quotation mark method: 'post', //teacherQuery condition object. The backend uses RequestBody to obtain data //data means that the object is transformed into json and passed to the interface data: teacherQuery }) } }
Initialize vue components
src/views/edu/teacher/list.vue
<template> <div class="app-container"> Instructor list </div> </template> <script> //Introducing teacher.js import teacher from '@/api/edu/teacher' export default { //Write core code data(){ //Define variables and initial values return{ } }, created(){//Before page rendering, the method defined by methods is generally called }, methods:{//Create a specific method and call the method defined by teacher.js } } </script>
Define data
data(){ //Define variables and initial values return{ list:null, //Collection returned by the interface after query page:1, //Current page limit:10, //Records per page total:0, //Total records teacherQuery:{} //Conditional encapsulation object }
Define methods
methods:{//Create a specific method and call the method defined by teacher.js //Instructor list method 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)//request was aborted }) } }
Full version
<template> <div class="app-container"> Instructor list </div> </template> <script> //Introducing teacher.js import teacher from '@/api/edu/teacher' export default { //Write core code data(){ //Define variables and initial values return{ list:null, //Collection returned by the interface after query page:1, //Current page limit:10, //Records per page total:0, //Total records teacherQuery:{} //Conditional encapsulation object } }, created(){//Before page rendering, the method defined by methods is generally called this.getList() }, methods:{//Create a specific method and call the method defined by teacher.js //Instructor list method 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)//request was aborted }) } } } </script>
Table rendering
<!-- form --> <el-table :data="list" border fit highlight-current-row> <el-table-column label="Serial number" width="70" align="center"> <template slot-scope="scope"> {{ (page - 1) * limit + scope.$index + 1 }} </template> </el-table-column> <el-table-column prop="name" label="name" width="80" /> <el-table-column label="title" width="80"> <template slot-scope="scope"> {{ scope.row.level===1?'Senior Lecturer':'Principal Lecturer ' }} </template> </el-table-column> <el-table-column prop="intro" label="Qualifications" /> <el-table-column prop="gmtCreate" label="Add time" width="160"/> <el-table-column prop="sort" label="sort" width="60" /> <el-table-column label="operation" 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">modify</el-button> </router-link> <el-button type="danger" size="mini" icon="el-icon-delete" @click="removeDataById(scope.row.id)">delete</el-button> </template> </el-table-column> </el-table>
paging
<!-- paging --> <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"/>
Modify getList method
Because the default current is 1, you can only check the first page,
methods:{//Create a specific method and call the method defined by teacher.js //Instructor list method 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)//request was aborted }) } }
And @ current change = "getList" / > don't add parameters in it. If it's encapsulated, it will help you pass it
query form
be careful:
The default binding time value of the date picker component of the element UI is the default world standard time, which is 8 hours different from the Chinese time
Set value format = "yyyy MM DD HH: mm: SS" to change the bound value
<!--query form --> <el-form :inline="true" class="demo-form-inline"> <el-form-item> <el-input v-model="teacherQuery.name" placeholder="Lecturer name"/> </el-form-item> <el-form-item> <el-select v-model="teacherQuery.level" clearable placeholder="Lecturer title"> <el-option :value="1" label="Senior Lecturer"/> <el-option :value="2" label="Principal Lecturer "/> </el-select> </el-form-item> <el-form-item label="Add time"> <el-date-picker v-model="teacherQuery.begin" type="datetime" placeholder="Select start time" 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="Select deadline" 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()">query</el-button> <el-button type="default" @click="resetData()">empty</el-button> </el-form>
Emptying function
Empty form input condition data
Query all data
resetData(){ //Empty form entry data this.teacherQuery={} //Query all instructor data this.getList(); }
Delete instructor
Define api
src/api/edu/teacher.js
//Delete instructor deleteTeacherById(id){ return request({ url: `/eduservice/teacher/${id}`, method: 'delete' }) }
Define methods
src/views/edu/teacher/list.vue
Using the MessageBox bullet box component
removeDataById(id){ this.$confirm('This operation will permanently delete the instructor record, Continue?', 'Tips', { confirmButtonText: 'determine', cancelButtonText: 'cancel', type: 'warning' }).then(() => { //Click OK to execute the then method //Call the deleted method teacher.deleteTeacherById(id) .then(response =>{//Delete succeeded //Prompt information this.$message({ type: 'success', message: 'Delete succeeded!' }); //Back to the list page this.getList(this.page) }) }) //Click Cancel to execute the catch method }
Add instructor
Define api
src/api/edu/teacher.js
//Add instructor addTeacher(teacher){ return request({ url:'/eduservice/teacher/addTeacher', method:'post', data: teacher }) }
Initialize component
src/views/edu/teacher/save.vue
<template> <div class="app-container"> Instructor add <el-form label-width="120px"> <el-form-item label="Lecturer name"> <el-input v-model="teacher.name" /> </el-form-item> <el-form-item label="Lecturer ranking"> <el-input-number v-model="teacher.sort" controls-position="right" :min="0" /> </el-form-item> <el-form-item label="Lecturer title"> <el-select v-model="teacher.level" clearable placeholder="Please select"> <el-option :value="1" label="Senior Lecturer" /> <el-option :value="2" label="Principal Lecturer " /> </el-select> </el-form-item> <el-form-item label="Lecturer qualifications"> <el-input v-model="teacher.career" /> </el-form-item> <el-form-item label="Trainer Introduction "> <el-input v-model="teacher.intro" :rows="10" type="textarea" /> </el-form-item> <!-- Instructor portrait: TODO --> <el-form-item> <el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate" >preservation</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 // Whether the Save button is disabled, } }, created(){}, methods:{ saveOrUpdate(){ //add to this.saveTeacher() }, //How to add an instructor saveTeacher(){ teacherApi.addTeacher(this.teacher) .then((response) => { //Prompt information this.$message({ type: 'success', message: 'Added successfully!' }); //Return to the list page and route jump this.$router.push({path:'/teacher/list'}) }).catch((err) => { }); } } } </script>
Modify instructor
Jump to the data echo page through the route, and then add the route from the route index page, which is a hidden route
Add and modify are the same page
Hide route
: id is a placeholder
hidden: true is hidden
{ path: 'edit/:id', name: 'Modify instructor', component: () => import('@/views/edu/teacher/save'), meta: { title: 'Modify instructor', noCache: 'tree' }, hidden: true }
Route jump
<router-link :to="'/teacher/edit/'+scope.row.id"> <el-button type="primary" size="mini" icon="el-icon-edit">modify</el-button> </router-link>
Data echo
Realize data echo on form page
In src/api/edu/teacher.js
getTeacherInfoById(id) { return request({ url: `/eduservice/teacher/${id}`, method: 'get', }) }
Page call echo
Because add and modify pages use the save page
The difference is whether to add or modify. The query data is echoed only when modifying
Judge whether there is an instructor id value in the path. If there is an id value modified, it can be added directly without an id value
The echo is determined according to whether the path has an id
created() { //Judge that the path has id value and modify it if (this.$route.params && this.$route.params.id) { //Get id value from path const id = this.$route.params.id; this.getInfo(id); } },
Modify instructor
In src/api/edu/teacher.js
//Modify instructor updateTeacher(teacher) { return request({ url: '/eduservice/teacher/updateTeacher', method: 'put', data: teacher }) },
updateTeacherInfo() { teacherApi .updateTeacher(this.teacher) .then((response) => { //Prompt information this.$message({ type: "success", message: "Modified successfully!", }); //Return to the list page and route jump this.$router.push({ path: "/teacher/list" }); }) .catch((err) => {}); },
saveOrUpdate
saveOrUpdate() { //Determine whether to modify or add //According to whether the teacher has an id if (!this.teacher.id) { //add to this.saveTeacher(); } else { //modify this.updateTeacherInfo(); } }
Problem bug
If you click Modify in the instructor list first, and then click Add instructor, you will find that the data echo still exists
The form page is still used to modify the echoed data. The correct effect should be to empty the form data
During Vue router navigation switching, if both routes render the same component, the component will be reused,
The component life cycle hook (created) will not be called again, so that some data of the component cannot be updated according to the change of path
Therefore:
1. We can monitor the route change in the watch. When the route changes, we can call the content in created again
2. In the init method, we judge the change of the route. If the route is modified, we obtain the form data from the api,
If it is a new route, reinitialize the form data
Full version
<template> <div class="app-container"> Instructor add <el-form label-width="120px"> <el-form-item label="Lecturer name"> <el-input v-model="teacher.name" /> </el-form-item> <el-form-item label="Lecturer ranking"> <el-input-number v-model="teacher.sort" controls-position="right" :min="0" /> </el-form-item> <el-form-item label="Lecturer title"> <el-select v-model="teacher.level" clearable placeholder="Please select"> <el-option :value="1" label="Senior Lecturer" /> <el-option :value="2" label="Principal Lecturer " /> </el-select> </el-form-item> <el-form-item label="Lecturer qualifications"> <el-input v-model="teacher.career" /> </el-form-item> <el-form-item label="Trainer Introduction "> <el-input v-model="teacher.intro" :rows="10" type="textarea" /> </el-form-item> <!-- Instructor portrait: TODO --> <el-form-item> <el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate" >preservation</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, // Whether the Save button is disabled, }; }, watch: { $route(to, from) { this.init(); }, }, created() { this.init(); }, methods: { init() { //Judge that the path has id value and modify it if (this.$route.params && this.$route.params.id) { //Get id value from path const id = this.$route.params.id; this.getInfo(id); } else { //The path has no id value. Please add it //Empty form this.teacher = {}; } }, //Query method based on instructor id getInfo(id) { teacherApi.getTeacherInfoById(id).then((response) => { this.teacher = response.data.teacher; }); }, saveOrUpdate() { //Determine whether to modify or add //According to whether the teacher has an id if (!this.teacher.id) { //add to this.saveTeacher(); } else { //modify this.updateTeacherInfo(); } }, //How to add an instructor saveTeacher() { teacherApi .addTeacher(this.teacher) .then((response) => { //Prompt information this.$message({ type: "success", message: "Added successfully!", }); //Return to the list page and route jump this.$router.push({ path: "/teacher/list" }); }) .catch((err) => {}); }, updateTeacherInfo() { teacherApi .updateTeacher(this.teacher) .then((response) => { //Prompt information this.$message({ type: "success", message: "Modified successfully!", }); //Return to the list page and route jump this.$router.push({ path: "/teacher/list" }); }) .catch((err) => {}); }, }, }; </script>