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