Comment.js:一个纯JS实现的静态站点评论系统

orangecat 发布于2年前
0 条问题

前言

我的博客最早是使用 Disqus 来实现评论功能的。Disqus 被墙了之后,改成了多说。今年年初,多说也正式关闭了,于是我被逼着又开始寻找其他的替代评论系统。

我先是试用了网易云跟贴、畅言等几种类似的社会化评论系统。畅言要求站点必须备案,而我实在没有为了评论去申请备案的动力。网易云跟贴的管理后台上有很多不明觉厉的功能,但好像都没多大用处。最致命的问题是我不小心把我的站点绑定到了另一个网易账户,而不是我常用的微博账户。这样的话,我每次回贴就得退登到微博账户,要管理贴子的时候又得切回管理员账户,非常不方便。然而网易云跟贴并没有提供解绑的功能。于是我给他们提了需求,然而一直到现在都没有回复。再加上有了多说作为前车之鉴,我对国内的免费评论服务已经失去了信心。今天把A换成B,难以保证日后B也关闭了,被逼着又换到C,实在是懒得折腾下去啊。于是,我放弃了换用类似的评论系统的念头。

之后我找到了 isso 项目,它是一个 Python 实现的开源评论服务。这个服务需要搭建在自己的服务器上。官方的简介简明扼要:“a Disqus alternative”。出于对 Python 的好感,我把站点的评论功能迁移到了 isso 。然而,我对 isso 也并不是很满意。首先它的功能其实也非常弱,不支持 Markdown 语法,不支持 Gravatar 头像,也没有一个像样的管理后台,搭建和配置的过程也比较费时,远达不到开箱即用的程度。再加上 isso 需要服务器运营,为了一个评论系统而去购买服务器确实太奢侈了。用了几个月后,我又萌生了换掉它的念头。

项目介绍

我的想法来源于一些基于 Github issue 的博客。其实 Github 的 issue 本身就是一个非常完善的评论系统,有完善的管理后台,灵活的通知设置,而且 Github 是开放 API 的。只要我能把 Github 的 issue 与博客的页面打通,把 issue 上的内容显示在我的博客上,然后在需要评论的时候点击跳转到 Github 的 issue 页,就实现了一个基本可用的评论系统了。

comment.js 就是基于这个想法实现的一个评论系统,它的核心代码只有 400 行左右,却能够用来实现评论会话和最新评论列表的两个功能。比起已有的社会化评论系统,它有如下几个优点:

  1. 完善的评论管理系统。基于 issue 的评论,支持 Markdown ,支持 Gravatar。
  2. 开箱即用的邮件通知功能。Github 的邮件通知功能非常完善,不像 isso 那样还得配置邮件通知服务。
  3. 无需搭建后台。直接用现成的 issue 作为后端,不像 isso 那样还需要自己搭个后台,搞定数据库。
  4. 接入简单。获取评论会话和获取最新列表各自对应一个函数。
  5. 代码简单。这意味着你也可以很快上手脚本代码,对这个脚本进行定制。
  6. 除了 Github issue 之外,comment.js 也支持使用 OSChina issue 作为后端,,即使 Github 被墙,也能通过修改参数迅速切换到其他备选站点,比起说关闭就关闭的评论服务可靠多了。

接入方法

comment.js 依赖几个 JS 前端库:

  • jQuery - 用于 Ajax 请求以及将评论内容插入到页面中。
  • markdown-js - Markdown 支持。
  • timeago.js - 时间文本格式化。
  • spin - 用于在加载评论数据前先绘制一个 loading 动画(可选)。

0. 添加静态资源文件

在页面中添加这些资源:

<!-- stylesheet -->
<linkrel="stylesheet"href="path_to_comment_css/comment.css">

<!-- javascripts -->
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.js">/script>
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/markdown.js/0.5.0/markdown.min.js">/script>
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/timeago.js/3.0.2/timeago.min.js"></script>
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js"></script>
<scriptsrc="path_to_comment_js/comment.js"></script>

1. 注册 OAuth App

为了避免 API 被恶意滥用,Github API (以及 OSChina API)设定了一个 API调用频率限制 。为了提高频率限额,建议 [注册一个 Oauth App](Register a OAuth application]( https://github.com/settings/applications/new )。

完成注册后,你将得到一个 client id 以及一个 client_secret ,先将这两个值记下来,后面我们会用到。

(提示:注册 App 的时候你可能会对 Authorization callback URL 这一项目感到困惑,一般填写你的站点地址即可。例如http://hahack.com )

2. 获取评论会话

第一步,在页面中添加一个 DIV ,用于展示评论会话内容。

<divid="comment-thread"></div>

第二步(可选),如果希望在加载完数据前先展示一个loading动画,还可以添加一个用于动画的 DIV :

<divid="loading-spin"></div>

最后,调用 getComments() 方法,获取该页面对应的 issue 包含的所有评论,然后展示到我们指定的 DIV 中:

<script type="text/javascript">
   var opt = {
       type: "github",
       user: "wzpan",
       repo: "comment.js",
       no_comment: "No comments yet. Press the button and go to comment now!",
       go_to_comment: "Go to comment",
       issue_id: "1",
       btn_class: "btn",
       comments_target: "#comment-thread",
       loading_target: "#loading-spin",
       client_id: "xxxxxx",
       client_secret: "xxxxxx"
   };
   getComments(opt);
</script>

参数说明:

  • type : 要作为后端的站点。目前支持 Github 和 OSChina 。
  • user : 您的 Github 用户名。
  • repo : 您用作评论后端的仓库名。
  • no_comment : 当没有评论时,展示的提示消息。
  • go_to_comment : “去留言” 按钮的按钮文本。
  • issue_title : 您当前页面对应的 issue 标题。也可以使用 issue_id ,二者只选其一。
  • issue_id : 您当前页面对应的 issue id。也可以使用 issue_title ,二者只选其一。
  • btn_class : “去留言”按钮的 CSS 样式名。
  • comments_target : 用于展示评论内容的容器。例如我们上面所写的 comment-thread DIV 。
  • loading_target (可选):用于展示 loading 动画的容器。例如我们上面所写的 loading-spin DIV 。
  • client_id (可选但建议):您注册的 OAuth App 的 client id。
  • client_secret (可选但建议):您注册的 OAuth App 的 client secret。

效果参见本页面下方的留言区。

3. 获取最新评论列表

评论列表用于获取你最近的若干条评论,效果可以参见站点首页 右侧的最新留言区。

要获取最新评论列表的方法也大同小异。首先写一个 DIV 用于加载获取得到的评论列表数据:

<divid="recent-comments"></div>

之后可以调用 getRecentCommentsList() 方法,获取最近评论列表并展示到指定的 DIV 中。

<script type="text/javascript">
   var opt = {
       type: "github",
       user: "wzpan",
       repo: "comment.js",
       recent_comments_target: "#recent-comments",
       count: 5,
       client_id: "xxxxxx",
       client_secret: "xxxxxx"
   };
   getRecentCommentsList(opt);
</script>

参数说明:

  • type : 要作为后端的站点。目前支持 Github 和 OSChina 。
  • user : 您的 Github 用户名。
  • repo : 您用作评论后端的仓库名。
  • recent_comments_target : 用于展示最新评论列表的容器。例如我们上面所写的 recent-comments DIV 。
  • count : 列表的最大长度。
  • client_id (可选但建议):您注册的 OAuth App 的 client id。
  • client_secret (可选但建议):您注册的 OAuth App 的 client secret。

开发心得

下面照例总结下项目的开发心得。虽然整个项目只有几百行的代码,但这个过程中还是不可避免的遇到一些困难。

关于选型和项目命名

一开始的想法只是给 Hexo 写一个插件,让其能够实现评论功能。最理想的情况是类似 hexo-generator-search 那样,npm install 一下,然后 _config.yml 里添加下配置就完事。通过阅读 Hexo 的文档后我发现 helper 似乎比较适合用作这个目的:把核心功能写成一个 helper ,然后在模板文件里直接执行这个 helper ,得到的数据还能进一步再模板中调诸如 markdown 等其他现成的 helper, 这样还能实现 Markdown 支持。于是我最初的项目仓库名叫做 hexo-helper-github-comment 。

等我实现了 getComments() 方法后,我发现我的想法是错误的:helper 只适用于同步执行的操作,不适合网络请求这种异步操作。这带来的问题就是模板文件里已经成功执行了 helper 了,也返回了数据,但此时 renderer 早已经完成了模板的渲染了,而异步返回的评论数据却不再能够被渲染。

之后我想在 NodeJS 中加入 jQuery,用 jQuery 来操纵 DOM ,而不再依赖 renderer 。但这个方案似乎也不可行。因为在模板文件中,DOM 还没有创建,jQuery 拿不到实际的 DOM 。

所以最终我改成了纯 JS 的方案,把请求的方式也从 request-promise 改成了 AJAX ,然后在模板文件中直接跑 JS ,让 JS 完成请求,此时的 DOM 是已创建的,可以使用 jQuery 来操纵页面。虽然这样做就不能直接用 Hexo 现成的 markdown helper 了,但由于是纯 JS 实现,这个库也就可以在任何静态站点中使用,变得更加通用了。于是我把仓库名改成了 github-comment 。

又后来,我准备开源的前一天,在微博上先公开了关于这个项目的信息。有些人也表示了 Github 将来也可能被墙的质疑。于是我花了几分钟时间,也加入了对 OSChina 的支持。这个仓库名似乎也不只是基于 Github 了,于是我又把仓库名改成了 comment.js 。

关于取舍

我最纠结的部分,在于要不要把评论框也写进来。

直接在页面中写评论,减少了页面的跳数,当然是一大收益。但这样做也有几个问题:

  1. 功能可用性和项目的复杂度的取舍。Github 的编辑框其实包含了非常多的功能,例如支持拖拽的附件添加、表情、预览、快捷键等等,如果不把这些功能加进来,编辑框的功能就显得很鸡肋,远不如在 Github 中评论有趣;如果加进来,整个项目的代码就远不止 400 行这么简单了。
  2. 通用性和专用程度的取舍。为了避免 Github 单点问题,comment.js 还支持 OSChina 作为备选评论系统。加入 Github 的这些编辑功能,是否会影响对其他站点后端的兼容性又是个问题。
  3. 界面美观程度和版权的取舍。现在的评论会话界面几乎照搬了 Github 的样式,因为点击“去留言”按钮实际上直接跳到了 Github ,相当于为 Github 做了引流,给了一个大大的版权说明,也就没有了侵权的担忧。如果界面完全隔离了 Github,也隐藏了 Github 的版权信息,反而有点滥用平台的感觉在。

有意思的是,当我刚发布 comment.js 的时候,我才发现几个月前已经有人做了一个类似的项目: gitment ,真是心有灵犀啊。这个项目与我的项目的最大区别就在于它实现了内置的编辑框,并且目前只支持 Github 。如果你认为评论框必不可少,那么建议使用 gitment;反之如果你觉得点击按钮跳到 Github 页面似乎也还能接受,担心 Github 单点问题,而且觉得保证代码的简单和通用性更重要的话,那么不妨使用 comment.js 。

查看原文: Comment.js:一个纯JS实现的静态站点评论系统

  • organicpanda
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。