Egg插件
egg-view-nunjucks
安装
cnpm install egg-view-nunjucks
plugin.js中引入插件
nunjucks: {
enable: true,
package: 'egg-view-nunjucks',
}
config.default.js中配置插件
config.view = {
defaultViewEngine: 'nunjucks' //配置模板引擎
}
如果要使用模板,需要在app下创建view目录,egg的规定
访问模板需要在home.js里await ctx.render("index"),与koa类似
水果列表
home.js
'use strict';
const { Controller } = require('egg');
class HomeController extends Controller {
async index() {
const { ctx } = this;
// ctx.body = 'hello world';
await ctx.render("index",{fruits:["苹果","香蕉","鸭梨"]});
}
}
module.exports = HomeController;
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>水果列表</h1>
<ul>
{% for item in fruits %}
<li>{{item}}</li>
{% endfor %}
</ul>
</body>
</html>
egg-cors
安装
cnpm install egg-cors
plugin.js中引入插件
cors: {
enable: true,
package: 'egg-cors',
}
config.default.js中配置插件
config.cors = {
origin: "*",//允许所有地址跨域请求
allowMethods:'GET,HEAD,PUT,POST,DELETE,PATCH'//允许的请求
};
实现3000和7001端口的跨域
App.vue 3000端口
<template>
<div>
<h1>{{ msg }}</h1>
</div>
</template>
<script>
import axios from 'axios';
export default {
data(){
return {
msg:"hello world"
}
},
created(){
axios.get("http://127.0.0.1:7001/data").then((res)=>{
this.msg = res.data
})
}
}
</script>
home.js 7001端口
'use strict';
const { Controller } = require('egg');
class HomeController extends Controller {
async index() {
const { ctx } = this;
// ctx.body = 'hello world';
await ctx.render("index",{fruits:["苹果","香蕉","鸭梨"]});
}
async getData(){
this.ctx.body = "hello egg"
}
}
module.exports = HomeController;
router.js
'use strict';//严格模式
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/data', controller.home.getData);
};
通过vue和egg实现水果列表的增删改查
首先写后台接口egg项目
router.js
'use strict';//严格模式
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/data', controller.home.getData);
router.resources("fruits","/fruits",controller.fruits);
};
fruits.js
const Controller = require('egg').Controller;
let fruitList = ["苹果","香蕉","鸭梨"];
class FruitsController extends Controller {
//查看 get请求
async index(){
this.ctx.body = fruitList;
}
//添加 post请求
async create(){
const fruit = this.ctx.request.body.fruit;//.body后面的.fruit是前端传过来的
fruitList.push(fruit);
this.ctx.body = "添加成功";
}
//删除 delete请求 /fruits:id
async destroy(){
let id = this.ctx.params.id;//通过id删除
fruitList.splice(id,1);
this.ctx.body = "删除成功";
}
//修改 put请求 /fruits:id
async update(){
let id = this.ctx.params.id;
const fruit = this.ctx.request.body.fruit;
fruitList.splice(id,1,fruit);
this.ctx.body = "修改成功";
}
}
module.exports = FruitsController;
再写前端vue项目
App.vue
<template>
<div>
<form @submit.prevent="postData">
<input type="text" v-model="fruit">
<button>添加</button>
</form>
<ul>
<li v-for="(item,index) of fruitList" :key="item">
<!--在v-for中,item in list,在循环数组中如果数组上的元素有属性,也会循环属性
而item of list则只循环数组
-->
<!-- :key的作用是提高循环效率,当v-for渲染数据时要对数据进行增删改操作
此时如果没有:key,整个列表都会重新渲染一遍
如果有:key,那就会判断key的值是否改变,改变了才渲染该项
key的值只能是不变的值,一般是id
-->
{{ item }}
<button @click="del(index)">删除</button>
<button @click="upd(index)">修改</button>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
data(){
return {
fruitList:[],
fruit:""
}
},
created(){
// axios.get("http://127.0.0.1:7001/fruits").then((res)=>{
// this.fruitList = res.data
// })
this.getData();//用getData方法提高复用性
},
methods:{
getData(){
axios.get("http://127.0.0.1:7001/fruits").then((res)=>{
this.fruitList = res.data
})
},
//添加
postData(){
axios.post("http://127.0.0.1:7001/fruits",{fruit:this.fruit})
.then(()=>{//之所以没写res,是因为提交表单后不需要把数据响应出来,直接查看就好
this.getData();
})
/*添加功能要加个数据,这个数据是后台post请求的字段
后台fruits.js中查看得知是const fruit = this.ctx.request.body.fruit
=后面的是字段,在后台被赋值给常量fruit
:的是内容,是data()中的fruit,即前端input框输入的内容
*/
},
//删除
del(id){
axios.delete(`http://127.0.0.1:7001/fruits/${id}`)
.then(()=>{
this.getData();
})
},
//修改
upd(id){
let updv = prompt("请输入要修改的内容");
axios.put(`http://127.0.0.1:7001/fruits/${id}`,{fruit:updv})
.then(()=>{
this.getData();
})
}
}
}
</script>
li标签那里对注释in of list区别的说明
结果
添加
删除
修改
逻辑流程:用户在本地3000端口操作前端页面App.vue(修改),通过axios发送请求(put),跨域传到127.0.0.17001/fruits(事先配置好egg-cors插件);
之后后台的路由router.js接收到put请求,根据router.resources("fruits","/fruits",controller.fruits),找到fruits.js的FruitController控制器;
再通过restful接口put请求对应的方法是update(),使用该方法对后台的数据fruitList进行操作(修改),修改后前端执行this.getData();查看数据
即又到后台使用index方法this.ctx.body = fruitList来查看数据并响应到前端。
学生信息列表
egg
students.js
const Controller = require('egg').Controller;
let studentList = [{uid:1,name:"benson",score:90},{uid:2,name:"mike",score:80}];
class studentsController extends Controller {
//查看 get请求
async index(){
this.ctx.body = studentList;
}
//添加 post请求
async create(){
const student = this.ctx.request.body.student;//.body后面的.student是前端传过来的
studentList.push(student);
this.ctx.body = "添加成功";
}
//删除 delete请求 /students:id
async destroy(){
let id = this.ctx.params.id;//通过id删除
studentList.splice(id,1);
this.ctx.body = "删除成功";
}
}
module.exports = studentsController;
router.js
'use strict';//严格模式
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.resources("students","/students",controller.students);
};
js不支持多个文本框的弹窗,需要jQuery才行,这里就不写修改功能了
vue
App.vue
<template>
<div>
<form @submit.prevent="postData">
学号<input type="text" v-model="student.uid" placeholder="学号">
姓名<input type="text" v-model="student.name" placeholder="姓名">
成绩<input type="text" v-model="student.score" placeholder="成绩">
<button>添加</button>
</form>
<ul>
<li v-for="(item,index) in studentList" :key="item">
学号:{{ item.uid }} 姓名:{{ item.name }} 成绩:{{ item.score }}
<button @click="del(index)">删除</button>
</li>
</ul>
</div>
</template>
<script>
import axios from 'axios';
export default {
data(){
return {
studentList:[],
student:{
uid:null,
name:"",
score:null
}
}
},
created(){
this.getData();//用getData方法提高复用性
},
methods:{
getData(){
axios.get("http://127.0.0.1:7001/students").then((res)=>{
this.studentList = res.data
})
},
//添加
postData(){
axios.post("http://127.0.0.1:7001/students",{student:this.student})
.then(()=>{//之所以没写res,是因为提交表单后不需要把数据响应出来,直接查看就好
this.getData();
})
},
//删除
del(id){
axios.delete(`http://127.0.0.1:7001/students/${id}`)
.then(()=>{
this.getData();
})
}
}
}
</script>
用Element-Plus美化
先安装配置好element plus,详情看element plus的博客页
students.js
const Controller = require('egg').Controller;
let studentList = [{uid:1,name:"benson",score:90},{uid:2,name:"mike",score:80}];
class studentsController extends Controller {
//查看 get请求
async index(){
this.ctx.body = studentList;
}
//添加 post请求
async create(){
const student = this.ctx.request.body.student;//.body后面的.student是前端传过来的
studentList.push(student);
this.ctx.body = "添加成功";
}
//删除 delete请求 /students:id
async destroy(){
let id = this.ctx.params.id;//接收的是学号
//需要遍历来匹配
studentList.map((item,index)=>{
if(item.uid == id){//遍历的学号=接收到的值
studentList.splice(index,1);//此时的下标就是要找的学生对象
this.ctx.body = "删除成功";
}
});
}
//修改 put请求
async update(){
const student = this.ctx.request.body.student;
let id = this.ctx.params.id;//接收的是学号
//需要遍历来匹配
studentList.map((item,index)=>{
if(item.uid == id){//遍历的学号=接收到的值
studentList.splice(index,1,student);//此时的下标就是要找的学生对象
this.ctx.body = "修改成功";
}
});
}
}
module.exports = studentsController;
router.js
'use strict';//严格模式
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.resources("students","/students",controller.students);
};
plugin.js
'use strict';
/** @type Egg.EggPlugin */
module.exports = {
// had enabled by egg
// static: {
// enable: true,
// }
nunjucks: {
enable: true,
package: 'egg-view-nunjucks',
},
cors: {
enable: true,
package: 'egg-cors',
},
jwt: {
enable: true,
package: "egg-jwt"
},
};
config.default.js
/* eslint valid-jsdoc: "off" */
'use strict';
/**
* @param {Egg.EggAppInfo} appInfo app info
*/
module.exports = appInfo => {
/**
* built-in config
* @type {Egg.EggAppConfig}
**/
const config = exports = {};
// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1675582188553_8108';
// add your middleware config here
config.middleware = [];
// add your user config here
const userConfig = {
// myAppName: 'egg',
};
config.security = {
csrf: {
enable:false,
},
};
config.view = {
defaultViewEngine: 'nunjucks' //配置模板引擎
};
config.cors = {
origin: "*",
allowMethods:'GET,HEAD,PUT,POST,DELETE,PATCH'//允许的请求
};
config.jwt = {
secret:"bensonjwt"
};
return {
...config,
...userConfig,
};
};
vue
App.vue
<template><!--element-plus的table组件找的-->
<div>
<el-button text @click="dialogVisible = true" type="primary">
添加学生
</el-button>
<el-dialog
v-model="dialogVisible"
title="添加学生信息"
width="30%"
>
<el-form>
<el-form-item label="学号">
<el-input v-model="form.uid" />
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="成绩">
<el-input v-model="form.score" />
</el-form-item>
<!--form.uid form.name form.score通过input的赋值,此时data()中的form也就有了值
所以addsubmit里的stuent:this.form的this.form才有值传给后台-->
</el-form><!--把对话框的内容换成表单-->
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="addSubmit">
确认
</el-button>
</span>
</template>
</el-dialog><!--dialog对话框-->
<el-table :data="studentList" border style="width:480px;"
:cell-style="{ textAlign: 'center' }"
:header-cell-style="{ 'text-align': 'center' }"
><!--:cell-style="{ textAlign: 'center' }"是所有列居中
:header-cell-style="{ 'text-align': 'center' }"是表头居中
如果是让单纯一两列el-table-column居中就在它的标签加个align="center"-->
<el-table-column prop="uid" label="学号" width="120" />
<el-table-column prop="name" label="姓名" width="120" />
<el-table-column prop="score" label="成绩" width="120" />
<el-table-column label="操作" width="120">
<template #default="scope">
<el-button type="primary" size="small" @click="del(scope.row.uid)">删除</el-button>
<el-button type="primary" size="small" @click="editClick(scope.row,scope.$index)">修改</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
v-model="editVisible"
title="修改学生信息"
width="30%"
>
<el-form>
<el-form-item label="学号">
<el-input v-model="editObj.uid" />
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="editObj.name" />
</el-form-item>
<el-form-item label="成绩">
<el-input v-model="editObj.score" />
</el-form-item>
</el-form><!--把对话框的内容换成表单-->
<template #footer>
<span class="dialog-footer">
<el-button @click="editVisible = false">取消</el-button>
<el-button type="primary" @click="editSubmit">
确认
</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script>
import axios from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus'//引入才能用messagebox
export default {
data(){
return {
studentList:[],
dialogVisible:false,
editVisible:false,
form:{
uid:null,
name:"",
score:null
},
editObj:{
uid:null,
name:"",
score:null
},
editIndex:null,
id_edit:null//创建一个容器存放修改前的学号
}
},
methods:{
handleClick(row){
console.log(row)
/*
scope.row能获取当前行的对象,如
{uid: '3', name: 'ben3', score: '95'}
*/
},
//查看
getData(){
axios.get("http://127.0.0.1:7001/students").then((res)=>{
this.studentList = res.data
})
},
//添加
postData(){
axios.post("http://127.0.0.1:7001/students",{student:this.student})
.then(()=>{//之所以没写res,是因为提交表单后不需要把数据响应出来,直接查看就好
this.getData();
})
},
//删除
del(id){
ElMessageBox.confirm(//messgebox组件
'此操作将永久删除该数据,是否继续?',
'提示',
{
confirmButtonText: '确定',//执行then方法
cancelButtonText: '取消',//执行catch方法
type: 'warning',//弹窗的标题
}
)
.then(() => {
axios.delete(`http://127.0.0.1:7001/students/${id}`)
.then(()=>{
ElMessage({
type: 'success',
message: '删除成功',
})
this.getData();
})
})
.catch(() => {
ElMessage({
type: 'info',
message: '已取消删除',
})
})
},
addSubmit(){
axios.post("http://127.0.0.1:7001/students",{student:this.form})//提交的是添加学生信息form的数据
.then(()=>{
this.dialogVisible = false;
this.getData();
})
},
editClick(row,index){
/*scope.row获取当前行的数据,而scope.$index获取的是当前行的数据在数组中的索引
(tabel表格绑定的数据是一个数组,数组中每一个对象就相当于一行的数据)*/
this.editVisible = true
this.editObj = row;//当前行的数据赋值给editObj,而修改按钮的表单绑定的是editObj的各属性,所以会同步显示
this.editIndex = index;//this.studentList[this.editIndex]就能得到当前行的数据,不过容易引起异步问题,还没想到用处
console.log(this.editObj.uid)
console.log(this.editIndex)
this.id_edit = this.editObj.uid;//把修改前的学号放到data()中
},
editSubmit(){
let id = this.id_edit; //通过data()的id_edit实现传参!!!想了半天竟然没想到这个
axios.put(`http://127.0.0.1:7001/students/${id}`,{student:this.editObj})
.then(()=>{
this.editVisible = false;
this.getData();
})
},
},
created(){
this.getData();
}
}
</script>
main.js
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import './index.css'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
优化了输入框同步当前行的数据,但又有个新问题,element不支持v-moel.lazy