欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于socket.io开发的聊天室demo

程序员文章站 2022-07-10 21:22:19
...

WebSocket比较不好的地方就是纯原生实现聊天室

// WebSocket的缺点,没有一个广播的事件或者说方法
// 需要我们自己去封装一个,封装一个广播事件的方法broadcast函数,并且broadcast函数内部职能发送字符串类型
// 如果你发送别的对象数组等等服务端就会报错,所以我们还需要用到JSON.stringify去转换一下发给前端,并且前端还需要哦转
// WebSocket的事件非常的少,用来用去就那几个事件方法

// 所以我们更多的是用一个框架去开发聊天室类的网站
// 我们使用socket.io这个框架去开发

// 我们基于socket.io开发一个完整的聊天室

我们基于socket.io做出来的demo聊天室

登录页面的demo样例图片基于socket.io开发的聊天室demo

聊天的页面

基于socket.io开发的聊天室demo

为了更加的简单便捷的去开发一个websocket项目我们使用到了socket.io去开发

基于socket.io开发的聊天室demo
我们基于socket.io开发的demo文件夹层级关系
server.js

var express = require("express")
var app = express()
var server = require("http").Server(app)
var io = require("socket.io")(server)
// 记录已经登录过的用户
var users = []
app.use(express.static("./public"))
server.listen(8083, () => {
    console.log("服务器8083开启成功~!")
})

app.get("/", function (req, res) {
    res.redirect("/index.html")
})

io.on("connection", function (socket) {
    // 用户连接的功能
    socket.on("login", function (data) {
        //    判断,如果data在user中存在,说明该用户已经登录了不允许登录
        // 如果data在users中不存在,说明该用户没有登录,允许用户登录
        var user = users.find(item => item.username === data.username)
        if (user) {
            // 表示用户存在,登录失败!服务器需要给当前用户响应,告诉登录失败
            socket.emit("loginError", {
                msg: "登陆失败"
            })
            console.log("登录失败!")
        } else {
            // 表示用户不存在,登录成功!
            users.push(data)
            socket.emit("loginSuccess", data)
            console.log("登录成功!")
            // socket.io广播消息如下
            // socket.emit是告诉单个人的事件
            // io.emit是广播给所有用户的事件
            // 告诉所有的用户.目前聊天室谁进入聊天室
            io.emit("addUser", data)
            // 告诉所有的用户.目前聊天室中有多少人
            io.emit("userList", users)
            // 把登录成功的用户名和头像存储起来
            socket.username = data.username
            socket.avatar = data.avatar
        }
    })

    // 用户断开连接的功能
    // 监听用户断开连接
    // 每个用户都有连接,如果浏览器断联就会自动触发disconnect事件
    // 前端不需要写emit disconnect事件
    socket.on("disconnect", function (data) {
        // 把当前用户的信息从users中删除
        var idx = users.findIndex(item => item.username === socket.username)
        // 删除掉断开连接的人
        users.splice(idx, 1)
        // 1.告诉所有人,有人离开了聊天室
        io.emit("delUser",{
            username:socket.username,
            avatar:socket.avatar
        })
        // 2.告诉所有人,userList发生更新
        io.emit("userList",users)
    })

    // 监听聊天的消息
    socket.on("sendMessage",data=>{
        console.log(data)
        // 广播给所有的用户
        io.emit("receiveMessage",data)
    })


    //接收图片信息
    socket.on("sendImage",data=>{
        console.log(data)
        // 广播给所有的用户
        io.emit("receiveImage",data)
    })
})

index.js

/* global io */
/* global $ */
/* 聊天室的主要功能 */

// 1.连接socketio服务
var socket = io('http://localhost:8083')
var username, avatar
var toName = '群聊'

// 2.登录功能
$('#login_avatar li').on('click', function () {
  $(this).addClass('now').siblings().removeClass('now')
})
// 点击按钮,登录
$('#loginBtn').on('click', function () {
  // 获取用户名
  var username = $('#username').val().trim()
  if (!username) {
    window.alert('请输入用户名')
    return
  }
  if (username === '群聊') {
    window.alert('用户名已存在')
    return
  }
  // 获取选择的头像
  var avatar = $('#login_avatar li.now img').attr('src')
  console.log(username, avatar)
  // 需要告诉socket io服务,登录
  // 前端携带username和avatar去触发后端的login事件
  socket.emit('login', {
    username,
    avatar
  })
})
// 监听登录失败的请求
socket.on('loginError', data => {
  window.alert('用户名已存在')
})

// 监听登录成功的请求
socket.on('loginSuccess', data => {
  console.log('登录成功')
  // 登录成功
  // 隐藏登录窗口
  // $('.login_box').fadeOut()
  $('.login_box').hide()
  // 显示聊天窗口
  $('.container').fadeIn()
  // 设置个人信息
  $('.user-list .header img').attr('src', data.avatar)
  $('.user-list .header .username').text(data.username)

  username = data.username
  avatar = data.avatar
})

// 监听添加用户的消息
socket.on('addUser', data => {
  // 添加一条系统消息
  $('.box-bd').append(`
    <div class="system">
      <p class="message_system">
        <span class="content">${data.username} 加入群聊</span>
      </p>
    </div>
  `)
  scrollIntoView()
})

// 监听用户离开的消息
socket.on('delUser', data => {
  // 添加一条系统消息
  $('.box-bd').append(`
    <div class="system leave">
      <p class="message_system">
        <span class="content">${data.username} 离开了群聊</span>
      </p>
    </div>
  `)
  scrollIntoView()
})

// 监听用户列表的消息
socket.on('userList', data => {
  // 把userlist
  $('.user-list ul').html('')
  $('.user-list ul').append(`
    <li class="user">
      <div class="avatar"><img src="images/群聊.jpg" alt=""></div>
      <div class="name">群聊</div>
    </li>
  `)
  data.forEach(item => {
    $('.user-list ul').append(`
      <li class="user">
        <div class="avatar"><img src="${item.avatar}" alt=""></div>
        <div class="name">${item.username}</div>
      </li>
    `)
  })
  $('#userCount').text(data.length)
  clickUser()
})

// 聊天功能
$('#btn-send').on('click', () => {
  var content = $('#content').html().trim()
  $('#content').html('')
  if (!content) {
    return window.alert('请输入内容')
  }
  // 发送消息给服务器
  socket.emit('sendMessage', {
    msg: content,
    username,
    avatar
  })
})

// 监听接收聊天消息
socket.on('receiveMessage', data => {
  console.log('收掉消息', data)
  if (data.toName === '群聊') {
    if (username === data.username) {
      // 自己的消息
      $('.box-bd').append(`
        <div class="message-box">
          <div class="my message">
            <img src="${data.avatar}" alt="" class="avatar">
            <div class="content">
              <div class="bubble">
                <div class="bubble_cont">${data.msg}</div>
              </div>
            </div>
          </div>
        </div>
      `)
    } else {
      // 别人的消息
      $('.box-bd').append(`
        <div class="message-box">
          <div class="other message">
            <img src="${data.avatar}" alt="" class="avatar">
            <div class="nickname">${data.username}</div>
            <div class="content">
              <div class="bubble">
                <div class="bubble_cont">${data.msg}</div>
              </div>
            </div>
          </div>
        </div>
      `)
    }
  } else {
    if (username === data.username) {
      // 自己的消息
      $('.box-bd').append(`
        <div class="message-box">
          <div class="my message">
            <img src="${data.avatar}" alt="" class="avatar">
            <div class="content">
              <div class="bubble">
                <div class="bubble_cont">${data.msg}</div>
                <div class="bubble_toName">私聊</div>
              </div>
            </div>
          </div>
        </div>
      `)
    } else {
      // 别人的消息
      $('.box-bd').append(`
        <div class="message-box">
          <div class="other message">
            <img src="${data.avatar}" alt="" class="avatar">
            <div class="nickname">${data.username}</div>
            <div class="content">
              <div class="bubble">
                <div class="bubble_cont">${data.msg}</div>
                <div class="bubble_toName">私聊</div>
              </div>
            </div>
          </div>
        </div>
      `)
    }
  }
  scrollIntoView()
})

// 当有消息时,将滑动到底部
function scrollIntoView () {
  // 当前元素的底部滚动到可视区
  $('.box-bd').children(':last').get(0).scrollIntoView(false)
}

// 发送图片功能
$('#file').on('change', function () {
  var file = this.files[0]
  // // 需要把这个图片发送到服务器,借助于H5新增的fileReader
  var fr = new window.FileReader()
  fr.readAsDataURL(file)
  fr.onload = function () {
    socket.emit('sendImage', {
      username,
      avatar,
      img: fr.result,
      toName
    })
  }
})

// 监听接收图片消息
socket.on('receiveImage', data => {
  if (username === data.username) {
    // 自己的消息
    $('.box-bd').append(`
      <div class="message-box">
        <div class="my message">
          <img src="${data.avatar}" alt="" class="avatar">
          <div class="content">
            <div class="bubble">
              <div class="bubble_cont">
                <img src="${data.img}">
              </div>
            </div>
          </div>
        </div>
      </div>
    `)
  } else {
    // 别人的消息
    $('.box-bd').append(`
      <div class="message-box">
        <div class="other message">
          <img src="${data.avatar}" alt="" class="avatar">
          <div class="nickname">${data.username}</div>
          <div class="content">
            <div class="bubble">
              <div class="bubble_cont">
                <img src="${data.img}">
              </div>
            </div>
          </div>
        </div>
      </div>
    `)
  }
  // 等待图片加载完成
  $('.box-bd img:last').on('load', function () {
    scrollIntoView()
  })
})

// 初始化jquery-emoji插件
$('.face').on('click', function () {
  // 点击.face的时候再去初始化
  $('#content').emoji({
    // 设置触发表情包的表情按钮
    button: '.face',
    // 表示只有一组标签的时候显不显示tab
    showTab: true,
    animation: 'slide',
    position: 'topRight',
    icons: [{
      name: 'QQ表情',
      path: 'lib/jquery-emoji/img/qq/',
      maxNum: 91,
      excludeNums: [41, 45, 54],
      file: '.gif'
    }]
  })
})

// // 扩展:私聊功能
// $('#btn-send').on('click', () => {
//   var content = $('#content').html().trim()
//   console.log(content)
//   if (!content) {
//     return window.alert('请输入内容')
//   }
//   if (toName === '群聊') {
//   // 发送消息给服务器
//     socket.emit('sendMessage', {
//       msg: content,
//       username,
//       avatar,
//       toName
//     })
//   } else {
//     // 发送私聊消息给服务器
//     socket.emit('sendMessageToOne', {
//       msg: content,
//       username,
//       avatar,
//       toName: toName
//     })
//   }
//   $('#content').html('')
// })

// 点击用户事件绑定
function clickUser () {
  $('.user').on('click', function () {
    $(this).addClass('active').siblings().removeClass('active')
    var to = $(this).children('.name').text()
    $('#chatName').text(to)
    toName = to
  })
}