Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Egg.js 试水 - 天气预报 #69

Open
reng99 opened this issue Sep 7, 2020 · 0 comments
Open

Egg.js 试水 - 天气预报 #69

reng99 opened this issue Sep 7, 2020 · 0 comments
Labels
blog a single blog javascript javascript tag

Comments

@reng99
Copy link
Owner

reng99 commented Sep 7, 2020

weather_banner

Egg.js是一个基于Koa开发的Node.js框架。为企业级框架和应用而生。

官网介绍,Egg奉行『约定优于配置』,按照一套统一的约定进行应用开发,团队内部采用这种方式可以减少开发人员的学习成本。

😊 约定优于配置理念,也是为了更好的拧螺丝的手段。不过挺好用~

环境搭建

推荐使用脚手架搭建:

$ mkdir egg-example && cd egg-example
$ npm init egg --type=simple
$ npm i

启动项目:

$ npm run dev
$ open http://localhost:7001

当然,推荐使用yarn进行包管理。

此时,在http://localhost:7001或者http://127.0.0.1:7001地址的页面上,你会看到egg 的 say hi提示。

基本概念什么的,感兴趣的话,直接去它的官网了解。

我们直接来实现一个mvc的后端渲染项目 - 天气预报

天气预报

我们使用的egg 版本号是 ^2.15.1~

为啥要说明这里的版本号?因为可能config里面的写法不同~无伤大雅

前期准备

  • 我们先关闭crsf,避免在进行表单提交的时候报错
// config/config.default.js
// 关闭csrf
config.security = {
  csrf: false
}
  • 视图模版引擎我们不使用官网推荐的nunjucks,而是使用egg-view-ejs插件。选择自己拿手的就行。

通过npm install egg-view-ejs --save,进行相关的配置:

// config/plugin.js
// 引入第三方插件ejs
ejs: {
  enable: true,
  package: 'egg-view-ejs',
}

// config/config.default.js
// 处理视图
config.view = {
  mapping: {
    '.html': 'ejs',
  },
};

⚠️ 注意:处理视图文件的配置时候,我们选择.html的后缀,比较适合前端习惯。当然,你可以保留.ejs的后缀。

  • 选择自己熟悉的IDE,安装相关插件进行信息提示

这里我还是选择了Visual Studio Code,安装eggjs插件。

接下来我们将集中在app文件夹内完成✅这个天气预报小项目。

weather-project
├── app
|	├── controller
|	|	└── weather.js
|	├── public
|	|	└── weather.css
|	├── service
|	|	└── weather.js
|	├── view
|	|	└── weather.html
|	└── router.js
.

开发进程

我们一一来说,你感兴趣的话,可以一一复制代码进行尝试~🉑️

页面骨架搭建:

<!--view/weather.html-->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>天气预报</title>
  <link rel="stylesheet" href="https://unpkg.com/ant-design-vue@1.6.4/dist/antd.min.css"/>
  <link rel="stylesheet" href="/public/weather.css" />
</head>

<body>
  <div id="app">
    <a-result>
      <template slot="icon">
        <a-icon type="cloud"/>
      </template>
      <template slot="title">
        <b>天气预报 - <%= data.currentCity %></b>
      </template>
    </a-result>
    <div class="search">
      <form action="http://127.0.0.1:7001/weather" method="POST">
        <input type="text" name="location" placeholder="请输入城市,如:广州" required>
        <a-button type="primary" html-type="submit">查询</a-button>
      </form>
    </div>
    <div class="main">
      <% if(data.code === -1) { %>
        <a-alert style="width: 260px; margin: 0 auto;" :message="`<%= data.msg %>`" banner />
      <% } else { %>
        <a-timeline mode="alternate">
          <% for(let i =0; i < data.weather_data.length; i++) {%>
            <a-timeline-item :color="`<%= i % 2 == 0 ? 'blue' : 'green'%>`">
              <p style="margin-bottom: 4px;"><%= data.weather_data[i].date %></p>
              <a-tag color="orange"><%= data.weather_data[i].temperature %></a-tag>
              <p style="margin-top: 4px;"><%= data.weather_data[i].wind %></p>
            </a-timeline-item>
          <% } %>
        </a-timeline>
        
      <% } %>
    </div>
  </div>

  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"></script>
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/ant-design-vue/1.6.4/antd.min.js"></script>
  <script type="text/javascript">
    (function(){
      new Vue({
        el: '#app'
      })
    })()
  </script>
</body>

</html>

页面展示润色:

# public/weather.css

*{
  padding: 0;
  margin: 0;
}

#app .search{
  text-align: center;
}

#app .search input{
  outline: none;
  width: 200px;
  height: 34px;
  border-radius: 4px;
  padding: 0 12px;
  border: 1px solid #ddd;
}

#app .main{
  margin: 20px 0;
}

我们是使用的MVC模式,怎么缺得了controller和service呢。当然,service是可选的,但是不建议省略~

controller部分:

// controller/weather.js

'use strict';

const Controller = require('egg').Controller;

class WeatherController extends Controller {
  async getWeather() {
    const { ctx, service } = this;
    const data = await service.weather.getWeather('广州')
    await ctx.render('weather', { data })
  }

  async postWeather() {
    const { ctx, service } = this;
    const location = ctx.request.body.location
    const data = await service.weather.getWeather(location)
    await ctx.render('weather', { data })
  }
}

module.exports = WeatherController;

service部分:

// service/weather.js

'use strict'

const Service = require('egg').Service

class WeatherService extends Service {
  async getWeather(location) {
    const { app } = this
    const data = await app.curl('https://api.map.baidu.com/telematics/v3/weather', {
      data: {
        ak: 'zVo5SStav7IUiVON0kuCogecm87lonOj',
        output: 'json',
        location
      },
      dataType: 'json'
    });

    if(data.data.error === 0) {
      return data.data.results && data.data.results[0]
    } else {
      return {
        code: -1,
        msg: '请输入正确的城市名字'
      }
    }
  }
}

module.exports = WeatherService

⚠️ 这里我们是使用了百度提供的天气查询API:https://api.map.baidu.com/telematics/v3/weather 需要的传参如上所示

还有个重头文件router.js,我们的页面是根据这个路由文件,通过controller来控制不同视图的展示。

// router.js

module.exports = app => {
  const { router, controller } = app;

  // weather
  router.get('/weather', controller.weather.getWeather)
  router.post('/weather', controller.weather.postWeather)
};

最终效果

  1. 输入正确的城市进行搜索

valid_city

  1. 输入不正确的城市进行搜索

invalid_city

后话

这次的讲解没有引入数据库,下篇文章讲解的是前后端分离的eggjs项目,会将数据库也引入。更多的项目详见Jimmy Blogs

源码

源码请见仓库egg demo ~

@reng99 reng99 added blog a single blog javascript javascript tag labels Sep 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blog a single blog javascript javascript tag
Projects
None yet
Development

No branches or pull requests

1 participant