小程序雲開發之新聞類項目分析

應該每個前端開發者都有一顆全乾全棧的心💗吧。 那就讓雲開發知足你

雲開發一出來就開始玩,雲數據庫,雲函數,全棧的體驗和開發速度,真的不是通常的爽。 接下來工做中要開發一款新聞類小程序,因而就開始了對頭條君的調研,此篇文章,是個人我的總結和分析,歡迎大佬拍磚。
圖片描述javascript

一. 準備


:剛開始項目的時候我使用了vant組件庫,想快速的完成項目,寫着寫着就發現使用起來有點麻煩,樣式達不到本身想要的。因此我果斷拋棄了它,我固然不能認可本身菜,只好說這個組件坑,個人項目中也就沒使用組件庫。但用組件庫能極大的提高開發的速度,聽大佬說wux這個組件庫很好用,同行們能夠試試。感受「真香」的記得告訴我html

看看效果圖:(沒有展現全,下面有更多配圖以供學習這個項目)前端

二. 先聊聊雲開發


小程序雲開發是什麼???java

開發者可使用雲開發開發微信小程序、小遊戲,無需搭建服務器,便可使用雲端能力。android

雲開發爲開發者提供完整的雲端支持,弱化後端和運維概念,無需搭建服務器,使用平臺提供的 API
進行核心業務開發,便可實現快速上線和迭代,同時這一能力,同開發者已經使用的雲服務相互兼容 > ,並不互斥。git

目前提供三大基礎能力支持:github

  • 雲函數:在雲端運行的代碼,微信私有協議自然鑑權,開發者只需編寫自身業務邏輯代碼
  • 數據庫:一個既可在小程序前端操做,也能在雲函數中讀寫的 JSON 數據庫
  • 存儲:在小程序前端直接上傳/下載雲端文件,在雲開發控制檯可視化管理

這是官方文檔的描述數據庫

其實簡單的來講小程序雲開發是一款Serverless服務,開發者可使用它開發微信小程序、小遊戲,無需搭建服務器,便可使用雲端能力。目前提供雲函數、數據庫、存儲三大基礎能力支持。,而且將這些能力封裝成特定的接口,以wx.cloud.xxx來進行調用。json

三.數據庫創建


根據需求創建了三個集合

  1. 文章基本信息articles

  1. 文章詳情detail


3.文章評論信息comment

三個集合經過id字段「鏈接」,要是個新手這時會想那麼麻煩幹嗎,直接所有放一塊兒,梭哈一下,全給拿過來,直接用。這確定是不行的,想一想要是這個數據多怎麼辦,你要讓用戶等你多久? 做爲前端工程師確定是但願給用戶帶來極佳的使用體驗,因此你想在頁面上展現什麼,就設置一個對應的數據去關聯,要什麼取什麼。後臺數據無非就是一對一,一對多,你要啥數據就用傳相關字段進雲函數,在雲函數裏進行簡單的增刪改查。

千萬記住,要考慮你的集合數據的使用範圍進行權限設置,好比我添加的是articles文章,那這是公開的。那我就應該在權限設置中修改成全部用戶可讀、僅管理員可寫,默認的是僅建立者及管理員可讀寫。

如何建表,表和表之間的聯繫,在動手項目以前要考慮好,避免表裏的內容重複致使內存浪費,在能實行其功能的基礎上作到不浪費內存。我上面的表建的就有點問題,圖片URL的地址存錯了地方,並且在兩表裏都存儲了,你們作的時候能夠吸收個人教訓。

四. 項目分析


頭條功能那麼可能是不可能寫的完,咱們在這裏就選擇其首頁、新聞詳情、登陸界面這部分來實現一下。

首頁推薦:頭條裏面有不一樣的新聞樣式,有無圖的,一張圖的還有三張圖的,因此咱們確定要分離出不一樣的模板,根據後臺傳過來的數據去判斷新聞的樣式最後在頁面中顯示出來 數據驅動頁面

  • MVVM

    • M 是數據 模型

      • V view 頁面 視圖
      • VM 數據綁定到界面上 視圖模型 -> 模板{{}}

新聞詳情:打開新聞詳情頁,分析以後發現大致分爲三個部分 頭部的做者信息 新聞內容
底部的用戶評論 這些信息都是在雲開發數據庫中不一樣的集合裏面,這些數據的提取操做封裝在雲函數裏面以便調用 這三部分都是重複的結構抽離出來做爲組件,組件很是的靈活,這樣作的好處是頁面結構將會更加的清晰,增長代碼的複用性,而且耦合度下降,後續程序的維護也更爲方便。

登陸界面:直接使用wx.getUserInfo得到用戶信息 後面會貼出js代碼

五.功能實現不詳解


1. 目錄

2. 首頁

該頁面採用頂部的固定搜索欄、scroll-view和swiper內容區三個模塊,三個模塊都可採用絕對定位,搜索欄flex佈局,swiper內容區內swiper-item有關注,推薦,熱點,南昌和視頻

<scroll-view class="navBar-box" scroll-x="true" style="white-space: nowrap; display:flex ">
    <view class="cate-list {{curIndex==index?'on':''}}" wx:for="{{category}}" 
    wx:key="{{item.id}}" data-id="{{item.id}}" data-index="{{index}}" bindtap="switchCategory">
    {{item.name}}
    </view>
</scroll-view>

在jsdata裏面 設置curIndex, toView,用以監控不一樣版塊的狀態 實現了將上面的scroll-view
和下面的文章swiper創建關係

<swiper class="notes"  current="{{curIndex}}"  bindchange="swiperchange">
      <swiper-item class="focus">
            ...
        </swiper-item>
        <swiper-item class="category"  wx:key="{{item.id}}">
            <scroll-view class="cate-box"  scroll-y="true" bindscrolltolower="loadarticles">
            <view class="note" wx:for="{{notes}}" wx:for-item="note" wx:key="{{index}}">
                 <block wx:if="{{note.image.length < 3 }}">
                 <template is="templateone" data="{{...note}}"></template>
                 </block>
                 <block wx:elif="{{note.image.length >= 3}} ">
                 <template is="templatetwo" data="{{...note}}"></template>
                 </block>
      </view>
    </scroll-view>
  </swiper-item>
</swiper>

不一樣的新聞顯示模板 使用組件化的概念,建立一個template文件夾

<template name="templateone">
  <view class="newList">
         ...
  </view>  
</template>
<template name="templatetwo">
  <view class="newList">
         ...
  </view>  
</template>

在須要用到模板的地方就能夠直接使用

<import src="../../components/template/template.wxml"/>

既然要用到模板那接下來咱們就把模板給寫出來。分析一下模板裏面的內容

裏面的數據除時間之外都是能夠直接從後臺調取在頁面上顯示出來的數據,但時間不同,它是變化的
在數據庫中time字段以時間戳的形式保存。在後面的詳情頁中也要用到時間的格式化,so寫一個js封裝起來

數據的調取 JS

在小程序中咱們時時刻刻須要去請求數據,數據的調取封裝起來是極好的,存在util裏想用的時候拿一下就ok

wx.cloud.init();
const db = wx.cloud.database();
const notes = db.collection('articles');
// 加載notes,page=1默認形參 ,limit = 4 ,fn 
const loadNotes = (fn,page = 1,limit = 4) =>{
  //return 數據集 異步
  const skip = (page -1) * limit;
  notes
  .count()
  .then(() =>{
    return notes
    .limit(limit)
     .skip(skip)
    .get()
  })
  .then(res =>{
    //console.log(res.data)
    fn({
      data:res.data
    })
  })
  // fn(data);
};

module.exports = {
  loadNotes,
}

WXS實現時間格式

WXS 是小程序的一套腳本語言,結合WXML,能夠構建出頁面的結構。了該一哈

新建一個timeapi.wxs文件,在template.wxml引用,定義模塊名便可引用:

<wxs src="../../utils/timeapi.wxs" module="timeapi" ></wxs>
.....
 <text class="newList-item-time">{{timeapi.formatTime(time)}}</text>

timeapi.wxs文件和時間格式實現方法:

var formatTime = function (time) {
  // 獲取當前時間
  var getUnix = function () {
    var date = getDate()
    return date.getTime()
  }
  // 獲取今天零點時間
  var getTodayUnix = function () {
    var date = getDate()
    date.setHours(0)
    date.setMinutes(0)
    date.setSeconds(0)
    date.setMilliseconds(0)
    return date.getTime()
  }
  // 獲取今年的1月1日零點時間
  var getYearUnix = function () {
    var date = getDate()
    date.setMonth(0)
    date.setDate(1)
    date.setHours(0)
    date.setMinutes(0)
    date.setSeconds(0)
    date.setMilliseconds(0)
    return date.getTime()
  }
  // 獲取標準時間
  var getLastDate = function (time) {
    var date = getDate(time)
    var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
    var day = date.getDay() < 10 ? '0' + (date.getDay()) : date.getDay()
    return date.getFullYear() + '-' + month + '-' + day
  }
  // 轉換時間
  var getFormatTime = function (timestamp) {
    var now = getUnix()
    var today = getTodayUnix()
    var year = getYearUnix()
    var timer = (now - timestamp) / 1000
    var tip = ''
    if (timer <= 0) {
      tip = '剛剛'
    } else if (Math.floor(timer / 60) <= 0) {
      tip = '剛剛'
    } else if (timer < 3600) {
      tip = Math.floor(timer / 60) + '分鐘前'
    } else if (timer >= 3600 && (timestamp - today >= 0)) {
      tip = Math.floor(timer / 3600) + '小時前'
    } else if (timer / 86400 <= 31) {
      tip = Math.ceil(timer / 86400) + '天前'
    } else {
      tip = getLastDate(timestamp)
    }
    return tip
  }
  return getFormatTime(time)
}

  module.exports = {
    formatTime: formatTime
  }

wxs有優勢有缺點,用的時候要考慮好。注意如下三點。

  1. wxs 與 javascript 是不一樣的語言,有本身的語法,並不和 javascript 一致。
  2. wxs 的運行環境和其餘 javascript 代碼是隔離的,wxs 中不能調用其餘 javascript 文件中定義的函數,也不能調用小程序提供的API。
  3. 因爲運行環境的差別,在 iOS 設備上小程序內的 wxs 會比 javascript 代碼快 2 ~ 20 倍。在 android 設備上兩者運行效率無差別。

3.詳情頁

詳情頁涉及到三個表的內容。那就在雲函數裏完成表的查詢組裝輸出,多方便啊。
這個代碼就不貼了,要參考的話,底部會把GitHub貼出來,目錄在上面的圖片。
使用雲函數的話有個技巧。在開發工具裏看是否成功,且把數據傳輸過來了
如圖。


項目中的數據是從網站上爬下來的,數據庫裏的文章內容就是html的格式,so咱們應該把tml =>wxml

wxParse-微信小程序富文本解析自定義組件,支持HTML及markdown解析本

githup 上有使用方法,這裏我就不作重複的描述 點着
我這裏使用這個工具徹底是爲項目實現的而去作,若是真正作一個小程序新聞類項目確定是不太好的,先不說wxParse解析可能會出現亂碼,再就是它所佔的內存也不小。真正開發的時候就別用了,數據庫裏的數據也不會是html格式的。

在手機上顯示時(坑)

wxparse 代碼的一個 bug,在一些特殊的手機裏面,在 wxparse/html2json.js 中的第 112 和 119 行,都有一個 console.dir 這個函數的使用,把這個函數註釋掉,內容就能夠正常顯示出來

評論組件


咱們這裏提一下點贊功能實現,借用大佬的話

點讚的變化是由用戶產生的一個交互,傳統的觀點就是用戶點贊->後端更新數據->前端拉取數據->數據驅動視圖的變化。
真實的體驗就是,很是的慢,慢到點擊後2秒才能看到點讚的效果,這種差勁的交互簡直就是一場災難。

那咱們就先把樣式給用戶表現出來,數據交給後臺慢慢異步處理

4.登錄頁面

頁面佈局就沒啥好說的,

登

  • 登陸(知識點)
  1. getUserInfo
  2. button type="bindUserInfo"
  3. auth 受權登陸
  4. 高階函數
  5. 異步的處理

html部分

<view wx:if="{{auth === 0}}" > //判斷登陸狀況
             <button open-type="getUserInfo" 
                bindgetuserinfo="getUserInfo">
                 登陸
             </button>
</view>
            <view wx:else>
                <view class="top">
                    <image class="avatar" src="{{avatarUrl}}"/>
                    <view class="name">
                        <text class="nickname">{{nickname}}</text>
                        <button>申請認證</button>
                    </view>
            <icon type="zhixiang" color="#848484"></icon>  //封裝的icon
                </view>
//獲取應用實例
const app = getApp()
const globalData= app.globalData;

Page({
  data: {
    auth:-1,
    nickname:'',
    avatarUrl:''
  },
  onLoad: function () {
    this.getScope(this.getUserInfo,()=>{
      this.setData({
        auth:0
      })
    });
  },
  //高階函數 success 參數也是一個函數
  getScope(success,fail,name='scope.userInfo'){
    wx.getSetting({
      success:(res) => {
        // console.log(res); 
        if(res.authSetting[name]){
          success();
        }else{
          fail();
        }
      }
    })
  },
  getUserInfo (){
    // console.log('userinfo')
    if(!globalData.nickname||!globalData.avatarUrl){
      // 1. wx.getUserInfo(nickname,avatar)函數 
      // 2. 放到全局 函數
      this._getUserInfo((res) =>{
        // console.log(res);
        this.setData({
          nickname:res.nickName,
          avatarUrl:res.avatarUrl,
          auth:-1
        });
        globalData.nickname=res.nickName;
        globalData.avatarUrl=res.avatarUrl;
      });
    }
  },
  _getUserInfo(cb = () =>{}){
    wx.getUserInfo({
      success:(res) =>{
        cb(res.userInfo);
      }
    })
  }
})

六.總結


  • 頁面無非是基本結構和一堆模塊外加js交互組合起來的。快速完成一張簡單的demo的頁面只須要:繪製基本架構、增長功能模塊、js交互三步就能完成。
  • 繪製基本架構:第一步看頁面的基本構造,分析佈局,這時細節不重要,看整體架構,使用BEM命名規則增長合適的class命名格式,這樣能夠爲內部的模塊提供合理的class命名格式,避免class混亂而形成頁面樣式混亂,維護css樣式麻煩
  • wxml上不要不捨得套盒子,盒子就和分類箱同樣,給你整的明明白白,服服帖帖.
  • 在雲函數中,咱們大多會實現一些在小程序中沒法實現,這時咱們不能使用傳統的 Callback 方法來進行請求,由於傳統的 callback 方法執行完成後,雲函數早已將數據返回給客戶端,咱們須要使用 Promise 來處理。
  • 界面只是一架軀殼,而數據是靈魂,核心思想MVVM 數據驅動頁面

將平凡的事堅持下去,就會變的不平凡,路漫漫其修遠兮,吾將上下而求索。

您的鼓勵是我前行最大的動力,歡迎點贊,歡迎送小星星✨ ~

項目地址

相關文章
相關標籤/搜索