>  기사  >  웹 프론트엔드  >  WeChat UI의 채팅 기능 구현

WeChat UI의 채팅 기능 구현

php中世界最好的语言
php中世界最好的语言원래의
2018-03-19 16:38:563055검색

이번에는 WeChat UI의 채팅 기능을 구현하기 위한 주의사항을 알려드리겠습니다. 실제 사례를 살펴보겠습니다.

WeChat 미니 프로그램은 최근 인기가 많을 만큼 WeChat을 열자마자 해당 프로그램을 WeChat에서 사용하는 거의 모든 앱에서 찾을 수 있습니다. 공식 버전은 Tiaotiao와 함께 제공되어 전례 없는 높은 위치에 올랐습니다. 공식 계정과 비교했을 때 제가 생각하는 차이점은 다음과 같습니다.

  • 공식 계정은 좀 번거롭습니다. 콘텐츠를 보려면 먼저 주의를 기울여야 하지만, 미니 프로그램은 그렇지 않습니다. 위챗 공식 계정에 대한 깊은 이해가 있어서 그렇지는 않을 것 같습니다) 양해 부탁드립니다

  • 미니 프로그램의 성능이 더 좋습니다. 미니 프로그램이 정확히 무엇을 구현하는지는 모르겠지만, 실제로 경험 측면에서는 원래 경험에 더 가깝습니다. 하지만 WeChat 공식 계정은 웹페이지 형식을 사용하여 콘텐츠를 표시합니다. 호환성 및 성능 문제를 설명할 필요가 없습니다. 모든 루어가 이미 알고 있습니다

  • 미니 프로그램은 개발하기가 더 쉽습니다. 미니 프로그램은 새로운 코드 규칙 세트를 출시했으며 일련의 구성 요소도 제공합니다. Bai Jia의 공개 계정과 비교하면 형식이 실제로 훨씬 더 통일되어 있습니다. , 최근에야 미니 프로그램 구현을 살펴보기 시작했는데 정말 즐거웠습니다. 개인 개발 요약은 다음과 같습니다.

  • 간단한 공식 웹 사이트 미니 프로그램 프로그램

간단한 작은 프로그램이 있습니다. WeChat 미니 프로그램 공식 웹사이트의 데모 주소는 다음과 같습니다:

https://

mp.weixin.qq.com/debug/wxadoc/dev/index.html, 해당 단계를 따르십시오. 예는 공식적인 것이므로 여기에 프로세스를 게시하지 않겠습니다. 주로 내 전반적인 개인적인 느낌에 대해 이야기해 보세요.

js는 여전히 원본 js이고, css는 여전히 원본 CSS입니다. html 측면에서 몇 가지 사항이 변경되었습니다. 예를 들어 p는 보기가 되고, 텍스트는 텍스트가 되고, img 이미지가 되었지만 수프는 변경되지 않았습니다. 여전히 동일한 방식으로 사용할 수 있으며 의미가 더 명확합니다.

开发一个类似微信UI的简单聊天程序

只是感兴趣稍微做了一下案例,其中功能可能根本就还只是九牛一毛,但是觉得有必要记录一下,说说自己遇到的问题以及解决办法,界面整体如下:

WeChat UI의 채팅 기능 구현

首先,在app.json中编写页面路由,如下:

{
  "pages":[        
    "pages/index/index",
    "pages/list/list",
    "pages/chat/chat"
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#000",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle":"#fff"
  }}

这里有3个页面,首页放一个按钮作为入口,列表页表示聊天记录,还有一个聊天页。

列表页没有什么可以讲的,设置列表页的标题可以在list.json中设置即可,如下:

// list.json{
  "navigationBarTitleText": "聊天列表"}

列表页模拟了一些数据,然后再点击每一条的时候,进入单个聊天页面当中,其中需要将当前点击的一些信息传入下一个页面当中,这里仅仅只有名字。

//chat.js//获取应用实例const app = getApp()const friends = require('./list-mock-data.js')Page({
  data: {
    friends: friends.list
  },
  gotoChat(event) {
    const currentUser = event.currentTarget.dataset.user;
    wx.navigateTo({
      url: '../chat/chat?nickname=' + currentUser.nickname
    })  }})

然后进入聊天页面,首先进入聊天页面我想到的是,每一个气泡加上它的头像是否可以做成一个组件,因为只有左右的区分而已,另外如果再加上时间的话,再将时间传递过去就可以了。

因此chat.wxml(시작 페이지 포함)이 있습니다. react/vue의 선언 주기에서는 어느 단계에서 무엇을 할 수 있는지가 더 명확해집니다

🎜🎜🎜코드는 컴포넌트화되어 있으며 와 같이 캡슐화된 많은 컴포넌트를 간단히 참조할 수 있습니다. 지도, 그리고 WeChat 공식 계정에서 개발할 때 전용 지도 플러그인을 작성해야 할 수도 있습니다🎜🎜🎜🎜API가 더 사용자 친화적입니다. 공식 계정을 많이 개발하지는 않았지만, 이전에 구성한 jssdk가 걱정되는 점은 미니 프로그램이 복잡한 것보다 낫다는 것입니다. 미니 프로그램은 appId만 필요하고 코드에서 wx 개체를 직접 사용하여 다양한 API를 호출할 수 있습니다🎜🎜🎜🎜 WeChat UI와 유사한 간단한 채팅 프로그램을 개발해보세요🎜🎜그저 관심이 있어서 약간의 사례 연구를 했습니다. 기능은 그저 한 방울일 수도 있지만, 그것을 기록하고 내가 겪은 문제에 대해 이야기하는 것이 필요하다고 느꼈습니다. 전체 인터페이스는 다음과 같습니다. 🎜🎜WeChat UI의 채팅 기능 구현 🎜🎜먼저 app.json에 다음과 같이 페이지 경로를 작성합니다. 🎜
<block>
  <template></template></block>
🎜여기에는 3개의 페이지가 있습니다. 홈페이지에 입구 버튼이 있고, 목록 페이지는 채팅 기록을 나타냅니다. , 채팅 페이지가 있습니다. 🎜🎜목록 페이지에 대해서는 말할 것도 없습니다. 목록 페이지 제목 설정은 다음과 같이 list.json에서 설정할 수 있습니다. 🎜
// chat.js// 设置昵称setNickName(option) {
    const nickname = option.nickname || 'Marry';
    wx.setNavigationBarTitle({
      title: nickname    });
  },
🎜목록 페이지는 일부 데이터를 시뮬레이션한 후 클릭합니다. 각 항목에 단일 채팅 페이지에 들어갈 때 현재 클릭한 정보 중 일부를 다음 페이지로 전송해야 합니다. 여기에는 이름만 있습니다. 🎜
// chat.wxml<scroll-view>
    <block>
      <template></template>    </block>
  </scroll-view>// chat.jsPage({  data: {    messages: [],         // 聊天记录    msg: '',              // 当前输入    lastId: ''            // 最后一条消息的ID    // ...  },  // ...  send() {    // ...    const data = {      id: `msg${++nums}`,      message: msg,      messageType: 0,      url: '../../images/5.png'
    };
    this.setData({ msg: '', lastId: data.id });
  }
});
🎜그런 다음 채팅 페이지에 들어갑니다. 먼저, 채팅 페이지에 들어갈 때 생각하는 것은 각 버블과 그 아바타를 구성 요소로 만들 수 있는지 여부입니다. 게다가 시간의 차이만 있기 때문입니다. 추가되면 시간이 지나면 그냥 지나치세요. 🎜🎜그래서 chat.wxml은 원래 다음과 같이 계획되었습니다: 🎜
<block>
  <template></template></block>

template中的代码就不展示了,最开始我写模板的时候,是开了一个codePen,然后模拟写出来之后,再往模板中套,保证基本的样子差不多,然后再在模板上进行细微的改动就可以了。

聊天页顶部的标题是通过列表页中传过来的,在页面加载完成的时候,设置就好了:

// chat.js// 设置昵称setNickName(option) {
    const nickname = option.nickname || 'Marry';
    wx.setNavigationBarTitle({
      title: nickname    });
  },

最开始的样子就是这样子的:

WeChat UI의 채팅 기능 구현

至此,基本的页面形态就已经完成了。

遇到的一些问题:

  • 每次进入页面的时候,即使聊天内容已经超过了聊天区域,都会显示为最开始的地方

  • 输入新的聊天记录的时候,如果聊天内容不是处于最底部,那么新加的内容会看不到

针对这两个问题,我按照自己最初的想法是:进入页面获取scrollHieght然后计算scrollTop值,将其滚动就好了,至于第二个问题按照类似的方法就可以解决了,但是我查看小程序的API之后,并没有发现如何计算scrollHeight的方法。只有类似的API,如:boundingClientRectscrollTop

好在天无绝人之路,看到了scroll-view中的scroll-into-view属性,于是就想出了解决上面两个问题的方法:

  • 进入页面,获取历史纪录,获取最后一条消息的ID值,记为lastId,在渲染的时候,消息列表中的每个ID值传入组件,作为每个消息记录的唯一标识,然后使用scroll-in-view={{ id }}就可以轻松地使最后一条消息进入视野当中

  • 在聊天的时候,新加的记录会更新这个lastId值,这样就自动更新视图了

// chat.wxml<scroll-view>
    <block>
      <template></template>    </block>
  </scroll-view>// chat.jsPage({  data: {    messages: [],         // 聊天记录    msg: '',              // 当前输入    lastId: ''            // 最后一条消息的ID    // ...  },  // ...  send() {    // ...    const data = {      id: `msg${++nums}`,      message: msg,      messageType: 0,      url: '../../images/5.png'
    };
    this.setData({ msg: '', lastId: data.id });
  }
});

这样就可以大致实现类似于聊天的效果了,但是还有一个小问题,每次从列表中进入单个聊天页面的时候,会有一个斜向左上方滑动的过程,原因是:页面的转场动画是向左的,但是自动滚动到最后一条记录的动作是向上的,所以会有动作叠加,既然这样,我只需要让滚动的过程延迟一段时间就好

// 延迟页面向顶部滑动
  delayPageScroll() {
    const messages = this.data.messages;
    const length = messages.length;
    const lastId = messages[length - 1].id;
    setTimeout(() => {
      this.setData({ lastId });
    }, 300);
  },

至此问题就算是解决了,在真机模拟的时候,IOS还有一个问题,就是当点击输入框的时候,整体页面会向上顶起来,这个问题我在论坛中也有看到,但是没有找到解决办法,如果各位有遇到,还望不吝赐教。

扩展延伸

如果是一个真正的聊天程序应该怎么做呢?我的设想是这样的:

WeChat UI의 채팅 기능 구현-one

由于当时自己的机器由于莫名的原因不能够进行登录,后来采用了本地开了一个websocket的服务器来实现消息的发送。服务器代码相当简单,只是消息的转发而已

// server.jsconst WebSocket = require('ws');const wss = new WebSocket.Server({ port: 12112 });wss.on('connection', ws => {
  console.log('connection established');
  ws.on('message', message => {
    console.log("on message coming");
    ws.send(message);
  });});

chat.js中需模拟历史消息的发送以及新加消息的发送,因此代码整体看起来是这样的:

//chat.js//获取应用实例const app = getApp()const msgs = require('./chat-mock-data.js');Page({
  data: {
    messages: [],         // 聊天记录
    msg: '',              // 当前输入
    scrollTop: 0,         // 页面的滚动值
    socketOpen: false,    // websocket是否打开
    lastId: '',           // 最后一条消息的ID
    isFirstSend: true     // 是否第一次发送消息(区分历史和新加)
  },
  onLoad(option) {
    // 设置标题
    this.setNickName(option);
  },
  //事件处理函数
  onReady() {
    // 连接websocket服务器
    this.connect();
  },
  onUnload() {
    const socketOpen = this.data.socketOpen;
    if (socketOpen) {
      wx.closeSocket({});
      wx.onSocketClose(res => {
        console.log('WebSocket 已关闭!')      });
    }
  },
  connect() {
    wx.connectSocket({
      url: 'ws://localhost:12112'
    });
    wx.onSocketOpen(res => {
      this.setData({ socketOpen: true });
      // 模拟历史消息的发送
      wx.sendSocketMessage({
        data: JSON.stringify(msgs),
      })    });
    wx.onSocketMessage(res => {
      const isFirstSend = this.data.isFirstSend;
      const data = JSON.parse(res.data);
      let messages = this.data.messages;
      let lastId = '';
      
      // 第一次为接收历史消息,
      // 之后的为新加的消息
      if (isFirstSend) {
        messages = messages.concat(data);
        lastId = messages[0].id;
        this.setData({ messages, lastId, isFirstSend: false });
        // 延迟页面向顶部滑动
        this.delayPageScroll();
      } else {
        messages.push(data);
        const length = messages.length;
        lastId = messages[length - 1].id;
        this.setData({ messages, lastId });
      }
    });
    wx.onSocketError(res => {
      console.log(res);
      console.log('WebSocket连接打开失败,请检查!')    })  },
  // 设置昵称
  setNickName(option) {
    const nickname = option.nickname || 'Marry';
    wx.setNavigationBarTitle({
      title: nickname    });
  },
  // 延迟页面向顶部滑动
  delayPageScroll() {
    const messages = this.data.messages;
    const length = messages.length;
    const lastId = messages[length - 1].id;
    setTimeout(() => {
      this.setData({ lastId });
    }, 300);
  },
  // 输入
  onInput(event) {
    const value = event.detail.value;
    this.setData({ msg: value });
  },
  // 聚焦
  onFocus() {
    this.setData({ scrollTop: 9999999 });
  },
  // 发送消息
  send() {
    const socketOpen = this.data.socketOpen;
    let messages = this.data.messages;
    let nums = messages.length;
    let msg = this.data.msg;
    if (msg === '') {
      return false;
    }
    const data = {
      id: `msg${++nums}`,
      message: msg,
      messageType: 0,
      url: '../../images/5.png'
    };
    this.setData({ msg: '' });
    
    if (socketOpen) {
      wx.sendSocketMessage({
        data: JSON.stringify(data)      })    }
  }})

整体来说,自己的思路就像是上面的代码所描述的,这个只是初步的构想,还有很多东西需要完善:

  • 头像

  • 列表页和聊天页新消息的处理

  • 数据库的历史消息存储

  • 图片以及语音的发送

  • 消息本地化存储

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

Vue指令的使用

JS闭包的使用

위 내용은 WeChat UI의 채팅 기능 구현의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.