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

posted @ 2023-02-05 17:35  ben10044  阅读(142)  评论(0编辑  收藏  举报