微信小程式初探【類微信UI聊天簡單實現】

来源:https://www.cnblogs.com/rynxiao/archive/2018/03/16/8575999.html
-Advertisement-
Play Games

微信小程式最近很火,火到什麼程度,只要你一打開微信,就是它的身影,幾乎你用的各個APP都可以在微信中找到它的複製版,另外官方自帶的跳一跳更是將它推到了空前至高的位置。對比公眾號,就我的感覺來說,有以下區別: 公眾號略顯繁瑣:我首先要關註才能看到內容,而小程式不用(個人對微信公眾號研究不深,不對之處還 ...


微信小程式最近很火,火到什麼程度,只要你一打開微信,就是它的身影,幾乎你用的各個APP都可以在微信中找到它的複製版,另外官方自帶的跳一跳更是將它推到了空前至高的位置。對比公眾號,就我的感覺來說,有以下區別:

  • 公眾號略顯繁瑣:我首先要關註才能看到內容,而小程式不用(個人對微信公眾號研究不深,不對之處還望見諒)
  • 小程式性能要好一些:雖然我不是很清楚小程式用什麼實現,就體驗來說確實更接近原生一點;但是微信公眾號是用網頁的形式來展示內容的,其中的相容性和性能問題不用我說,各位luer就已經清楚了吧
  • 小程式更易開發:小程式發佈了一套新的代碼規則,也提供了一系列的組件,對比公眾號百家爭鳴的形式確實要統一得多

廢話說了這麼多,我也是最近才開始看小程式的實現方式,體驗了一把,確實比較爽,以下就是個人開發總結:

簡易的官網小程式

微信小程式官網中有個簡單的小demo,地址在這裡:https://mp.weixin.qq.com/debug/wxadoc/dev/index.html,按照它的步驟來,一定是可以運行一個和官方一樣的例子出來的,這裡就不貼過程了。主要說一下個人整體感受:

  • js還是原來的js,css還是原來的css,html方面來說,是改了一點東西,比如:div變成了view,文本變成了text,以及img變成了image,但是換湯不換藥,該怎麼用還是怎麼用,而且語義也更加明確。
  • 增加了配置文件.json,全局有一個app.json,是全局的配置,比如導航欄、TAB的配置,全局路由的配置等等,而在每個頁面中,依然是可以進行全局覆蓋的,比如list.json中單獨規定了列表頁面長啥樣子。
  • 每個頁面都具有生命周期(包括啟動頁),類似於react/vue的聲明周期,更加明確在哪個階段可以做哪些事情
  • 代碼組件化,很多封裝的組件都可以簡單引用,比如map,而在微信公眾號上開發的時候,你可能還需要專門寫一個地圖插件
  • API更加好用,雖然我沒多少開發過公眾號,但是就之前配置的jssdk來說,就感覺比小程式複雜,小程式只需要一個appId就可以了,然後在代碼中直接使用wx對象來調用各種API

開發一個類似微信UI的簡單聊天程式

只是感興趣稍微做了一下案例,其中功能可能根本就還只是九牛一毛,但是覺得有必要記錄一下,說說自己遇到的問題以及解決辦法,界面整體如下:

all

首先,在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最開始就是這樣規劃的:

<block wx:for="{{ messages }}" wx:key="messages{{ index }}" >
  <template id="{{ item.id }}" is="bubble" data="{{ ...item }}" />
</block>

template中的代碼就不展示了,最開始我寫模板的時候,是開了一個codePen,然後模擬寫出來之後,再往模板中套,保證基本的樣子差不多,然後再在模板上進行細微的改動就可以了。

聊天頁頂部的標題是通過列表頁中傳過來的,在頁面載入完成的時候,設置就好了:

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

最開始的樣子就是這樣子的:

first-chat

至此,基本的頁面形態就已經完成了。

遇到的一些問題:

  • 每次進入頁面的時候,即使聊天內容已經超過了聊天區域,都會顯示為最開始的地方
  • 輸入新的聊天記錄的時候,如果聊天內容不是處於最底部,那麼新加的內容會看不到

針對這兩個問題,我按照自己最初的想法是:進入頁面獲取scrollHieght然後計算scrollTop值,將其滾動就好了,至於第二個問題按照類似的方法就可以解決了,但是我查看小程式的API之後,並沒有發現如何計算scrollHeight的方法。只有類似的API,如:boundingClientRectscrollTop

好在天無絕人之路,看到了scroll-view中的scroll-into-view屬性,於是就想出瞭解決上面兩個問題的方法:

  • 進入頁面,獲取歷史紀錄,獲取最後一條消息的ID值,記為lastId,在渲染的時候,消息列表中的每個ID值傳入組件,作為每個消息記錄的唯一標識,然後使用scroll-in-view={{ id }}就可以輕鬆地使最後一條消息進入視野當中
  • 在聊天的時候,新加的記錄會更新這個lastId值,這樣就自動更新視圖了
// 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: '',              // 當前輸入
    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還有一個問題,就是當點擊輸入框的時候,整體頁面會向上頂起來,這個問題我在論壇中也有看到,但是沒有找到解決辦法,如果各位有遇到,還望不吝賜教。

擴展延伸

如果是一個真正的聊天程式應該怎麼做呢?我的設想是這樣的:

first-chat-one

由於當時自己的機器由於莫名的原因不能夠進行登錄,後來採用了本地開了一個websocket的伺服器來實現消息的發送。伺服器代碼相當簡單,只是消息的轉發而已

// 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中需模擬歷史消息的發送以及新加消息的發送,因此代碼整體看起來是這樣的:

//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)
      })
    }
  }
})

整體來說,自己的思路就像是上面的代碼所描述的,這個只是初步的構想,還有很多東西需要完善:

  • 頭像
  • 列表頁和聊天頁新消息的處理
  • 資料庫的歷史消息存儲
  • 圖片以及語音的發送
  • 消息本地化存儲

這些問題對於剛接觸的我來說,還需要一點時間來消化,暫且就貼這麼多吧。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡要:本系列文章講會對expo進行全面的介紹,本人從2017年6月份接觸expo以來,對expo的研究斷斷續續,一路走來將近10個月,廢話不多說,接下來你看到內容,講全部來與官網 我猜去全部機翻+個人修改補充+demo測試的形式,對expo進行一次大補血!歡迎加入expo興趣學習交流群:597732 ...
  • 最近在做項目的時候遇到了一個需求,那就是要對一張圖片做處理,實現邊緣模糊過渡。 苦思良久,最終用了以下的方法。 1、構成一張圖片的是ARGB,我們可以直接把這整張圖片的ARGB取出來,然後改變圖片的A,也就是透明度。 以上我們便獲得了圖片的ARGB值,而我們只需要改變透明度A。 2、我們可以用 最後 ...
  • 普通廣播: 1.在AndroidManifest.xml中配置廣播接收器: <receiver android:name="com.example.toast.MyBroadReceiver" > <intent-filter> <action android:name="MyBroad" /> < ...
  • 對於這個問題,今天折騰了一下午,不是說我不懂得怎麼調用,而是我用了看似正確的調用方式,而其實這是一個坑。 我用了下麵這種方式: 用這種方式是正確的,必須要將context轉換為Activity。 但是由於我是在一個特殊的場景裡面使用的,導致activity的onActivityResult沒有被回調 ...
  • 一、Audio Toolbox 1.使用代碼 import AudioServicesPlaySystemSound(1106); 2.如果想用自己的音頻文件創建系統聲音來播放的同學可以參考如下代碼。 //Get the filename of the sound file: NSString pa ...
  • 簡要:本系列文章講會對expo進行全面的介紹,本人從2017年6月份接觸expo以來,對expo的研究斷斷續續,一路走來將近10個月,廢話不多說,接下來你看到內容,講全部來與官網 我猜去全部機翻+個人修改補充+demo測試的形式,對expo進行一次大補血!歡迎加入expo興趣學習交流群:597732 ...
  • 最近項目上需要用到一個選擇器,選擇器中的內容只有年和月,而在iOS系統自帶的日期選擇器UIDatePicker中卻只有四個選項如下,分別是時間(時分秒)、日期(年月日)、日期+時間(年月日時分)以及倒計時。其中並沒有我們所需要的只顯示年月的選擇器,在網上找了很多相關的資料,但是覺得都寫得過於麻煩。因 ...
  • 我們知道Android加混淆之後,代碼的安全性得到了提高,即使你hook,反編譯得到的也是亂碼的,對於閱讀性造成了影響,為了增強代碼的破解難度,我們通常退對apk進行加固,常見的有騰訊,360,愛加密等。今天說說用360怎麼一鍵加固apk。 加固保為移動應用提供專業安全的保護,可防止應用被逆向分析、 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...