ホームページ  >  記事  >  ウェブフロントエンド  >  Node+Express のパーソナライズされたチャット ルームを実装するにはどうすればよいですか?

Node+Express のパーソナライズされたチャット ルームを実装するにはどうすればよいですか?

亚连
亚连オリジナル
2018-06-07 16:12:171421ブラウズ

この記事では主にnode+expressのパーソナライズされたチャットルームを基礎ゼロで実装した例を紹介し、参考として提供します。

この記事では、node+express+jquery を使用してパーソナライズされたチャット ルームを作成します。一緒に作成しましょう~ (記事の最後にあるソース コードのアドレスを参照してください)

レンダリング

プロジェクト構造

機能の実装

  1. ログイン検出

  2. システムは自動的にユーザーステータス(入力/退出)を要求します

  3. オンラインユーザーを表示

  4. メッセージの送受信をサポート

  5. カスタムフォントcolor

  6. 絵文字の送信をサポート

  7. 写真の送信をサポート

以下では実装方法を一つずつ説明していきます

準備

nodeとnpm環境、express、socket.io

具体的な実装

1. チャット ルームをサーバーにデプロイします

まず、ノードを使用してサーバーを構築し、localhost:3000 ポートに「hello world」を送信してみます。新しいserver.jsファイルを作成します。


var app = require('express')(); // 引入express模块
var http = require('http').Server(app);

app.get('/', function(req, res){ // 路由为localhost:3000时向客户端响应“hello world”
 res.send(&#39;<h1>Hello world</h1>&#39;); // 发送数据
});

http.listen(3000, function(){ // 监听3000端口
 console.log(&#39;listening on *:3000&#39;); 
});

ブラウザを開いて、このようにURL: localhost:3000を入力してください

ノードサーバーが正常に構築されます。


次に、expressを使用してHTMLページをブラウザに返します


#安装express模块
npm install --save express

server.jsのコードを変更します:


var express = require(&#39;express&#39;);
var app = express();
var http = require(&#39;http&#39;).Server(app); 

// 路由为/默认www静态文件夹
app.use(&#39;/&#39;, express.static(__dirname + &#39;/www&#39;));

express.static(__dirname + '/www') ; www フォルダーを静的リソースとしてホストすることは、このフォルダー内のファイル (html、css、js) が相互に相対パスを使用できることを意味します。以下に示すように、index.html ファイルと対応する CSS を www フォルダーに追加します (対応する CSS コードは投稿されません。詳細についてはソース コードを参照してください)。このページでは、素晴らしいフォントの小さなアイコン


<!doctype html>
<html>
 <head>  
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <title>chat</title>
 <link rel="stylesheet" href="style/index.css" rel="external nofollow" >
 <link rel="stylesheet" href="style/font-awesome-4.7.0/css/font-awesome.min.css" rel="external nofollow" >
 </head>
 <body>
 <p class="all">
  <p class="name">
  <!-- <h2>请输入你的昵称</h2> -->
  <input type="text" id="name" placeholder="请输入昵称..." autocomplete="off"> 
  <button id="nameBtn">确 定</button>
  </p>
  <p class="main">
  <p class="header">
   <img src="image/logo.jpg">
   happy聊天室
  </p>
  <p id="container">
   <p class="conversation">
    <ul id="messages"></ul>
    <form action="">
     <p class="edit"> 
     <input type="color" id="color" value="#000000">
     <i title="双击取消选择" class="fa fa-smile-o" id="smile">
     </i><i title="双击取消选择" class="fa fa-picture-o" id="img"></i>
     <p class="selectBox"> 
      <p class="smile"> 
      </p>
      <p class="img"> 
      </p>
     </p>
     </p>
     <!-- autocomplete禁用自动完成功能 -->
     <textarea id="m"></textarea>
     <button class="btn rBtn" id="sub">发送</button>
     <button class="btn" id="clear">关闭</button>
    </form>
   </p>
   <p class="contacts">
   <h1>在线人员(<span id="num">0</span>)</h1>
   <ul id="users"></ul>
   <p>当前无人在线哟~</p>
   </p>
  </p>
  </p> 
 </p> 
 </body>
</html>
が使用されています。

localhost: 3000 を開くと、次の内容が表示されます:

チャット ルームがサーバーに正常にデプロイされました。


2. ログインを検出

クライアントとサーバーの間でメッセージを送信するにはSocket.ioが必要です


#安装socket.io模块
npm install --save socket.io

server.jsを次のように変更します:


var app = require(&#39;express&#39;)();
var http = require(&#39;http&#39;).Server(app);
var io = require(&#39;socket.io&#39;)(http);

app.use(&#39;/&#39;, express.static(__dirname + &#39;/www&#39;));

io.on(&#39;connection&#39;, function(socket){ // 用户连接时触发
 console.log(&#39;a user connected&#39;);
});

http.listen(3000, function(){
 console.log(&#39;listening on *:3000&#39;);
});

いつlocalhost:3000 が開かれると、サーバー側 IO の接続イベントがトリガーされ、サーバーに「ユーザーが接続されました」と表示されますが、サーバーに接続しているユーザーの数をカウントしたいと考えます。接続しているユーザー数の場合、「n ユーザーが接続しています」と表示されます。n はユーザーの数です。どうすればよいですか?


server.js でグローバル配列を user として設定します。ユーザーが接続に成功するたびに、接続イベントの user.length にユーザーのニックネームをプッシュして、接続に成功したユーザーの数を確認します。


ちょっと待ってください。


ユーザーが接続するときにログインするためのニックネームを入力します。同じニックネームが使用されることを避けるために、サーバーはログイン イベントを監視します。したがって、次のようになります。トリガーとなるイベントは、接続イベントのコールバック関数に記述する必要があります。


io.on(&#39;connection&#39;, (socket)=> {
 // 渲染在线人员
 io.emit(&#39;disUser&#39;, usersInfo);

 // 登录,检测用户名
 socket.on(&#39;login&#39;, (user)=> {
  if(users.indexOf(user.name) > -1) { // 昵称是否存在
   socket.emit(&#39;loginError&#39;); // 触发客户端的登录失败事件
  } else {
   users.push(user.name); //储存用户的昵称
   usersInfo.push(user); // 储存用户的昵称和头像
   socket.emit(&#39;loginSuc&#39;); // 触发客户端的登录成功事件
   socket.nickname = user.name;
   io.emit(&#39;system&#39;, { // 向所有用户广播该用户进入房间
    name: user.name,
    status: &#39;进入&#39;
   });
   io.emit(&#39;disUser&#39;, usersInfo); // 渲染右侧在线人员信息
   console.log(users.length + &#39; user connect.&#39;); // 打印连接人数
  }
 });

ここでは system イベントと disUser イベントを無視して、io.emit(foo)、socket.emit(foo)、socket.broadcast.emit(foo) の区別について説明します


io.emit(foo); //会触发所有客户端用户的foo事件
socket.emit(foo); //只触发当前客户端用户的foo事件
socket.broadcast.emit(foo); //触发除了当前客户端用户的其他用户的foo事件

次は、クライアントコード chat-c​​lient.js


$(function() {
  // io-client
  // 连接成功会触发服务器端的connection事件
  var socket = io();

  // 点击输入昵称
  $(&#39;#nameBtn&#39;).click(()=> { 
   var imgN = Math.floor(Math.random()*4)+1; // 随机分配头像
   if($(&#39;#name&#39;).val().trim()!==&#39;&#39;)
     socket.emit(&#39;login&#39;, { // 触发服务器端登录事件
      name: $(&#39;#name&#39;).val(),
      img: &#39;image/user&#39; + imgN + &#39;.jpg&#39;
     }); 
   return false; 
  });
  // 登录成功,隐藏登录层
  socket.on(&#39;loginSuc&#39;, ()=> { 
   $(&#39;.name&#39;).hide(); 
  })
  socket.on(&#39;loginError&#39;, ()=> {
   alert(&#39;用户名已存在,请重新输入!&#39;);
   $(&#39;#name&#39;).val(&#39;&#39;);
  }); 
});

ログインに成功すると、次のページが表示されます:

ログイン検出が完了しました。


3. システムはユーザーのステータス (入室/退出) を自動的に表示します

この機能は、ログインが成功すると、上の図に示すように、システム プロンプトを実現します。システムイベントがトリガーされ、すべてのユーザーに情報が報告されます。このとき、クライアントコードは次のとおりです


4. オンラインで表示します。ユーザー

クライアントは、オンライン ユーザーを表示するイベント disUser を監視し、サーバー側はイベントをトリガーし、次の 3 つの期間に 1 回再レンダリングします

プログラムの開始時

  1. ルームに入る

  2. ユーザーがルームを出るたび

  3. // 系统提示消息
    socket.on(&#39;system&#39;, (user)=> { 
     var data = new Date().toTimeString().substr(0, 8);
     $(&#39;#messages&#39;).append(`<p class=&#39;system&#39;><span>${data}</span><br /><span>${user.name} ${user.status}了聊天室<span></p>`);
     // 滚动条总是在最底部
     $(&#39;#messages&#39;).scrollTop($(&#39;#messages&#39;)[0].scrollHeight);
    });

5. メッセージの送受信をサポートします

用户发送消息时触发服务器端的sendMsg事件,并将消息内容作为参数,服务器端监听到sendMsg事件之后向其他所有用户广播该消息,用的socket.broadcast.emit(foo)

 // server.js
  // 发送消息事件
  socket.on(&#39;sendMsg&#39;, (data)=> {
    var img = &#39;&#39;;
    for(var i = 0; i < usersInfo.length; i++) {
      if(usersInfo[i].name == socket.nickname) {
        img = usersInfo[i].img;
      }
    }
    socket.broadcast.emit(&#39;receiveMsg&#39;, { // 向除了发送者之外的其他用户广播
      name: socket.nickname,
      img: img,
      msg: data.msg,
      color: data.color,
      side: &#39;left&#39;
    });
    socket.emit(&#39;receiveMsg&#39;, { // 向发送者发送消息,为什么分开发送?因为css样式不同
      name: socket.nickname,
      img: img,
      msg: data.msg,
      color: data.color,
      side: &#39;right&#39;
    });
  });

服务器端接受到来自用户的消息后会触发客户端的receiveMsg事件,并将用户发送的消息作为参数传递,该事件会向聊天面板添加聊天内容,以下为chat-client.js代码

// 点击按钮或回车键发送消息
  $(&#39;#sub&#39;).click(sendMsg);
  $(&#39;#m&#39;).keyup((ev)=> {
   if(ev.which == 13) {
    sendMsg();
   }
  });

  // 接收消息
  socket.on(&#39;receiveMsg&#39;, (obj)=> { // 将接收到的消息渲染到面板上
   $(&#39;#messages&#39;).append(` 
     <li class=&#39;${obj.side}&#39;>
     <img src="${obj.img}">
     <p>
      <span>${obj.name}</span>
      <p>${obj.msg}</p>
     </p>
    </li>
   `);
   // 滚动条总是在最底部
   $(&#39;#messages&#39;).scrollTop($(&#39;#messages&#39;)[0].scrollHeight);
  });


  // 发送消息
  function sendMsg() { 
   if($(&#39;#m&#39;).val() == &#39;&#39;) { // 输入消息为空
    alert(&#39;请输入内容!&#39;);
    return false;
   }
   socket.emit(&#39;sendMsg&#39;, {
    msg: $(&#39;#m&#39;).val()
   });
   $(&#39;#m&#39;).val(&#39;&#39;); 
   return false; 
  }

6、自定义字体颜色

得益于html5的input新特性,可以通过type为color的input调用系统调色板

<!-- $(&#39;#color&#39;).val();为选中颜色,格式为#FFCCBB -->
<input type=&#39;color&#39; id=&#39;color&#39;>

客户端根据用户选择的颜色渲染内容样式,代码很容易看懂,这里就不赘述了。

7、支持发送表情

发送表情其实很简单,将表情图片放在li中,当用户点击li时就将表情的src中的序号解析出来,用[emoji+表情序号]的格式存放在聊天框里,点击发送后再解析为src。就是一个解析加还原的过程,这一过程中我们的服务器代码不变,需要改变的是客户端监听的receiveMsg事件。

// chat-client.js

  // 显示表情选择面板
  $(&#39;#smile&#39;).click(()=> {
   $(&#39;.selectBox&#39;).css(&#39;display&#39;, "block");
  });
  $(&#39;#smile&#39;).dblclick((ev)=> { 
   $(&#39;.selectBox&#39;).css(&#39;display&#39;, "none");
  }); 
  $(&#39;#m&#39;).click(()=> {
   $(&#39;.selectBox&#39;).css(&#39;display&#39;, "none");
  });

  // 用户点击发送表情
  $(&#39;.emoji li img&#39;).click((ev)=> {
    ev = ev || window.event;
    var src = ev.target.src;
    var emoji = src.replace(/\D*/g, &#39;&#39;).substr(6, 8); // 提取序号
    var old = $(&#39;#m&#39;).val(); // 用户输入的其他内容
    $(&#39;#m&#39;).val(old+&#39;[emoji&#39;+emoji+&#39;]&#39;);
    $(&#39;.selectBox&#39;).css(&#39;display&#39;, "none");
  });

客户端收到之后将表情序号还原为src,更改如下

// chat-client.js

  // 接收消息
  socket.on(&#39;receiveMsg&#39;, (obj)=> { 
   // 提取文字中的表情加以渲染
   var msg = obj.msg;
   var content = &#39;&#39;;
   while(msg.indexOf(&#39;[&#39;) > -1) { // 其实更建议用正则将[]中的内容提取出来
    var start = msg.indexOf(&#39;[&#39;);
    var end = msg.indexOf(&#39;]&#39;);

    content += &#39;<span>&#39;+msg.substr(0, start)+&#39;</span>&#39;;
    content += &#39;<img src="image/emoji/emoji%20(&#39;+msg.substr(start+6, end-start-6)+&#39;).png">&#39;;
    msg = msg.substr(end+1, msg.length);
   }
   content += &#39;<span>&#39;+msg+&#39;</span>&#39;;
   
   $(&#39;#messages&#39;).append(`
    <li class=&#39;${obj.side}&#39;>
     <img src="${obj.img}">
     <p>
      <span>${obj.name}</span>
      <p style="color: ${obj.color};">${content}</p>
     </p>
    </li>
   `);
   // 滚动条总是在最底部
   $(&#39;#messages&#39;).scrollTop($(&#39;#messages&#39;)[0].scrollHeight);
  });

可以成功发送表情了。

8、支持发送图片

首先是图片按钮样式,发送图片的按钮是type为file的input。这里有一个改变样式的小技巧,那就是将input的透明度设为0,z-index为5,将你想要得样式放在p中,z-index设为1覆盖在input上。

<input type="file" id="file">
<i class="fa fa-picture-o" id="img"></i>
css:

.edit #file {
  width: 32.36px;
  height: 29px;
  opacity: 0;
  z-index: 5;
}
.edit #img {
  z-index: 0;
  margin-left: -43px;
}

完美

接下来是点击按钮发送图片,我们用了fileReader对象,这里有一篇不错的文章讲解了fileReader,fileReader是一个对象,可以将我们选中的文件已64位输出然后将结果存放在reader.result中,我们选中图片之后,reader.result就存放的是图片的src

// chat-client.js

  // 用户发送图片
  $(&#39;#file&#39;).change(function() {
   var file = this.files[0]; // 上传单张图片
   var reader = new FileReader();

   //文件读取出错的时候触发
   reader.onerror = function(){
     console.log(&#39;读取文件失败,请重试!&#39;); 
   };
   // 读取成功后
   reader.onload = function() {
    var src = reader.result; // 读取结果
    var img = &#39;<img class="sendImg" src="&#39;+src+&#39;">&#39;;
    socket.emit(&#39;sendMsg&#39;, { // 发送
     msg: img,
     color: color,
     type: &#39;img&#39; // 发送类型为img
    }); 
   };
   reader.readAsDataURL(file); // 读取为64位
  });

由于发送的是图片,所以对页面布局难免有影响,为了页面美观客户端在接收其他用户发送的消息的时候会先判断发送的是文本还是图片,根据不同的结果展示不同布局。判断的方法是在客户发送消息的时候传入一个type,根据type的值来确实发送内容的类型。所以上面发送图片代码中触发了sendMsg事件,传入参数多了一个type属性。

响应的,我们应该在chat-client.js中修改receiveMsg事件监听函数,改为根据传入type做不同操作

chat-client.js
  // 接收消息
  socket.on(&#39;receiveMsg&#39;, (obj)=> { 
   // 发送为图片
   if(obj.type == &#39;img&#39;) {
    $(&#39;#messages&#39;).append(`
     <li class=&#39;${obj.side}&#39;>
      <img src="${obj.img}">
      <p>
       <span>${obj.name}</span>
       <p style="padding: 0;">${obj.msg}</p>
      </p>
     </li>
    `); 
    $(&#39;#messages&#39;).scrollTop($(&#39;#messages&#39;)[0].scrollHeight);
    return;
   }

   // 提取文字中的表情加以渲染
   // 下面不变
  });

现在我们可以发送图片了

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue中如何使用cli请求代理与项目打包方面的问题

在vue-cli中使用webpack模板解决项目搭建及打包路径问题

在vue中bus全局事件中心(详细教程)

以上がNode+Express のパーソナライズされたチャット ルームを実装するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。