Node+WebSocket+Vue聊天室: 界面美化,代码优化 – 第六章

100 篇文章 5 订阅

前言

Node+WebSocket+Vue聊天室: 界面美化,代码优化 - 第六章

感谢你再次点开了我,只能说明你是喜欢我的,对不对?哈哈,开个玩笑。

今天主要是把之前的聊天室界面美化一下,不至于太难看,同时也对代码做了一些优化。具体细节请看详细内容。

并且可以线上体验了:体验地址

如果您还没有看过之前的文字,请点击下方链接查看!
推荐文章:

《Nodejs + WebSocket简单介绍及示例 - 第一章》
《Nodejs + WebSocket + Vue 实现多人聊天室WebIM功能 - 第二章》
《Nodejs + WebSocket + Vue 一对一、一对多聊天室 - 第三章》
《Node + WebSocket + Vue 一对一、一对多聊天室消息已读未读 - 第四章》
《Node + WebSocket + Vue 聊天室创建群聊/加入群聊功能 - 第五章》

客户端HTML代码优化

Node+WebSocket+Vue聊天室: 界面美化,代码优化 - 第六章

页面先分为左右布局,然后左/右里面再分为上中下布局。

很自然,我们想到了flex布局,Flex是Flexible Box的缩写,意为”弹性布局”,用来为盒状模型提供最大的灵活性。

...
<div class="web-im">
  <div class="left">
    <div class="aside content">
      <div class="header">
       ...
      </div>
      <div class="body user-list">
        ...
      </div>
      <div class="footer">
        ...
      </div>
    </div>
  </div>
  <div class="right content">
    <div class="header">...</div>
    <div class="body im-record" id="im-record">
      ...
    </div>
    <div class="footer im-input">
      ...
    </div>
  </div>
</div>
...

HTML

Copy

css样式是用stylus书写的,有些初学的小伙伴应该有点点不是很明白,但是大致能懂,就是把嵌套的书写,使其看起来更容易阅读、维护。

如果对flex、和stylus不是很明白的小伙伴,可以留言区留言,后期看情况出更详细的教程,这里就不啰嗦了。

.web-im
  display flex
.left
  width 220px
.right
    flex 1
.content
  display: flex;
  flex-direction: row;
  flex: 1;
  box-sizing: border-box;
  min-width: 0;
  flex-direction: column;
  .header
    box-shadow 1px -1px 2px 2px #eee
    line-height 40px
    height 40px
    font-size 24px
    z-index 10
    background #fff
  .body
    flex 1
    overflow-y auto
    box-shadow 1px 1px 1px #eee
  .footer
    box-shadow 1px 1px 8px #eee
    height 60px

Stylus

Copy

WebSocket客户端JS

我们主要研究变的地方,没有变的通过...表示。同时,如果您想看完整代码,可以去文章最下方“了解更多”,来获取源码查看。

...
export default {
  ...
  mounted() {
    ...
    // 监听页面刷新,关闭事件,退出聊天室
    window.onbeforeunload = function (e) {
      vm.socket.send(JSON.stringify({
        uid: vm.uid,
        type: 2,
        nickname: vm.nickname,
        bridge: []
      }));
    }
  },
  computed: {
    // 当前展示的消息列表
    currentMessage() {
      let vm = this;
      let data = vm.messageList.filter(item=>{
        if(item.type === 1) {
          return item;
        } else if(this.groupId) {
          return item.groupId === this.groupId
        } else if(item.bridge.length){
          return item.bridge.sort().join(',') == vm.bridge.sort().join(',')
        }
      })
      data.map(item=>{
        item.status = 0
        return item;
      })
      return data;
    },
    // 当前群组列表
    currentGroups() {
      let vm = this;
      vm.groups.map(group=>{
        // 找出群组对应未读消息
        group.unread = this.messageList.filter(item=>{
          return item.groupId === group.id && item.status === 1
        }).length
        return group;
      })
      return vm.groups;
    },
    // 群组列表是否有未读消息
    groupsUnRead(){
      return this.messageList.some(item=>{
        return item.groupId && item.status === 1
      })
    },
    // 联系人列表是否有未读消息
    usersUnRead(){
      return this.messageList.some(item=>{
        return item.bridge.length && item.status === 1
      })
    },
    // 当前联系人列表
    currentUserList() {
      let vm = this;
      vm.users.map(user=>{
        // 找出联系人对应未读消息
        user.unread = this.messageList.filter(item=>{
          return item.bridge.length && item.uid === user.uid && item.status === 1
        }).length
        return user;
      })
      return vm.users;
    }
  },
  methods: {
    ...
    conWebSocket(){
      let vm = this;
      if(window.WebSocket){
        ...
        socket.onmessage = function(e){
          ...
          // 消息列表滚动条始终在最底部
          vm.$nextTick(function(){
            var div = document.getElementById('im-record');
            div.scrollTop = div.scrollHeight;
          })
        }   
      }
    }
    ...
  }
}

JavaScript

Copy

这次代码优化,主要是在计算属性上面做了大的调整。之前都是用方法来获取未读已读等,现在直接计算属性先一步计算,然后渲染到页面。

WebSocket服务端

...
// 注销
case 2:
  delete conns[''+obj.uid+''];
  users.map((item, index)=>{
    if(item.uid === obj.uid){
      item.status = 0;
    }
    return item;
  })
  boardcast({
    type: 1,
    date: moment().format('YYYY-MM-DD HH:mm:ss'),
    msg: obj.nickname+'退出了聊天室',
    users: users,
    groups: groups,
    uid: obj.uid,
    nickname: obj.nickname,
    bridge: []
  });
  break;
...

JavaScript

Copy

服务端主要增加了一个注销功能,用户下线。
同时,之前type=2是发送消息,现在改成了100是发送消息,2是用户下线。

快速预览效果

Node+WebSocket+Vue聊天室: 界面美化,代码优化 - 第六章

Node+WebSocket+Vue聊天室: 界面美化,代码优化 - 第六章

源码地址:源码地址
体验地址:体验地址

转自http://www.javanx.cn/20190509/websocket_im5/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个简单的使用Spring Boot、Vue.js和WebSocket实现的聊天室的代码示例: Spring Boot后端代码: ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new WebSocketHandler(), "/chat").setAllowedOrigins("*"); } @Bean public ObjectMapper objectMapper() { return new ObjectMapper(); } } class WebSocketHandler extends TextWebSocketHandler { private static final Map<WebSocketSession, String> users = new ConcurrentHashMap<>(); @Override public void afterConnectionEstablished(WebSocketSession session) { users.put(session, "Anonymous"); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { ChatMessage chatMessage = new ObjectMapper().readValue(message.getPayload(), ChatMessage.class); if (chatMessage.getType() == ChatMessage.MessageType.JOIN) { users.put(session, chatMessage.getSender()); } for (WebSocketSession user : users.keySet()) { user.sendMessage(new TextMessage(new ObjectMapper().writeValueAsString(chatMessage))); } } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) { users.remove(session); } } @Data @AllArgsConstructor @NoArgsConstructor class ChatMessage { public enum MessageType { CHAT, JOIN, LEAVE } private String sender; private String content; private MessageType type; public static ChatMessage joinMessage(String sender) { return new ChatMessage(sender, "", MessageType.JOIN); } public static ChatMessage leaveMessage(String sender) { return new ChatMessage(sender, "", MessageType.LEAVE); } } @RestController public class ChatController { @GetMapping("/users") public List<String> users() { return new ArrayList<>(WebSocketHandler.users.values()); } } ``` Vue.js前端代码: ```html <template> <div> <h2>Chat Room</h2> <div> <label>Your name:</label> <input v-model="name" @keyup.enter="join" /> <button @click="join">Join</button> </div> <div v-if="joined"> <div> <label>Message:</label> <input v-model="message" @keyup.enter="send" /> <button @click="send">Send</button> </div> <div> <h3>Users:</h3> <ul> <li v-for="user in users" :key="user">{{ user }}</li> </ul> </div> <div> <h3>Chat:</h3> <ul> <li v-for="chat in chats" :key="chat.id"> <strong>{{ chat.sender }}:</strong> {{ chat.content }} </li> </ul> </div> </div> </div> </template> <script> import SockJS from "sockjs-client"; import Stomp from "stompjs"; export default { data() { return { name: "", message: "", joined: false, chats: [], users: [], stompClient: null, }; }, methods: { join() { const socket = new SockJS("/chat"); this.stompClient = Stomp.over(socket); this.stompClient.connect({}, () => { this.stompClient.subscribe("/topic/chat", (message) => { const chat = JSON.parse(message.body); if (chat.type === "JOIN") { this.users.push(chat.sender); } else if (chat.type === "LEAVE") { this.users.splice(this.users.indexOf(chat.sender), 1); } this.chats.push(chat); }); this.stompClient.send( "/app/chat", JSON.stringify(ChatMessage.joinMessage(this.name)) ); this.joined = true; }); }, send() { this.stompClient.send( "/app/chat", JSON.stringify( new ChatMessage(this.name, this.message, ChatMessage.MessageType.CHAT) ) ); this.message = ""; }, }, }; class ChatMessage { static MessageType = { CHAT: "CHAT", JOIN: "JOIN", LEAVE: "LEAVE", }; constructor(sender, content, type) { this.sender = sender; this.content = content; this.type = type; } static joinMessage(sender) { return new ChatMessage(sender, "", ChatMessage.MessageType.JOIN); } static leaveMessage(sender) { return new ChatMessage(sender, "", ChatMessage.MessageType.LEAVE); } } </script> ``` 在这个示例中,我们使用了Spring Boot的WebSocket支持来处理来自客户端的事件。我们创建了一个WebSocket处理程序,它维护了一个用户会话列表,并在用户加入、离开或发送聊天消息时广播消息到所有连接的客户端。我们还为WebSocket处理程序创建了一个控制器,以便在客户端请求所有当前连接的用户列表时返回它们。 在Vue.js应用程序中,我们使用SockJS和Stomp.js来建立与服务器的WebSocket连接,并处理来自服务器的事件。我们使用Vue.js的数据绑定来更新聊天消息、用户列表和用户输入框中的数据,并在加入聊天室、发送聊天消息或断开连接时发送相关的WebSocket事件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值