首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
安装 Node.js
安装与启动 MongoDB
require
exports 和 module.exports
Promise
环境变量
package.json
npm 使用注意事项
初始化一个 Express 项目
路由
模板引擎
Express 浅析
开发环境
准备工作
配置文件
功能与路由设计
页面设计
连接数据库
注册
登出与登录
文章模块
留言模块
当前位置:
首页>>
技术小册>>
Nodejs开发博客应用
小册名称:Nodejs开发博客应用
我们使用要实现的页面列表: **注册页** **登录页** **未登录时的主页(或用户页)** **登录后的主页(或用户页)** **发表文章页** **编辑文章页** **未登录时的文章页** **登录后的文章页** **通知** ## 4.5.1 组件 前面提到过,我们可以将模板拆分成一些组件,然后使用 ejs 的 include 方法将组件组合起来进行渲染。我们将页面切分成以下组件: **主页** **文章页** 我们创建以下样式及模板文件: **public/css/style.css** ```css /* ---------- 全局样式 ---------- */ body { width: 1100px; height: 100%; margin: 0 auto; padding-top: 40px; } a:hover { border-bottom: 3px solid #4fc08d; } .button { background-color: #4fc08d !important; color: #fff !important; } .avatar { border-radius: 3px; width: 48px; height: 48px; float: right; } /* ---------- nav ---------- */ .nav { margin-bottom: 20px; color: #999; text-align: center; } .nav h1 { color: #4fc08d; display: inline-block; margin: 10px 0; } /* ---------- nav-setting ---------- */ .nav-setting { position: fixed; right: 30px; top: 35px; z-index: 999; } .nav-setting .ui.dropdown.button { padding: 10px 10px 0 10px; background-color: #fff !important; } .nav-setting .icon.bars { color: #000; font-size: 18px; } /* ---------- post-content ---------- */ .post-content h3 a { color: #4fc08d !important; } .post-content .tag { font-size: 13px; margin-right: 5px; color: #999; } .post-content .tag.right { float: right; margin-right: 0; } .post-content .tag.right a { color: #999; } ``` **views/header.ejs** ```ejs <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title><%= blog.title %></title> <link rel="stylesheet" href="//cdn.bootcss.com/semantic-ui/2.1.8/semantic.min.css"> <link rel="stylesheet" href="/css/style.css"> <script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script> <script src="//cdn.bootcss.com/semantic-ui/2.1.8/semantic.min.js"></script> </head> <body> <%- include('components/nav') %> <%- include('components/nav-setting') %> <%- include('components/notification') %> ``` **views/footer.ejs** ```ejs <script type="text/javascript"> $(document).ready(function () { // 点击按钮弹出下拉框 $('.ui.dropdown').dropdown(); // 鼠标悬浮在头像上,弹出气泡提示框 $('.post-content .avatar-link').popup({ inline: true, position: 'bottom right', lastResort: 'bottom right' }); }) </script> </body> </html> ``` > 注意:上面 `<script></script>` 是 semantic-ui 操控页面控件的代码,一定要放到 footer.ejs 的 `</body>` 的前面,因为只有页面加载完后才能通过 JQuery 获取 DOM 元素。 在 views 目录下新建 components 目录用来存放组件(即可以复用的模板片段),在该目录下创建以下文件: **views/components/nav.ejs** ```ejs <div class="nav"> <div class="ui grid"> <div class="four wide column"></div> <div class="eight wide column"> <a href="/posts"><h1><%= blog.title %></h1></a> <p><%= blog.description %></p> </div> </div> </div> ``` **views/components/nav-setting.ejs** ```ejs <div class="nav-setting"> <div class="ui buttons"> <div class="ui floating dropdown button"> <i class="icon bars"></i> <div class="menu"> <% if (user) { %> <a class="item" href="/posts?author=<%= user._id %>">个人主页</a> <div class="divider"></div> <a class="item" href="/posts/create">发表文章</a> <a class="item" href="/signout">登出</a> <% } else { %> <a class="item" href="/signin">登录</a> <a class="item" href="/signup">注册</a> <% } %> </div> </div> </div> </div> ``` **views/components/notification.ejs** ```ejs <div class="ui grid"> <div class="four wide column"></div> <div class="eight wide column"> <% if (success) { %> <div class="ui success message"> <p><%= success %></p> </div> <% } %> <% if (error) { %> <div class="ui error message"> <p><%= error %></p> </div> <% } %> </div> </div> ``` ## 4.5.2 app.locals 和 res.locals 上面的 ejs 模板中我们用到了 blog、user、success、error 变量,我们将 blog 变量挂载到 `app.locals` 下,将 user、success、error 挂载到 `res.locals` 下。为什么要这么做呢?`app.locals` 和 `res.locals` 是什么?它们有什么区别? express 中有两个对象可用于模板的渲染:`app.locals` 和 `res.locals`。我们从 express 源码一探究竟: **express/lib/application.js** ```js app.render = function render(name, options, callback) { ... var opts = options; var renderOptions = {}; ... // merge app.locals merge(renderOptions, this.locals); // merge options._locals if (opts._locals) { merge(renderOptions, opts._locals); } // merge options merge(renderOptions, opts); ... tryRender(view, renderOptions, done); }; ``` **express/lib/response.js** ```js res.render = function render(view, options, callback) { var app = this.req.app; var opts = options || {}; ... // merge res.locals opts._locals = self.locals; ... // render app.render(view, opts, done); }; ``` 可以看出:在调用 `res.render` 的时候,express 合并(merge)了 3 处的结果后传入要渲染的模板,优先级:`res.render` 传入的对象> `res.locals` 对象 > `app.locals` 对象,所以 `app.locals` 和 `res.locals` 几乎没有区别,都用来渲染模板,使用上的区别在于:`app.locals` 上通常挂载常量信息(如博客名、描述、作者这种不会变的信息),`res.locals` 上通常挂载变量信息,即每次请求可能的值都不一样(如请求者信息,`res.locals.user = req.session.user`)。 修改 index.js,在 `routes(app)` 上一行添加如下代码: ```js // 设置模板全局常量 app.locals.blog = { title: pkg.name, description: pkg.description } // 添加模板必需的三个变量 app.use(function (req, res, next) { res.locals.user = req.session.user res.locals.success = req.flash('success').toString() res.locals.error = req.flash('error').toString() next() }) ``` 这样在调用 `res.render` 的时候就不用传入这四个变量了,express 为我们自动 merge 并传入了模板,所以我们可以在模板中直接使用这四个变量。
上一篇:
功能与路由设计
下一篇:
连接数据库
该分类下的相关小册推荐:
Nodejs底层原理与源码解读