meteor构建app程序_在Meteor.js中构建Slack克隆(第4部分):频道和聊天室

meteor构建app程序

This is the fourth of a five-part series on building a Slack clone using Meteor. The aim of these tutorials are not just for you to blindly follow instructions, but it's our hope that you'll understand the thought process and reasoning behind the architecture.

这是有关使用Meteor构建Slack克隆的五部分系列的第四部分。 这些教程的目的不仅是让您盲目遵循说明,而且我们希望您能理解架构背后的思考过程和推理。

We have already dealt with publish and subscribe functions before when dealing with security, but now we will use the same logic to create different channels (or rooms) and private messaging.

处理安全性之前,我们已经处理过发布和订阅功能,但是现在我们将使用相同的逻辑来创建不同的通道(或会议室)和私人消息传递。

We will also take a look at using sessions to keep track of which channel we are on. Lastly, we will explore using a router to allow us to permalink the channels.

我们还将看一下使用会话来跟踪我们在哪个频道上。 最后,我们将探索使用路由器允许我们永久链接频道。

建立频道 (Creating Channels)

So, let's create a new collection of channels and seed it. Since every Slack room always have two default channels - general and random, we will create those too.

因此,让我们创建一个新的渠道集合并为其添加种子。 由于每个Slack会议室始终都有两个默认通道generalrandom ,我们也将创建它们。

/lib/collections/channels.js

/lib/collections/channels.js

Channels = new Mongo.Collection("channels");

/server/seeder.js

/server/seeder.js

Channels.remove({});
Channels.insert({
  name: "general"
});
Channels.insert({
  name: "random"
});

更新种子消息 (Updating Seeded Messages)

Now that we have two channels, we must associate our seeded messages with a channel. For simplicity, the seeded messages will all be in the general channel.

现在我们有两个渠道,我们必须将播种的消息与一个渠道相关联。 为简单起见,种子消息将全部位于general通道中。

Factory.define('message', Messages, {
    text: function() {
        return Fake.sentence();
    },
    user: Meteor.users.findOne()._id,
    timestamp: Date.now(),
    channel: 'general'
});

更新UI (Updating UI)

Now we have channels, let's update our UI. We will publish our Channels collection and subscribe to it on our client.

现在我们有了频道,让我们更新UI。 我们将发布我们的Channels收藏并在我们的客户上订阅。

server/publications.js

server/publications.js

Meteor.publish('channels', function () {
    return Channels.find();
});

client/startup/subscribe.js

client/startup/subscribe.js

Meteor.subscribe('channels');

We'd now use that subscription to list out each channel on the left sidebar.

现在,我们将使用该订阅在左侧栏中列出每个频道。

client/app.js

client/app.js

Template.listings.helpers({
    channels: function () {
        return Channels.find();
    }
});

client/components/listings.html

client/components/listings.html

{{#each channels}}
    {{> channel name=name}}
{{/each}}

/client/components/channel.html

/client/components/channel.html

<span>
    <span class="prefix">#</span>
    <span class="channel-name">{{name}}</span>
</span>

Now we can see our channels on the sidebar listing.

现在,我们可以在侧边栏列表中看到我们的频道。

channels-sidebar

切换频道 (Switching Channels)

Now we have two channels, there needs to be a mechanism to allow users to switch between them. We will explore two new (to you) features - Sessions and Routing.

现在我们有两个渠道,需要一种允许用户在它们之间切换的机制。 我们将向您探索两个新功能-会话和路由。

With sessions, we'd store a session variable representing our current channel and use that to display our messages at the template-level. We'd then use the Router to update our URL.

对于会话,我们将存储代表当前频道的会话变量,并使用该变量在模板级别显示消息。 然后,我们将使用路由器更新我们的URL。

届会 (Sessions)

Sessions is a global object which is meant to store temporary UI states of the application. The tyoe of data you can store are simple key-value pairs.

会话是一个全局对象,用于存储应用程序的临时 UI状态。 您可以存储的数据类型是简单的键值对。

When you open a new browser tab and go to the application, you'd get a new session object. So different tabs will each have a session object of its own.

当打开新的浏览器选项卡并转到应用程序时,您将获得一个新的会话对象。 因此,不同的选项卡将各自具有其自己的会话对象。

基本会议 (Basic Sessions)

You set a session variable by running

您可以通过运行来设置会话变量

Session.set(key, value)

And retrieve the value of a session variable by running

并通过运行检索会话变量的值

Session.get(key)

So we can use a session variable called channel to keep track of which channel we are currently on.

因此,我们可以使用一个名为channel的会话变量来跟踪我们当前所在的频道。

For simplicity's sake, let's set the default channel to general; this means whenever someone goes to our application, they'll always land on the general channel first.

为了简单起见,让我们将默认通道设置为general ; 这意味着无论何时有人进入我们的应用程序,他们总是将首先登陆general渠道。

Meteor.startup(function() {
    Session.set('channel', 'general');
});

We can also make it so that whenever a channel is clicked, it will update the channel session variable with the name of the channel being clicked.

我们还可以做到这一点,以便每当单击一个频道时,它将使用被单击的频道名称更新channel会话变量。

Template.channel.events({
    'click .channel': function (e) {
        Session.set('channel', this.name);
    }
});

Now if you click on 'general', and then check for the channel session variable, you'll find.

现在,如果您单击“常规”,然后检查channel会话变量,就会找到。

> Session.get('channel')
"general"

And if you click on 'random', the session variable has changed.

如果您单击“随机”,则会话变量已更改。

> Session.get('channel')
"random"
更新UI (Updating UI)

Slack shows a green background only behind the current channel, so let's update our UI to do the same.

Slack 在当前通道后面显示绿色背景,因此让我们更新UI来执行相同的操作。

client/app.js

client/app.js

We will create a new template helper that will return the string "active" if the channel's name matches the value in our channel session variable.

我们将创建一个新的模板帮助器,如果该通道的名称与我们的channel会话变量中的值匹配,它将返回字符串“ active”。

Template.channel.helpers({
    active: function () {
        if (Session.get('channel') === this.name) {
            return "active";
        } else {
            return "";
        }
    }
});

We will then add the class into our client/components/channel.html

然后,我们将类添加到我们的client/components/channel.html

<li class="channel {{active}}">

And now you can see the active channel has a green background, I've also changed the template so the name reflects the current channel.

现在您可以看到活动频道的背景为绿色,我还更改了模板,以便名称反映当前频道。

channel-active-split

The above image also illustrates the fact that different tabs on the same browser and client have different sessions object. Where the channel session variable in one tab is set to general, the other is set to random.

上图还说明了以下事实:同一浏览器和客户端上的不同选项卡具有不同的会话对象。 将一个选项卡中的channel会话变量设置为“ general ,将另一个选项卡设置为“ random

持续会议 (Persistent Sessions)

If you'd like to persist the session after the page has been refreshed, or if the browser has been closed, I'd recommend using the u2622:persistent-session package.

如果您想在刷新页面后保持会话状态,或者如果浏览器已经关闭,建议您使用u2622:persistent-session软件包。

Just install it and whenever you want to set a persistent Session variable, use Session.setPersistent(key, value) instead of Session.set(key, value). You can use the normal Session.get(key) to retrieve the value.

只需安装它,就可以在需要设置持久性Session变量时使用Session.setPersistent(key, value)而不是Session.set(key, value) 。 您可以使用普通的Session.get(key)检索值。

This can be great of user experience. If your website has an age gate feature, where users under the legal age cannot access, you'd want the age-verification page to appear only on the first visit. If it shows up every time someone visits, the bounce rate will be terrible.

这可能是很棒的用户体验。 如果您的网站具有年龄限制功能,而未达到法定年龄的用户无法使用该功能,则希望年龄验证页面仅在首次访问时出现。 如果每次有人拜访时都显示出来,跳出率将很糟糕。

In this case, you should utilize persistent session to store a variable that says "This visitor has verified their age before", so your application knows not to display the age-verification page again.

在这种情况下,您应该利用持久性会话来存储一个变量,该变量显示“此访问者之前已经验证了他们的年龄”,因此您的应用程序知道不再显示年龄验证页面。

更新我们的信息 (Updating Our Messages)

获取消息 (Getting the Messages)

Previously, we published all our messages, but now we have channels, we should publish, and subscribe to, only messages in the current channel. To do this, we must pass a parameter into the Meteor.publish method and also provide the argument in the subscription call.

以前,我们发布了所有消息,但是现在我们有了频道,我们应该只发布和订阅当前频道中的消息。 为此,我们必须将参数传递给Meteor.publish方法,并在订阅调用中提供参数。

Instead of

代替

Meteor.publish('messages', function () {
    return Messages.find();
}

We now have

现在我们有

Meteor.publish('messages', function (channel) {
    return Messages.find({channel: channel});
});

And in our subscription call, we pass the current channel session variable as the argument.

在订阅调用中,我们将当前的channel会话变量作为参数传递。

Template.messages.onCreated(function() {
  var self = this;
  self.autorun(function() {
    self.subscribe('messages', Session.get('channel'));
  });
});
模板级订阅 (Template-level Subscription)

You may have noticed that this template.subscribe() method didn't occur in the global scope but rather inside a Template.messages.onCreated() method.

您可能已经注意到,此template.subscribe()方法不是在全局范围内发生,而是在Template.messages.onCreated()方法内发生。

The onCreated() method of a template gets ran after the template created, but before the template logic gets evaluated. So the collection we are subscribing to here will be available inside the template.

模板的onCreated()方法在创建模板之后但在评估模板逻辑之前运行。 因此,我们在此处订阅的集合将在模板内提供。

But the significance is that the subscription occurred on the template-level. This is neat because the subscription is associated with our template. When our template gets destroyed (e.g. removed from the page), the subscription goes with it.

但是重要的是, 订阅发生在模板级别 。 这很整洁,因为订阅与我们的模板相关联。 当我们的模板被销毁(例如,从页面中删除)时,订阅随之进行。

Template-level subscription is a relatively new thing, introduced at the beginning of 2015.

模板级订阅是一个相对较新的事物, 于2015年初推出

We can even display a loading message while our subscription is getting ready.

我们的订阅准备就绪时,我们甚至可以显示加载消息。

{{#if Template.subscriptionsReady}}
    {{#each messages}}
        {{> message text=text timestamp=timestamp user=user }}
    {{/each}}
{{else}}
    Loading…
{{/if}}
autorun (autorun)

You'll notice that I wrapped the subscribe call inside a self.autorun() function. This uses the Tracker.

您会注意到,我将订阅调用包装在self.autorun()函数中。 这将使用跟踪器。

Basically, whenever any variables inside the autorun function changes, the whole autorun function is reran. This means when we switch channels, the messages template will re-subscribe using the new channel session variable, and we only get the messages from the new, current channel.

基本上,每当autorun功能内部的任何变量发生更改时,整个autorun功能都会重新运行。 这意味着当我们切换频道时, messages模板将使用新的channel会话变量重新订阅,并且我们仅从新的当前频道中获取消息。

插入新消息 (Inserting New Messages)

Each new message must be associated with a channel, so let's add a new property to our Messages collection.

每个新消息都必须与一个通道关联,因此让我们向Messages集合添加一个新属性。

Meteor.call('newMessage', {
    text: $('.input-box_text').val(),
    channel: Session.get('channel')
});

channels-new-messages

路由器 (Router)

The most popular router package out there is Iron Router. Let's add the package.

最受欢迎的路由器包是Iron Router 。 让我们添加包。

$ meteor add iron:router

For most cases, this is how you'd use Iron Router:

在大多数情况下,这是使用Iron Router的方式:

  1. Designate a template as a layout

    将模板指定为布局
  2. Define your routes, which will catch the request URL and insert the appropriate template into the layout

    定义您的路线,该路线将捕获请求URL并将适当的模板插入布局中

指定布局 (Designating a Layout)

We have our room.html, which contains the <head> and <body> tags; that would be our layout. So let's wrap that inside a template named app, and configure our router to use app as the layout. We'd also need to separate our head with our body. We can omit the <body> tag because Meteor will automatically add that in for us once it has concatenated everything together.

我们有room.html ,其中包含<head><body>标记; 那将是我们的布局。 因此,让我们将其包装在名为app的模板中,并配置路由器以将app用作布局。 我们还需要将头部与身体分开。 我们可以省略<body>标记,因为一旦Meteor将所有内容串联在一起,它将自动为我们添加该标记。

client/room.html

client/room.html

<template name="app">
    {{> header}}
    <div class="main">
        {{> loginButtons}}
        {{> listings}}
        {{> yield}}
    </div>
    {{> footer}}
</template>

client/head.html

client/head.html

<head>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <title></title>
     <link href='http://fonts.googleapis.com/css?family=Lato:400,700,900' rel='stylesheet' type='text/css'>
 </head>

client/routes.js

client/routes.js

Router.configure({
  layoutTemplate: 'app'
});

Notice the {{> yield}} inside our app layout. This is where Iron Router will insert the template into.

请注意我们app布局中的{{> yield}} 。 这是Iron Router将模板插入其中的位置。

定义路线 (Define Routes)

Slack uses the URL structure teamname.slack.com/messages/channel-name. But let's keep things simple so our URL will just be example.com/general or example.com/random.

Slack使用URL结构teamname.slack.com/messages/channel-name 。 但是让我们保持简单,以便我们的URL只是example.com/generalexample.com/random

Because our subscription has already been taken care of in the template level, all we need to worry about in the router-level are simply rendering the correct template - the messages template.

因为我们的订阅已经在模板级别进行了处理,所以我们在路由器级别需要担心的只是简单地渲染正确的模板- messages模板。

Router.route('/:channel', function () {
    this.render('messages');
});

Here the :channel is a variable. So if our request URL is example.com/helloworld, the :channel variable will have the value helloworld. As you'll see later, we can access this variable using this.params.channel.

这里:channel是一个变量。 因此,如果我们的请求URL为example.com/helloworld ,则:channel变量将具有值helloworld 。 稍后您将看到,我们可以使用this.params.channel访问此变量。

But now, if we go to example.com, we'd see an error.

但是现在,如果转到example.com ,将会看到一个错误。

home-not-found

That's because there are no routes for just /. So let's create a redirect from / to general.

那是因为没有路线只是 / 。 因此,让我们创建从/general的重定向。

Router.route('/', function () {
    this.redirect('/general');
});

And now if we go to example.com, it will automatically redirect to example.com/general.

现在,如果我们转到example.com ,它将自动重定向到example.com/general

切换频道 (Switching Channels)

Now if we switch channels, the URL doesn't get updated. Let's change that. All we have to do is to provide the link with an href attribute, just like any other link.

现在,如果我们切换频道,URL将不会更新。 让我们改变一下。 我们要做的就是为链接提供href属性,就像其他任何链接一样。

From

<a class="channel_name">

To

<a class="channel_name" href="/{{name}}">

We should also update the CSS styles.

我们还应该更新CSS样式。

.channel_name {
  text-decoration: none;
  color: inherit;
}

通过URL设置会话 (Setting the Session from URL)

Previously, we set our channel session variable on startup.

以前,我们在启动时设置channel会话变量。

Meteor.startup(function() {
  Session.set('channel', 'general');
});

That means if we open a new tab and type in http://localhost:3000/random, we'd still be on the general channel.

这意味着,如果我们打开一个新标签页并输入http://localhost:3000/random ,我们仍将位于general频道上。

Now, we should also override this default by setting the channel session variable to the channel defined in the URL. If you remember, we can get the channel name using this.params.channel.

现在,我们还应该通过将channel会话变量设置为URL中定义的通道来覆盖此默认值。 如果您还记得的话,我们可以使用this.params.channel获得频道名称。

Router.route('/:channel', function () {
    Session.set('channel', this.params.channel);
    this.render('messages');
});

This allows allows me to get rid of other Session-setting code, as it's all being handled at the router-level now. We can now get rid of:

这使我可以摆脱其他会话设置代码,因为它们现在都在路由器级别进行了处理。 我们现在可以摆脱:

client/input.js

client/input.js

Template.channel.events({
    'click .channel': function (e) {
    Session.set('channel', this.name);
}

client/startup/subscribe.js

client/startup/subscribe.js

Meteor.startup(function() {
    Session.set('channel', 'general');
});

走得更远 (Going Further)

So in this article, while practising our publish/subscribe skills by creating channels, we also explored using Iron Router, sessions and template-level subscription.

因此,在本文中,在通过创建渠道练习发布/订阅技能的同时,我们还探索了使用Iron Router,会话和模板级订阅的方法。

But Iron Router isn't the only router for Meteor out there. Recently, a new kid on the block - Flow Router by Arunoda Susiripala. Check out the discussion at forums.meteor.com and join the discussion!

但是Iron Router并不是唯一的Meteor路由器。 最近, Arunoda Susiripala的块流路由器上出现了一个新孩子。 在forums.meteor.com上查看讨论并加入讨论!

翻译自: https://scotch.io/tutorials/building-a-slack-clone-in-meteor-js-part-4-channels-and-chat-rooms

meteor构建app程序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值