ホームページ > 記事 > ウェブフロントエンド > WeChat UIのチャット機能を実装する
今回はWeChat UIのチャット機能を実装するための注意事項をご紹介します。実際の事例を見てみましょう。
WeChat ミニ プログラムは最近非常に人気があり、WeChat を開くとすぐに、WeChat で使用するほぼすべてのアプリにそのコピーが表示されます。正式版には Tiaotiao が付属しており、前例のない高い位置にあります。公式アカウントと比較すると、次のような違いがあると個人的には思います:
公式アカウントは少し面倒です: コンテンツを見るために最初に注意を払う必要がありますが、ミニプログラムはそうではありません(私はコンテンツを持っていません) WeChat公式アカウントについては深く理解しているので、そうではないと思います)ご容赦ください)
ミニプログラムのパフォーマンスが向上しています。ミニプログラムが何を実装するために使用されているのか正確にはわかりませんが、経験という点では確かに元のエクスペリエンスに近いですが、WeChat 公式アカウントはコンテンツを表示するために Web ページの形式を使用しています。互換性とパフォーマンスの問題については説明する必要はありません。すべてのルアーはすでに認識しています
ミニ プログラムは開発が簡単です。ミニ プログラムは、新しいコード ルールのセットをリリースし、一連のコンポーネントも提供します。Bai Jia が主張するパブリック アカウントと比較して、フォームは確かにはるかに統一されています
ナンセンスなことをたくさん言いましたが、私は最近ミニ プログラムの実装を検討し始めましたが、実際に非常に楽しいです。個人的な開発の概要を以下に示します。
簡単な小さなデモがあります。 WeChat ミニ プログラムの公式 Web サイトのアドレスは次のとおりです: https://mp.weixin.qq.com/debug/wxadoc/dev/index.html、その手順に従ってください。同じ例を実行できます。公式のものなので、ここではプロセスを投稿しません。主に私の全体的な個人的な感想について話します:
js はオリジナルの js のまま、css はオリジナルの css のままです。html に関しては、いくつかの点が変更されています。たとえば、p が view になり、text が text になり、 img 画像になりましたが、スープは変わりません。同じように使用でき、意味がより明確になります。
設定ファイル.json
を追加しました。グローバルapp.json
があります。これは、ナビゲーションバー、TAB設定、グローバルルーティング設定などのグローバル設定です。などですが、各ページでグローバル カバレッジを実行することもできます。たとえば、list.json
でリスト ページの内容を個別に規定します。 .json
,全局有一个app.json
,是全局的配置,比如导航栏、TAB的配置,全局路由的配置等等,而在每个页面中,依然是可以进行全局覆盖的,比如list.json
中单独规定了列表页面长啥样子。
每个页面都具有生命周期(包括启动页),类似于react/vue
的声明周期,更加明确在哪个阶段可以做哪些事情
代码组件化,很多封装的组件都可以简单引用,比如map
,而在微信公众号上开发的时候,你可能还需要专门写一个地图插件
API更加好用,虽然我没多少开发过公众号,但是就之前配置的jssdk来说,就感觉比小程序复杂,小程序只需要一个appId就可以了,然后在代码中直接使用wx
对象来调用各种API
只是感兴趣稍微做了一下案例,其中功能可能根本就还只是九牛一毛,但是觉得有必要记录一下,说说自己遇到的问题以及解决办法,界面整体如下:
首先,在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
の宣言サイクルでは、どの段階で何ができるかがより明確になります🎜🎜🎜🎜 コードはコンポーネント化されており、map などの多くのカプセル化されたコンポーネントは単純に参照できます
、そして WeChat 公式アカウントで開発する場合は、マップ プラグインも作成する必要があるかもしれません 🎜🎜🎜🎜 API の方が使いやすいですが、jssdk に関する限り、私はあまり公式アカウントを開発したことがありません。ミニ プログラムは複雑であるため、コード内で wx
オブジェクトを直接使用してさまざまな API を呼び出すだけで済みます。 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 }); },
最开始的样子就是这样子的:
至此,基本的页面形态就已经完成了。
遇到的一些问题:
每次进入页面的时候,即使聊天内容已经超过了聊天区域,都会显示为最开始的地方
输入新的聊天记录的时候,如果聊天内容不是处于最底部,那么新加的内容会看不到
针对这两个问题,我按照自己最初的想法是:进入页面获取scrollHieght
然后计算scrollTop
值,将其滚动就好了,至于第二个问题按照类似的方法就可以解决了,但是我查看小程序的API之后,并没有发现如何计算scrollHeight
的方法。只有类似的API,如:boundingClientRect
和scrollTop
好在天无绝人之路,看到了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还有一个问题,就是当点击输入框的时候,整体页面会向上顶起来,这个问题我在论坛中也有看到,但是没有找到解决办法,如果各位有遇到,还望不吝赐教。
如果是一个真正的聊天程序应该怎么做呢?我的设想是这样的:
由于当时自己的机器由于莫名的原因不能够进行登录,后来采用了本地开了一个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中文网其它相关文章!
推荐阅读:
以上がWeChat UIのチャット機能を実装するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。