應該每一個前端開發者都有一顆全乾全棧的心?吧。 那就讓雲開發滿足你
雲開發一出來就開始玩,雲資料庫,雲函式,全棧的體驗和開發速度,真的不是一般的爽。 接下來工作中要開發一款新聞類小程式,於是就開始了對頭條君的調研,此篇文章,是我的個人總結和分析,歡迎大佬拍磚。
準備
- 小程式雲開發必須有小程式AppId才能使用,所以首先應先註冊一個小程式賬號(如果已有請忽略)。設定->開發設定中的小程式AppId
- 開發工具:編輯器-vscode, 微信開發者工具
- 輔助工具:
- Markman:圖示標註工具,可用於取色、測量。
- 小程式雲開發文件:文件
- Iconfont-阿里巴巴向量圖示庫: 各種你需要的圖示,下載程式碼,體量比用圖片小多了
- 元件庫 :剛開始專案的時候我使用了vant元件庫,想快速的完成專案,寫著寫著就發現使用起來有點麻煩,樣式達不到自己想要的。所以我果斷拋棄了它,我當然不能承認自己菜,只好說這個元件坑,我的專案中也就沒使用元件庫。但用元件庫能極大的提升開發的速度,聽大佬說wux這個元件庫很好用,同行們可以試試。感覺“真香”的記得告訴我
看看效果圖:(沒有展示全,下面有更多配圖以供學習這個專案)
先聊聊雲開發
小程式雲開發是什麼???
開發者可以使用雲開發開發微信小程式、小遊戲,無需搭建伺服器,即可使用雲端能力。
雲開發為開發者提供完整的雲端支援,弱化後端和運維概念,無需搭建伺服器,使用平臺提供的 API 進行核心業務開發,即可實現快速上線和迭代,同時這一能力,同開發者已經使用的雲服務相互相容 > ,並不互斥。
目前提供三大基礎能力支援:
- 雲函式:在雲端執行的程式碼,微信私有協議天然鑑權,開發者只需編寫自身業務邏輯程式碼
- 資料庫:一個既可在小程式前端操作,也能在雲函式中讀寫的 JSON 資料庫
- 儲存:在小程式前端直接上傳/下載雲端檔案,在雲開發控制檯視覺化管理
這是官方文件的描述
其實簡單的來說小程式雲開發是一款Serverless服務,開發者可以使用它開發微信小程式、小遊戲,無需搭建伺服器,即可使用雲端能力。目前提供雲函式、資料庫、儲存三大基礎能力支援。,並且將這些能力封裝成特定的介面,以wx.cloud.xxx來進行呼叫。
資料庫建立
根據需求建立了三個集合
- 文章基本資訊articles
三個集合通過id欄位“連線”,要是個新手這時會想那麼麻煩幹嘛,直接全部放一起,梭哈一下,全給拿過來,直接用。這肯定是不行的,想想要是這個資料多怎麼辦,你要讓使用者等你多久? 作為前端工程師肯定是希望給使用者帶來極佳的使用體驗,所以你想在頁面上展示什麼,就設定一個對應的資料去關聯,要什麼取什麼。後臺資料無非就是一對一,一對多,你要啥資料就用傳相關欄位進雲函式,在雲函式裡進行簡單的增刪改查。
千萬記住,要考慮你的集合資料的使用範圍進行許可權設定,比如我新增的是articles文章,那這是公開的。那我就應該在許可權設定中修改為所有使用者可讀、僅管理員可寫,預設的是僅建立者及管理員可讀寫。
如何建表,表和表之間的聯絡,在動手專案之前要考慮好,避免表裡的內容重複導致記憶體浪費,在能實行其功能的基礎上做到不浪費記憶體。我上面的表建的就有點問題,圖片URL的地址存錯了地方,而且在兩表裡都儲存了,大家做的時候可以吸取我的教訓。
專案分析
頭條功能那麼多是不可能寫的完,我們在這裡就選擇其首頁、新聞詳情、登入介面這部分來實現一下。
首頁推薦:頭條裡面有不同的新聞樣式,有無圖的,一張圖的還有三張圖的,所以我們肯定要分離出不同的模板,根據後臺傳過來的資料去判斷新聞的樣式最後在頁面中顯示出來 資料驅動頁面
- MVVM
- M 是資料 模型
- V view 頁面 檢視
- VM 資料繫結到介面上 檢視模型 -> 模板{{}}
新聞詳情:開啟新聞詳情頁,分析之後發現大體分為三個部分 頭部的作者資訊 新聞內容 底部的使用者評論 這些資訊都是在雲開發資料庫中不同的集合裡面,這些資料的提取操作封裝在雲函式裡面以便呼叫 這三部分都是重複的結構抽離出來作為元件,元件非常的靈活,這樣做的好處是頁面結構將會更加的清晰,增加程式碼的複用性,並且耦合度降低,後續程式的維護也更為方便。
登入介面:直接使用wx.getUserInfo獲得使用者資訊 後面會貼出js程式碼
功能實現不詳解
目錄
首頁
該頁面採用頂部的固定搜尋欄、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有優點有缺點,用的時候要考慮好。注意以下三點。
- wxs 與 javascript 是不同的語言,有自己的語法,並不和 javascript 一致。
- wxs 的執行環境和其他 javascript 程式碼是隔離的,wxs 中不能呼叫其他 javascript 檔案中定義的函式,也不能呼叫小程式提供的API。
- 由於執行環境的差異,在 iOS 裝置上小程式內的 wxs 會比 javascript 程式碼快 2 ~ 20 倍。在 android 裝置上二者執行效率無差異。
詳情頁
詳情頁涉及到三個表的內容。那就在雲函式裡完成表的查詢組裝輸出,多方便啊。 這個程式碼就不貼了,要參考的話,底部會把GitHub貼出來,目錄在上面的圖片。 使用雲函式的話有個技巧。在開發工具裡看是否成功,且把資料傳輸過來了。 如圖。
專案中的資料是從網站上爬下來的,資料庫裡的文章內容就是html的格式,so我們應該把tml =>wxmlwxParse-微信小程式富文字解析自定義元件,支援HTML及markdown解析本
githup 上有使用方法,這裡我就不做重複的描述 點著 我這裡使用這個工具完全是為專案實現的而去做,如果真正做一個小程式新聞類專案肯定是不太好的,先不說wxParse解析可能會出現亂碼,再就是它所佔的記憶體也不小。真正開發的時候就別用了,資料庫裡的資料也不會是html格式的。
在手機上顯示時(坑)
wxparse 程式碼的一個 bug,在一些特殊的手機裡面,在 wxparse/html2json.js 中的第 112 和 119 行,都有一個 console.dir 這個函式的使用,把這個函式註釋掉,內容就可以正常顯示出來
評論元件
我們這裡提一下點贊功能實現,借用大佬的話點讚的變化是由使用者產生的一個互動,傳統的觀點就是使用者點贊->後端更新資料->前端拉取資料->資料驅動檢視的變化。 真實的體驗就是,非常的慢,慢到點選後2秒才能看到點讚的效果,這種差勁的互動簡直就是一場災難。
那我們就先把樣式給使用者表現出來,資料交給後臺慢慢非同步處理
登陸頁面
頁面佈局就沒啥好說的,
- 登入(知識點)
-
getUserInfo
-
button type="bindUserInfo"
-
auth 授權登入
-
高階函式
-
非同步的處理
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 資料驅動頁面
將平凡的事堅持下去,就會變的不平凡,路漫漫其修遠兮,吾將上下而求索。
您的鼓勵是我前行最大的動力,歡迎點贊,歡迎送小星星✨ ~