egg.js入门学习 之 做个文章发布小demo

    科技2022-08-04  93

    虽然是小 demo,但是咱们前后端那都是齐全的。这里使用 vue + vant 搭建前端,egg.js + mysql 做为后端(完美)👍👍👍👍👍

    前端: vue 脚手架搭建啥的,大家都会了。

    vue create clinet

    安装 vant

    npm install vant -S

    咱们这是学习 egg.js,所以前端就不细说了。 安装一个时间格式化工具 moment

    npm install monent --save

    代码直接奉上

    Add.vue

    <template> <div style="margin-top: 50px;"> <van-uploader v-model="fileList" :max-count="1" :after-read="afterReader" /> <van-cell-group> <van-field label="文章标题" placeholder="文章标题" v-model="title" /> <van-field label="文章简介" placeholder="文章简介" v-model="summary" /> <van-field label="文章内容" placeholder="文章内容" v-model="content" type="textarea" autosize /> </van-cell-group> <van-button type="primary" @click="handleAdd" class="add-button">提交</van-button> </div> </template> <script> import { Toast } from 'vant'; export default { data() { return { fileList: [], title: '', summary: '', content: '', img: '' } }, methods: { afterReader(info) { console.log(info) this.img = info.content }, handleAdd() { const data = { title: this.title, summary: this.summary, content: this.content, img: this.img } console.log(data.img) fetch('/article/create', { method: 'post', headers: { 'Content-type': 'application/json' }, body: JSON.stringify(data) }).then(res => res.json()) .then(res => { if (res.status === 200) { Toast.success('成功'); this.$router.push('/') } else { Toast.loading({ message: '加载中...', forbidClick: true, }) } }) } }, } </script> <style scoped> .add-button { position: absolute; left: 0; bottom: 100; left: 40%; } </style>

    Detail.vue

    <template> <div class="detail"> <div class="title">{{detail.title}}</div> <div class="summary">{{detail.summary}}</div> <div class="content">{{detail.content}}</div> <div class="create-time">{{detail.createTime}}</div> </div> </template> <script> import moment from 'moment' export default { data() { return { detail: { id: undefined, title: undefined, img: undefined, summary: undefined, content: undefined, createTime: undefined, }, } }, created() { fetch('/article/detail/' + this.$route.query.id).then(res => res.json().then((res) => { if (res.status === 200) { this.detail = res.data this.detail.createTime = res.data.createTime ? moment(res.data.createTime).format('YYYY-MM-DD HH:mm:ss') : undefined } else { Toast.loading({ message: '加载中...', forbidClick: true, }) } })) } } </script> <style scoped> .detail { padding: 20px; text-align: left; margin-bottom: 45px; } .detail .title { font-size: 25px; padding-bottom: 20px; } .detail .summary { padding: 20px; background: #dcdcdc; } .detail .content { padding-top: 20px; text-indent: 2rem; line-height: 200%; } .detail .create-time { color: #9c9c9c; text-align: right; } </style>

    Home.vue

    <template> <div class="home"> <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad" > <van-cell v-for="item in list" :key="item.id" @click="handleClick(item.id)" > <div class="list"> <div class="left"> <img :src="item.img" alt="" /> <!-- <img src="" alt=""> --> </div> <div class="right"> <div class="title">{{ item.title }}</div> <div class="create-time">{{ item.createTime }}</div> </div> </div> </van-cell> </van-list> </div> </template> <script> import moment from 'moment' export default { name: "home", data() { return { loading: false, finished: false, list: [], }; }, methods: { onLoad() { fetch('/article/lists').then((res) => res.json()).then((res) => { if (res.status === 200) { this.loading = false; this.finished = true; this.list = res.data.map(item => { if (item.createTime) { item.createTime = moment(item.createTime).format('YYYY-MM-DD HH:mm:ss') } return item // console.log(item.createTime) }) // this.list = res.data } else { Toast.loading({ message: '加载中...', forbidClick: true, }) } }) }, handleClick(id) { this.$router.push({ path: "/detail", query: { id, }, }); }, }, mounted() { this.onLoad(); }, }; </script> <style scoped> .list { display: flex; flex-direction: row; } .list .left, img { width: 150px; height: 100px; border-radius: 10px; } .list .right { display: flex; flex-direction: column; justify-content: space-between; margin-left: 15px; } .list .right .title { font-size: 18px; } .list .right .create-time { font-size: 12px; color: #ccc; } </style>

    App.vue

    <template> <div id="app"> <router-view /> <van-tabbar route> <van-tabbar-item replace to="/" icon="home-o"> 首页 </van-tabbar-item> <van-tabbar-item replace to="/add" icon="plus"> 发布 </van-tabbar-item> </van-tabbar> </div> </template> <script> export default { }; </script> <style lang="scss"> #app { font-family: "Avenir", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; } #nav { padding: 30px; a { font-weight: bold; color: #2c3e50; &.router-link-exact-active { color: #42b983; } } } </style>

    main.js

    import Vue from 'vue' import App from './App.vue' import Vant from 'vant'; import 'vant/lib/index.css'; import router from './router' import store from './store' Vue.config.productionTip = false Vue.use(Vant) new Vue({ router, store, render: h => h(App) }).$mount('#app')

    router.js

    import Vue from 'vue' import Router from 'vue-router' import Home from './views/Home.vue' Vue.use(Router) export default new Router({ mode: 'hash', routes: [ { path: '/', name: 'home', component: () => import(/* webpackChunkName: "about" */ './views/Home.vue') }, { path: '/detail', name: 'detail', component: () => import(/* webpackChunkName: "about" */ './views/Detail.vue') }, { path: '/add', name: 'add', component: () => import(/* webpackChunkName: "about" */ './views/Add.vue') } ] })

    vue.config.js

    module.exports = { devServer: { proxy: { '/article': { target: 'http://localhost:7001', ws: true, changeOrgin: true } } } }

    后端: 安装 egg

    mkdir server && cd server npm init egg --type=simple npm i

    启动

    npm run dev open http://localhost:7001

    之前那一篇,我们是模拟数据库,今天我们使用 mysql 数据库,所以第一步就是连接数据库 (安装啥的,网上教程都有,或者可以看笔者之前写的文章)🤛🤛🤛🤛

    安装

    npm i --save egg-mysql

    config / plugin.js

    'use strict'; /** @type Egg.EggPlugin */ exports.mysql = { enable: true, package: 'egg-mysql', }; config / 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 + '_1601799155318_9545'; // add your middleware config here config.middleware = []; config.security = { csrf: { enable: false } } config.mysql = { // 单数据库信息配置 client: { // host host: 'localhost', // 端口号 port: '3306', // 用户名 user: 'root', // 密码 password: '*******', // 数据库名 database: 'egg_article', }, // 是否加载到 app 上,默认开启 app: true, // 是否加载到 agent 上,默认关闭 agent: false, }; // add your user config here const userConfig = { // myAppName: 'egg', }; return { ...config, ...userConfig, }; };

    之后就是把你电脑上的数据库打开

    C:\Users\DELL>mysql -uroot -p Enter password: ****** Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show databases; +--------------------+ | Database | +--------------------+ | book | | information_schema | | koa_weibo | | myemployees | | mysql | | performance_schema | | sys | | test | | weixin-koa | +--------------------+ 9 rows in set (1.00 sec) mysql> create database egg_article; Query OK, 1 row affected (0.44 sec) mysql> use egg_article; Database changed mysql> mysql> create table article( -> id int(10) not null auto_increment, -> img text default null comment '缩略图', -> title varchar(80) default null comment '文章标题', -> summary varchar(300) default null comment '文章简介', -> content text default null comment '文章内容', -> createTime timestamp default null comment '发布时间', -> primary key(id) -> )engine=InnoDB AUTO_INCREMENT=1 comment '文章表'; Query OK, 0 rows affected, 1 warning (1.82 sec) mysql> mysql> insert into article(img, title, summary, content, createTime) -> values('编程必备基础知识 计算机组成原理+操作系统+计算机网络', 'https://img2.mukewang.com/szimg/5d1032ab08719e0906000338.jpg', '介绍编辑必备基础知识', '快速、系统补足必备的计算机系统知识、更快更有趣、更贴近实际工作,让你更快地学到满足实际工作需要的知识,为以后的工作打好良好的基础', '2020-03-03 10:20:20'); Query OK, 1 row affected (0.53 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | book | | egg_article | | information_schema | | koa_weibo | | myemployees | | mysql | | performance_schema | | sys | | test | | weixin-koa | +--------------------+ 10 rows in set (0.08 sec) mysql> use egg_article; Database changed mysql> show tables; +-----------------------+ | Tables_in_egg_article | +-----------------------+ | article | +-----------------------+ 1 row in set (0.29 sec) mysql> desc article; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | int | NO | PRI | NULL | auto_increment | | img | text | YES | | NULL | | | title | varchar(80) | YES | | NULL | | | summary | varchar(300) | YES | | NULL | | | content | text | YES | | NULL | | | createTime | timestamp | YES | | NULL | | +------------+--------------+------+-----+---------+----------------+ 6 rows in set (0.11 sec) mysql>

    初始化数据的 SQL 文件

    create database egg_article; use egg_article; create table article( id int(10) not null auto_increment, img text default null comment '缩略图', title varchar(80) default null comment '文章标题', summary varchar(300) default null comment '文章简介', content text default null comment '文章内容', createTime timestamp default null comment '发布时间', primary key(id) )engine=InnoDB AUTO_INCREMENT=1 comment '文章表'; insert into article(img, title, summary, content, createTime) values('编程必备基础知识 计算机组成原理+操作系统+计算机网络', 'https://img2.mukewang.com/szimg/5d1032ab08719e0906000338.jpg', '介绍编辑必备基础知识', '快速、系统补足必备的计算机系统知识、更快更有趣、更贴近实际工作,让你更快地学到满足实际工作需要的知识,为以后的工作打好良好的基础', '2020-03-03 10:20:20');

    之后我们安装一个时间格式化工具 moment npm install monent --save

    一切准备就绪之后,我们就开始编写路由吧

    router.js

    'use strict'; /** * @param {Egg.Application} app - egg application */ module.exports = app => { const { router, controller } = app; router.get('/', controller.home.index); router.post('/article/create', controller.article.create); router.get('/article/lists', controller.article.lists); router.get('/article/detail/:id', controller.article.detail); };

    home.js

    'use strict'; const Controller = require('egg').Controller; class HomeController extends Controller { async index() { const { ctx, app } = this; const res = await app.mysql.select('article'); console.log(res) ctx.body = 'hi, egg'; } } module.exports = HomeController;

    与 home.js 同级目录下,新建 article.js

    const Controller = require('egg').Controller const moment = require('moment') class ArticleController extends Controller { async create() { const { ctx } = this; const params = { ...ctx.request.body, createTime: moment().format('YYYY-MM-DD HH:mm:ss') } const result = await ctx.service.article.create(params) if (result) { ctx.body = { status: 200, data: result } } else { ctx.body = { status: 500, errMsg: 'err' } } } async lists() { const { ctx } = this; const result = await ctx.service.article.lists() if (result) { ctx.body = { status: 200, data: result } } else { ctx.body = { status: 500, errMsg: '查询文章列表失败' } } } async detail() { const { ctx } = this const result = await ctx.service.article.detail(ctx.params.id) if (result) { ctx.body = { status: 200, data: result } } else { ctx.body = { status: 500, errMsg: '该文章不存在' } } } } module.exports = ArticleController

    app 文件夹下新建一个 service 文件夹,里面新建一个 article.js

    const Service = require('egg').Service; class ArticleService extends Service { async create(params) { const { app } = this; try { const result = await app.mysql.insert('article', params) return result } catch (error) { console.log(error) return null } } async lists() { const { app } = this; try { const result = await app.mysql.select('article') return result } catch (error) { console.log(error) return null } } async detail(id) { if (!id) { console.log('id 必须有值') return null } try { const result = await this.app.mysql.get('article', { id }) return result } catch (error) { console.log(error) return null; } } } module.exports = ArticleService

    不处意外的话,你应该是可以正常运行的。但笔者写文章之时,可能会有一些错误,若有发现,望指正🙏🙏🙏🙏🙏

    Processed: 0.073, SQL: 8