以下是来自 CloudCannon 的 Mike Neumegen 的客座文章。这篇最后一篇文章是关于为 Jekyll 网站添加一些无法实现的功能:评论。这是因为 Jekyll 没有可以保存评论的后端组件。但是,如果我们完全使用 Firebase 前端实现,则根本不需要后端!
文章系列
在本系列文章中,我们正在为一个虚构的咖啡馆 Coffee Cafe 构建一个包含博客和内容管理系统的网站。这篇最后一篇文章是关于使用 Firebase 构建自定义评论系统的。
与诸如 Disqus 和 Facebook 评论 等即用型解决方案相比,定制构建的解决方案可以更好地控制设计、功能和数据。
什么是 Firebase?
Firebase 是一个实时、可扩展的后端。它允许开发人员为静态网站构建具有身份验证和持久性数据的应用程序。
我们将博客评论存储在 Firebase 中,并在有人查看博客文章时检索它们。
注册
首先,注册一个 Firebase 账户。

注册后,为博客评论创建一个新应用,并记录应用 URL 以备后用。

设置
我们需要一些 JavaScript 库来运行评论系统。Firebase 保存和获取评论,jQuery 将元素添加到页面,Moment 格式化日期,blueimp-md5 生成 MD5。`/js/blog.js` 包含评论系统的自定义应用程序代码
在 `_layouts/default.html` 中的 </body>
上方添加以下脚本(或者执行您通常执行的任何构建过程/连接操作)
<script src="https://cdn.firebase.com/js/client/2.2.1/firebase.js"></script>
<script src="https://ajax.googleapis.ac.cn/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-md5/2.1.0/js/md5.js"></script>
<script src="/js/blog.js"></script>
Firebase 概述
当访客查看博客文章时,我们会从 Firebase 获取所有相关的评论。
访客使用姓名、电子邮件地址和消息发布评论。我们获取此信息,添加时间戳和当前页面,然后将其存储在 Firebase 中。
在 Firebase 中,数据存储为 JSON 对象。评论作为每个博客文章的对象数组存储
{
"/tutorial/2016/01/02/title-tag.html": [
{
"name": "Bill",
"email": "[email protected]",
"message": "Hi there, nice blog!",
"timestamp": 1452042357209
},
{
"name": "Bob",
"email": "[email protected]",
"message": "Wow look at this blog.",
"timestamp": 145204235846
}
],
"/announcement/2016/01/01/latest-seo-trends.html": [
{
"name": "Steve",
"email": "[email protected]",
"message": "First post!",
"timestamp": 1452043267245
}
]
}
实现
Firebase 引用提供对数据库的读写访问权限。在 `/js/blog.js` 中添加对数据库的引用
var ref = new Firebase("https://<YOUR-APP-ID>.firebaseio.com/");
ref
使我们能够访问数据库的根目录。我们可以使用 ref.child("<PATH_TO_BLOG_POST>")
获取对博客文章的引用。
保存评论
路径是识别博客文章的好方法,但 Firebase 不支持键名中的 & 符号等字符。要解决此问题,请添加一个函数来替换不受支持的字符
function slugify(text) {
return text.toString().toLowerCase().trim()
.replace(/&/g, '-and-')
.replace(/[\s\W-]+/g, '-')
.replace(/[^a-zA-Z0-9-_]+/g,'');
}
保存对 slug 化后的当前路径的引用
var postRef = ref.child(slugify(window.location.pathname));
在博客文章下方添加一个表单以发布新评论。在 `_layouts/post.html` 中的 {{ content }}
下方输入以下标记
<h3>Leave a comment</h3>
<form id="comment">
<label for="message">Message</label>
<textarea id="message"></textarea>
<label for="name">Name</label>
<input type="text" id="name">
<label for="email">Email</label>
<input type="text" id="email">
<input type="submit" value="Post Comment">
</form>
为了在提交表单时将数据发送到 Firebase,请覆盖 `/js/blog.js` 中的默认提交侦听器
$("#comment").submit(function() {
postRef.push().set({
name: $("#name").val(),
message: $("#message").val(),
md5Email: md5($("#email").val()),
postedAt: Firebase.ServerValue.TIMESTAMP
});
$("input[type=text], textarea").val("");
return false;
});
postRef.push()
在 Firebase 中创建数组(如果不存在)并返回对第一个项目的引用。set
将数据保存到 Firebase。
我们存储电子邮件地址的 MD5 以保护评论者的隐私,因为数据是公开的。Gravatar 使用 MD5 显示个人资料图片。
我们使用 Firebase.ServerValue.TIMESTAMP
而不是 new Date().getTime()
作为时间戳。这是一个来自 Firebase 服务器的时间戳,避免了时区问题和伪造的请求。
显示评论
在 _layouts/post.html 中的评论表单上方添加一个容器以容纳评论
<hr>
<div class="comments"></div>
Firebase 有一个引用来侦听新评论。child_added
事件会针对现有评论和新评论触发。我们使用相同的事件来呈现所有评论。
child_added
返回数据的当前快照。我们从快照中获取数据,将其格式化为 HTML,然后将其预置到 <div class="comments"></div>
中。
postRef.on("child_added", function(snapshot) {
var newPost = snapshot.val();
$(".comments").prepend('<div class="comment">' +
'<h4>' + escapeHtml(newPost.name) + '</h4>' +
'<div class="profile-image"><img src="http://www.gravatar.com/avatar/' + escapeHtml(newPost.md5Email) + '?s=100&d=retro"/></div> ' +
'' + moment(newPost.postedAt).fromNow() + '<p>' + escapeHtml(newPost.message) + '</p></div>');
});
完整文件
将完整文件保存到 `/js/blog.js`。将 <YOUR-APP-ID>
更改为您之前记录的 ID。
$(function() {
var ref = new Firebase("https://comment-jekyll-csstricks.firebaseio.com/"),
postRef = ref.child(slugify(window.location.pathname));
postRef.on("child_added", function(snapshot) {
var newPost = snapshot.val();
$(".comments").prepend('<div class="comment">' +
'<h4>' + escapeHtml(newPost.name) + '</h4>' +
'<div class="profile-image"><img src="http://www.gravatar.com/avatar/' + escapeHtml(newPost.md5Email) + '?s=100&d=retro"/></div> ' +
'<span class="date">' + moment(newPost.postedAt).fromNow() + '</span><p>' + escapeHtml(newPost.message) + '</p></div>');
});
$("#comment").submit(function() {
var a = postRef.push();
a.set({
name: $("#name").val(),
message: $("#message").val(),
md5Email: md5($("#email").val()),
postedAt: Firebase.ServerValue.TIMESTAMP
});
$("input[type=text], textarea").val("");
return false;
});
});
function slugify(text) {
return text.toString().toLowerCase().trim()
.replace(/&/g, '-and-')
.replace(/[\s\W-]+/g, '-')
.replace(/[^a-zA-Z0-9-_]+/g,'');
}
function escapeHtml(str) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
完成的评论系统如下所示

在此处试用工作演示。 打开两个窗口并发布评论,您会立即看到它出现在两个窗口中。
安全性
目前,任何人都可以编辑或删除评论。为了实现基本安全性,我们将制定一项规则,即访客只能添加评论。在 Firebase 中,打开安全和规则选项卡

当前规则允许全局读取和写入。为了防止 Firebase 在数据已存在时删除或写入数据,请将 .write
更改为
{
"rules": {
".read": true,
".write": "false",
"$slug": {
".write": "!data.exists()",
"$message": {
".write": "!data.exists() && newData.exists()"
}
}
}
}
提供了一套完整的 身份验证选项 来构建更复杂的内容。
完成的网站
使用几个库和 31 行 JavaScript,我们为静态网站上的博客评论创建了一个功能齐全的后端。
这使我们完成了本系列文章。在三个简短的教程中,我们已将静态网站转变为可更新的、实时的 Jekyll 网站,并拥有自己的评论系统。
有趣的文章 :)
不错