在平常的項目中,有時候仍是不可避免的會維護一些jq官網項目等。面對此類需求,不少仍是之前的老套路,前端寫頁面交給後端去套數據。很煩有木有~~而改動以後還得交給後端再次修改,時間和溝通都是個麻煩。同時開發中,寫靜態頁面也很麻煩,不能複用,不能使用如今的工具,心累有木有~~固然了,解決辦法不少javascript
而本文介紹一下node的egg.js框架配合模板引擎來快速開發項目的模式。上手簡單快速,一我的搞定先後端。PS:又能夠學習新知識來,我好(草)開(泥)心(馬),奧利給~~~css
# 初始化
cnpm init egg --type=simple
# 安裝依賴
cnpm i
# 啓動服務
npm run dev
複製代碼
簡單看下生成的文件目錄(ps:個別文件是沒有的,後期本身添加的)html
先介紹一下egg中app下的這些文件的基本做用,有個大概的概念:前端
定義路由,首先要打開app/router.js文件,在裏面進行定義,例如:vue
'use strict';
module.exports = app => {
const { router, controller } = app;
// 定義首頁的路由
// 即當直接訪問域名的時候,將請求映射到controller.home.home中進行進一步的處理
router.get('/', controller.home.home);
// 定義關於咱們的路由
router.get('/about', controller.home.about);
// 定義新聞詳情的路由
router.get('/details/:id', controller.home.details);
};
複製代碼
此處的路由能夠理解爲就是咱們訪問的域名後面的具體的路徑地址。例如xxx.com/about中的/about
java
controller.xx.xx是指當咱們訪問了這個路由的時候,服務將當前路由映射到這個控制器中。具體的控制器做用,下面會詳細介紹。node
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async home() {
const { ctx } = this;
await ctx.render('index.njk')
}
}
module.exports = HomeController
// 或者你也能夠簡化一下寫法
module.exports = class extends require('egg').Controller {
// ...
}
複製代碼
下面演示一個調用service的例子:jquery
// app/controller/home.js
'use strict';
module.exports = class extends require('egg').Controller {
async details() {
const { ctx } = this;
try {
// 調用service的home模塊中的details服務
// 獲得數據後,塞給靜態模板使用
const data = await ctx.service.home.details(ctx.params.id)
// 渲染一個模板
await ctx.render('details.njk', data)
} catch (error) {
ctx.body = '新聞獲取出錯'
}
}
}
複製代碼
service服務主要是用來作什麼的呢?上面在controller中也提到了,主要用來獲取數據,拿到數據以後也能夠格式化再返回給controller使用。webpack
下面演示一個service調用某些接口服務獲得數據並返回給controller使用:ios
// 首先須要在app/下新建service文件夾
// 而後在service下新建home.js,最終爲app/service/home.js
'use strict';
module.exports = class extends require('egg').Service {
// 根據文章id獲取文章數據
// 此處的id是controll調用service服務時傳遞的id
async details(id) {
try {
const url = `https:xxxx.com/api/${id}`
const { data } = await this.ctx.curl(url, { dataType: 'json' })
if (data.data && data.code === 200) {
// 此處也能夠對數據進行處理後再返回
// 返回數據
return data.data
}
throw '數據獲取失敗'
} catch (error) {
throw error
}
}
}
複製代碼
home.js
,是由於咱們controller
中使用的是ctx.service.home
service.home
中的home
就是service
文件的文件名稱this.ctx.curl
方法請求其餘接口的數據。相似於使用axios
獲取數據的操做。定義好了基本的路由、控制器和service以後,就剩下模板了。首先模板,多是前端小夥伴寫的靜態頁面給到咱們的(ps:這個前端充氣小夥伴或許就是咱們本身!哦呸,不是充氣的)
好了,言歸正傳!Egg中有關於模板渲染的文檔,能夠看一下。Egg自己內置了egg-view做爲模板的解決方案,其中View支持插件egg-view-nunjucks,本文也是經過該插件進行的模板開發。
# 首先安裝
cnpm i egg-view-nunjucks --save
# 而後在根目錄下的config/plugin.js中使用插件
'use strict';
module.exports = {
nunjucks: {
enable: true,
package: 'egg-view-nunjucks',
}
};
# 完成了插件的安裝和引入,咱們還須要配置插件的參數
# 根目錄下的config/config.default.js中
module.exports = appInfo => {
// 其餘代碼
// ...
// 配置咱們的插件參數
config.view = {
// 定義映射的文件後綴名
// 此處咱們定義爲.njk,那麼咱們的模板都須要以.njk結束,
// 這樣該類型的文件纔會被咱們的模板插件進行處理
mapping: {
'.njk': 'nunjucks',
}
}
// 其餘代碼
// ...
}
複製代碼
.njk
也是能夠的,這個是自定義的,只要知足你的模板文件的後綴名和你定義的同樣就行,這樣纔會被插件處理。egg-view-nunjucks
封裝的是nunjucks
,nunjucks
推薦叫.njk
egg-view-nunjucks文檔 nunjucks文檔
有了模板引擎,咱們嵌套數據等就會方便不少了。下面來簡單看下一個模板的文件夾:
下面咱們簡單看下base.njk
這個模板,作了什麼事情:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>{% block title %}title默認內容{% endblock %}</title>
<meta name="keywords" content="{% block keywords %}keywords默認內容{% endblock %}">
<meta name="description" content="{% block description %}description默認內容{% endblock %}">
<link rel="stylesheet" type="text/css" href="../../public/css/base.css">
{% block head %}{% endblock %}
</head>
<body>
<!-- 主體內容部分 -->
{% block content %}{% endblock %}
<script src="../../public/js/jquery.js"></script>
<!-- script部分 -->
{% block script %}{% endblock %}
</body>
</html>
複製代碼
block
塊,這樣就能夠在頁面中替換掉這塊的內容。有些相似於vue的slot
插槽。// 定義block塊
{% block title %}默認內容{% endblock %}
複製代碼
名稱 | 說明 |
---|---|
head塊 | 用於在head內最底部插入一些代碼。例如,公共模板引入了公共css,可是每一個頁面還有可能單獨引入css,全局只有一個css文件的除外 |
content塊 | 用於放置每一個頁面的主體部分 |
script塊 | 用於放置每一個頁面須要單獨引入的js文件 |
定義好了基本的模板和塊,下面咱們看下頁面中如何使用:
{% extends "./base/base.njk" %}
{% block title %}這是一個新的title{% endblock %}
{% block description %}這是一個新的description{% endblock %}
{% block keywords %}壹沓科技,加入壹沓,聯繫咱們{% endblock %}
{% set navActive = "about" %}
{% block head %}
<link rel="stylesheet" href="../public/css/swiper.min.css">
{% endblock %}
{% block content %}
<div class="page-wrapper">
<!-- 導入公共的nav模板 -->
{% include './base/nav.njk' %}
<!-- 背景圖 -->
<section class="banner-wrapper">
<img src="../public/img/icon/about-banner.jpg" alt="背景LOGO">
<span>{{ userName }}</span>
</section>
<!-- 渲染html模板演示 -->
<div>{{content | safe}}</div>
<!-- 導入公共的底部模板 -->
{% include './base/foot.njk' %}
</div>
{% endblock %}
{% block script %}
<script src="../public/js/swiper.min.js"></script>
<script src="../public/js/about.js"></script>
{% endblock %}
複製代碼
// 相對路徑便可
{% extends "./base/base.njk" %}
複製代碼
// 例如,設置該頁面的title
// 若是不設置,就會使用基礎模板中默認的
{% block title %}這是一個新的title{% endblock %}
複製代碼
// 定義了一個navActive變量
// 後面會講解一個常見的場景
{% set navActive = "about" %}
複製代碼
// 變量的使用,和vue的{{}}插值同樣
// 好比這個userName是咱們從controller中調用service獲取的數據對象中的一個屬性,
// 而後把對象傳遞給了模板,
// 那麼在模板中能夠直接取對象中的屬性進行渲染
// 注意,傳遞給模板的是一個對象,例如{userName: 'jack'},可是咱們使用的時候直接取userName
{{userName}}
// 一樣的,咱們在模板內定義的變量也能夠直接使用的
// 渲染html,好比很常見的富文本
// 相似vue的過濾器,這個safe是內置的,
// 過濾器也能夠自定義,具體的查看文檔吧
{{content | safe}}
複製代碼
// 導入咱們的nav模板
{% include './base/nav.njk' %}
複製代碼
<!-- 導航頭部 -->
<nav class="nav-wrapper">
<ul class="menu-content">
<li>
<a href="/news" class="{{ 'active' if navActive == 'news' else '' }}">動態資訊</a>
</li>
<li>
<a href="/about" class="{{ 'active' if navActive == 'about' else '' }}">關於咱們</a>
</li>
</ul>
</nav>
複製代碼
能夠看到,咱們對class名
進行了一個if判斷,判斷當變量navActive
是某些值的時候給他增長一個active
類名,不然就是各空的class名
。這裏仔細注意一下寫法便可。 那麼咱們怎麼定義變量呢?此時再回到上面定義變量的部分介紹,咱們已經在頁面中定義了一個變量navActive
,因此咱們只須要每一個頁面定義一個navActive
且值爲咱們須要的便可了。
router.js
中定義的路由便可,而不是寫的模板地址。// a標籤跳轉
<a href="/news"></a>
// js調整也是同樣,使用router.js定義的路由
window.location.href="/news"
複製代碼
百尺竿頭、日進一步 我是大家的老朋友愣錘~ 喜歡的小夥伴歡迎關注點贊,一塊兒分享交流更多的前端好玩技術!