课程表

Meteor课程

工具箱
速查手册

Meteor 通知

当前位置:免费教程 » JS/JS库/框架 » Meteor

现在用户们可以给帖子添加评论了,让他们互相知道讨论已经开始了是个好主意。

我们将通知帖子的作者已经有用户在他的帖子上添加了评论,并且提供一个链接可以看到评论。

这是 Meteor 真正闪光的特性之一:因为 Meteor 在默认情况下是实时的,我们会_瞬时_看到这些 notifications。不需要用户去刷新页面或者做其他检查,我们不需要写任何特殊代码就可以得到一个简单的 notifications 弹出框。

生成 Notifications

当有人在你的帖子上添加评论时我们将生成一个 notification。在后面,notifications 会扩展覆盖很多其他情况,但是目前让用户知道正在发生什么就足够了。

让我们先创建一个 Notifications 集合,和一个方法 createCommentNotification,当有人在你的帖子下添加评论时该方法会添加一个 notification 到集合。

因为我们将从客户端更新 notifications, 我们需要确定 allow 方法是防弹的。我们检查如下内容:

  • 用户是文档的创建者才能调用 update 方法
  • 用户只更新一个属性
  • 更新的属性名字是 read
  1. Notifications = new Mongo.Collection('notifications');
  2. Notifications.allow({
  3. update: function(userId, doc, fieldNames) {
  4. return ownsDocument(userId, doc) &&
  5. fieldNames.length === 1 && fieldNames[0] === 'read';
  6. }
  7. });
  8. createCommentNotification = function(comment) {
  9. var post = Posts.findOne(comment.postId);
  10. if (comment.userId !== post.userId) {
  11. Notifications.insert({
  12. userId: post.userId,
  13. postId: post._id,
  14. commentId: comment._id,
  15. commenterName: comment.author,
  16. read: false
  17. });
  18. }
  19. };

和帖子和评论一样,Notifications 集合也是在服务器端和客户端共享的。用户看完 notifications 后,我们需要更新他们,因此需要允许更新操作。和其他部分一样只有拥有 notification 的用户才允许更新操作。

我们写了个简单的程序用来当用户给帖子添加评论时找到需要通知的用户,并插入一个新的 notification。

我们已经在服务器端方法创建了评论对象,我们用 comment._id = Comments.insert(comment) 来替换 return Comments.insert(comment);。这样就能在评论对象中保存 _id, 然后调用 createCommentNotification 方法:

  1. Comments = new Mongo.Collection('comments');
  2. Meteor.methods({
  3. commentInsert: function(commentAttributes) {
  4. //...
  5. comment = _.extend(commentAttributes, {
  6. userId: user._id,
  7. author: user.username,
  8. submitted: new Date()
  9. });
  10. // update the post with the number of comments
  11. Posts.update(comment.postId, {$inc: {commentsCount: 1}});
  12. // create the comment, save the id
  13. comment._id = Comments.insert(comment);
  14. // now create a notification, informing the user that there's been a comment
  15. createCommentNotification(comment);
  16. return comment._id;
  17. }
  18. });

接下来发布 notifications:

  1. Meteor.publish('posts', function() {
  2. return Posts.find();
  3. });
  4. Meteor.publish('comments', function(postId) {
  5. check(postId, String);
  6. return Comments.find({postId: postId});
  7. });
  8. Meteor.publish('notifications', function() {
  9. return Notifications.find();
  10. });

在客户端订阅 notifications:

  1. Router.configure({
  2. layoutTemplate: 'layout',
  3. loadingTemplate: 'loading',
  4. notFoundTemplate: 'notFound',
  5. waitOn: function() {
  6. return [Meteor.subscribe('posts'), Meteor.subscribe('notifications')]
  7. }
  8. });

显示 Notifications

现在我们在 header 中添加一个 notifications 列表。

  1. <template name="header">
  2. <nav class="navbar navbar-default" role="navigation">
  3. <div class="container-fluid">
  4. <div class="navbar-header">
  5. <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navigation">
  6. <span class="sr-only">Toggle navigation</span>
  7. <span class="icon-bar"></span>
  8. <span class="icon-bar"></span>
  9. <span class="icon-bar"></span>
  10. </button>
  11. <a class="navbar-brand" href="{{pathFor 'postsList'}}">Microscope</a>
  12. </div>
  13. <div class="collapse navbar-collapse" id="navigation">
  14. <ul class="nav navbar-nav">
  15. {{#if currentUser}}
  16. <li>
  17. <a href="{{pathFor 'postSubmit'}}">Submit Post</a>
  18. </li>
  19. <li class="dropdown">
  20. {{> notifications}}
  21. </li>
  22. {{/if}}
  23. </ul>
  24. <ul class="nav navbar-nav navbar-right">
  25. {{> loginButtons}}
  26. </ul>
  27. </div>
  28. </div>
  29. </nav>
  30. </template>

接下来创建 notificationsnotificationItem 模板 (两个模板都在 notifications.html 文件中):

  1. <template name="notifications">
  2. <a href="#" class="dropdown-toggle" data-toggle="dropdown">
  3. Notifications
  4. {{#if notificationCount}}
  5. <span class="badge badge-inverse">{{notificationCount}}</span>
  6. {{/if}}
  7. <b class="caret"></b>
  8. </a>
  9. <ul class="notification dropdown-menu">
  10. {{#if notificationCount}}
  11. {{#each notifications}}
  12. {{> notificationItem}}
  13. {{/each}}
  14. {{else}}
  15. <li><span>No Notifications</span></li>
  16. {{/if}}
  17. </ul>
  18. </template>
  19. <template name="notificationItem">
  20. <li>
  21. <a href="{{notificationPostPath}}">
  22. <strong>{{commenterName}}</strong> commented on your post
  23. </a>
  24. </li>
  25. </template>

我们可以看到每个 notification 有一个指向帖子的链接,而且包含注释作者的名字。

接下来我们需要确定在 helper 中选择了正确的 notifications 列表,并且在用户点击链接后将 notifications 标记为已读。

  1. Template.notifications.helpers({
  2. notifications: function() {
  3. return Notifications.find({userId: Meteor.userId(), read: false});
  4. },
  5. notificationCount: function(){
  6. return Notifications.find({userId: Meteor.userId(), read: false}).count();
  7. }
  8. });
  9. Template.notificationItem.helpers({
  10. notificationPostPath: function() {
  11. return Router.routes.postPage.path({_id: this.postId});
  12. }
  13. });
  14. Template.notificationItem.events({
  15. 'click a': function() {
  16. Notifications.update(this._id, {$set: {read: true}});
  17. }
  18. });

你可能觉得 notifications 和 errors 很像,是的从结构上看他们很相似。但有一点不同: 我们为 notification 创建了一个集合。这意味着 notification 是持久化的,他对于同一用户不论浏览器刷新还是跨设备都是存在的。

试一下: 打开一个新的浏览器 (比如 Firefox), 然后创建一个新用户, 然后在主用户的帖子下发表一个评论 (在 Chrome 中)。你将看到如下:

控制 notifications 的访问权限

Notifications 工作的很好。然后这有一个小问题:所有人都能看到我们的 notifications。

如果你的浏览器还开着,试一下在浏览器 console 中输入以下 js 代码:

  1. Notifications.find().count();
  2. 1

一个新的用户 (当有帖子被评论时) 不该收到任何 notifications. Notifications 集合中的内容实际上属于以前的用户。

除了可能的隐私问题外,我们不能让浏览器显示每条 notifications 的原因是. 对于一个足够规模的网站,这么做会很容易耗尽浏览器内存,并带来严重的性能问题。

我们通过 publications 来解决这个问题。我们可以通过 publications 来精确的指定哪部分集合我们想共享给其他用户。

为了实现这个,我们需要在 publication 中返回不同的 cursor 而不是使用 Notifications.find()。换句话说,我们返回的 cursor 是和当前用户的 notificatons 相关的。

这么做足够直接,因为 publish 函数有当前用户的 _id, 它存在于 this.userId 中:

  1. Meteor.publish('notifications', function() {
  2. return Notifications.find({userId: this.userId, read: false});
  3. });

现在看一下我们的两个浏览器窗口,我们会看到两个不同的 notifications 集合。

  1. Notifications.find().count();
  2. 1
  1. Notifications.find().count();
  2. 0

实际上,当你登录和登出时 Notifications 集合都会变化。这是因为当账户变化时 publications 会自动重新发布。

我们的 app 功能越来越完善,当越来越多的用户发帖时,我们的首页会无限长。下一章我们通过分页来解决这个问题。

转载本站内容时,请务必注明来自W3xue,违者必究。
 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号