微信小程序最近很火,火到什么程度,只要你一打開微信,就是它的身影,幾乎你用的各個(gè)APP都可以在微信中找到它的復(fù)制版,另外官方自帶的跳一跳更是將它推到了空前至高的位置。對(duì)比公眾號(hào),就我的感覺來說,有以下區(qū)別:
廢話說了這么多,我也是最近才開始看小程序的實(shí)現(xiàn)方式,體驗(yàn)了一把,確實(shí)比較爽,以下就是個(gè)人開發(fā)總結(jié): 簡易的官網(wǎng)小程序 微信小程序官網(wǎng)中有個(gè)簡單的小demo,地址在這里:https://mp.weixin.qq.com/debug/wxadoc/dev/index.html,按照它的步驟來,一定是可以運(yùn)行一個(gè)和官方一樣的例子出來的,這里就不貼過程了。主要說一下個(gè)人整體感受:
開發(fā)一個(gè)類似微信UI的簡單聊天程序 只是感興趣稍微做了一下案例,其中功能可能根本就還只是九牛一毛,但是覺得有必要記錄一下,說說自己遇到的問題以及解決辦法,界面整體如下: ![]()
首先,在app.json中編寫頁面路由,如下: { "pages":[ "pages/index/index", "pages/list/list", "pages/chat/chat" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#000", "navigationBarTitleText": "WeChat", "navigationBarTextStyle":"#fff" } } 這里有3個(gè)頁面,首頁放一個(gè)按鈕作為入口,列表頁表示聊天記錄,還有一個(gè)聊天頁。 列表頁沒有什么可以講的,設(shè)置列表頁的標(biāo)題可以在list.json中設(shè)置即可,如下: // list.json { "navigationBarTitleText": "聊天列表" } 列表頁模擬了一些數(shù)據(jù),然后再點(diǎn)擊每一條的時(shí)候,進(jìn)入單個(gè)聊天頁面當(dāng)中,其中需要將當(dāng)前點(diǎn)擊的一些信息傳入下一個(gè)頁面當(dāng)中,這里僅僅只有名字。 //chat.js //獲取應(yīng)用實(shí)例 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 }) } })
然后進(jìn)入聊天頁面,首先進(jìn)入聊天頁面我想到的是,每一個(gè)氣泡加上它的頭像是否可以做成一個(gè)組件,因?yàn)橹挥凶笥业膮^(qū)分而已,另外如果再加上時(shí)間的話,再將時(shí)間傳遞過去就可以了。 因此chat.wxml最開始就是這樣規(guī)劃的: <block wx:for="{{ messages }}" wx:key="messages{{ index }}" > <template id="{{ item.id }}" is="bubble" data="{{ ...item }}" /> </block> template中的代碼就不展示了,最開始我寫模板的時(shí)候,是開了一個(gè)codePen,然后模擬寫出來之后,再往模板中套,保證基本的樣子差不多,然后再在模板上進(jìn)行細(xì)微的改動(dòng)就可以了。 聊天頁頂部的標(biāo)題是通過列表頁中傳過來的,在頁面加載完成的時(shí)候,設(shè)置就好了: // chat.js // 設(shè)置昵稱 setNickName(option) { const nickname = option.nickname || 'Marry'; wx.setNavigationBarTitle({ title: nickname }); },
最開始的樣子就是這樣子的:
至此,基本的頁面形態(tài)就已經(jīng)完成了。 遇到的一些問題:
每次進(jìn)入頁面的時(shí)候,即使聊天內(nèi)容已經(jīng)超過了聊天區(qū)域,都會(huì)顯示為最開始的地方 好在天無絕人之路,看到了scroll-view中的scroll-into-view屬性,于是就想出了解決上面兩個(gè)問題的方法:
進(jìn)入頁面,獲取歷史紀(jì)錄,獲取最后一條消息的ID值,記為lastId,在渲染的時(shí)候,消息列表中的每個(gè)ID值傳入組件,作為每個(gè)消息記錄的唯一標(biāo)識(shí),然后使用scroll-in-view={{ id }}就可以輕松地使最后一條消息進(jìn)入視野當(dāng)中 // chat.wxml <scroll-view scroll-y scroll-with-animation class="chat-content" scroll-top="{{ scrollTop }}" scroll-into-view="{{ lastId }}"> <block wx:for="{{ messages }}" wx:key="messages{{ index }}" > <template id="msg{{ index }}" is="bubble" data="{{ ...item }}" /> </block> </scroll-view> // chat.js Page({ data: { messages: [], // 聊天記錄 msg: '', // 當(dāng)前輸入 lastId: '' // 最后一條消息的ID // ... }, // ... send() { // ... const data = { id: `msg${++nums}`, message: msg, messageType: 0, url: '../../images/5.png' }; this.setData({ msg: '', lastId: data.id }); } }); 這樣就可以大致實(shí)現(xiàn)類似于聊天的效果了,但是還有一個(gè)小問題,每次從列表中進(jìn)入單個(gè)聊天頁面的時(shí)候,會(huì)有一個(gè)斜向左上方滑動(dòng)的過程,原因是:頁面的轉(zhuǎn)場動(dòng)畫是向左的,但是自動(dòng)滾動(dòng)到最后一條記錄的動(dòng)作是向上的,所以會(huì)有動(dòng)作疊加,既然這樣,我只需要讓滾動(dòng)的過程延遲一段時(shí)間就好. // 延遲頁面向頂部滑動(dòng) delayPageScroll() { const messages = this.data.messages; const length = messages.length; const lastId = messages[length - 1].id; setTimeout(() => { this.setData({ lastId }); }, 300); },
至此問題就算是解決了,在真機(jī)模擬的時(shí)候,IOS還有一個(gè)問題,就是當(dāng)點(diǎn)擊輸入框的時(shí)候,整體頁面會(huì)向上頂起來,這個(gè)問題我在論壇中也有看到,但是沒有找到解決辦法,如果各位有遇到,還望不吝賜教。
擴(kuò)展延伸
由于當(dāng)時(shí)自己的機(jī)器由于莫名的原因不能夠進(jìn)行登錄,后來采用了本地開了一個(gè)websocket的服務(wù)器來實(shí)現(xiàn)消息的發(fā)送。服務(wù)器代碼相當(dāng)簡單,只是消息的轉(zhuǎn)發(fā)而已
// server.js const 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中需模擬歷史消息的發(fā)送以及新加消息的發(fā)送,因此代碼整體看起來是這樣的: //chat.js //獲取應(yīng)用實(shí)例 const app = getApp() const msgs = require('./chat-mock-data.js'); Page({ data: { messages: [], // 聊天記錄 msg: '', // 當(dāng)前輸入 scrollTop: 0, // 頁面的滾動(dòng)值 socketOpen: false, // websocket是否打開 lastId: '', // 最后一條消息的ID isFirstSend: true // 是否第一次發(fā)送消息(區(qū)分歷史和新加) }, onLoad(option) { // 設(shè)置標(biāo)題 this.setNickName(option); }, //事件處理函數(shù) onReady() { // 連接websocket服務(wù)器 this.connect(); }, onUnload() { const socketOpen = this.data.socketOpen; if (socketOpen) { wx.closeSocket({}); wx.onSocketClose(res => { console.log('WebSocket 已關(guān)閉!') }); } }, connect() { wx.connectSocket({ url: 'ws://localhost:12112' }); wx.onSocketOpen(res => { this.setData({ socketOpen: true }); // 模擬歷史消息的發(fā)送 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 }); // 延遲頁面向頂部滑動(dòng) 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連接打開失敗,請(qǐng)檢查!') }) }, // 設(shè)置昵稱 setNickName(option) { const nickname = option.nickname || 'Marry'; wx.setNavigationBarTitle({ title: nickname }); }, // 延遲頁面向頂部滑動(dòng) 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 }); }, // 發(fā)送消息 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) }) } } })
整體來說,自己的思路就像是上面的代碼所描述的,這個(gè)只是初步的構(gòu)想,還有很多東西需要完善:
頭像 我只是一只小菜鳥,但我并沒有停下學(xué)習(xí)的腳步^_^ 另外,覺得這篇文章不錯(cuò),可以隨手點(diǎn)個(gè)贊么?求星星 |