應該每一個前端開發者都有一顆全干全棧的心💗吧。 那就讓雲開發滿足你
雲開發一出來就開始玩,雲數據庫,雲函數,全棧的體驗和開發速度,真的不是一般的爽。 接下來工作中要開發一款新聞類小程序,於是就開始了對頭條君的調研,此篇文章,是我的個人總結和分析,歡迎大佬拍磚。
一. 准備
- 小程序雲開發必須有小程序AppId才能使用,所以首先應先注冊一個小程序賬號(如果已有請忽略)。設置->開發設置中的小程序AppId
- 開發工具:編輯器-vscode, 微信開發者工具
-
輔助工具:
- Markman:圖標標注工具,可用於取色、測量。
- 小程序雲開發文檔:文檔
- Iconfont-阿里巴巴矢量圖標庫: 各種你需要的圖標,下載代碼,體量比用圖片小多了
- 組件庫
:剛開始項目的時候我使用了vant組件庫,想快速的完成項目,寫着寫着就發現使用起來有點麻煩,樣式達不到自己想要的。所以我果斷拋棄了它,我當然不能承認自己菜,只好說這個組件坑,我的項目中也就沒使用組件庫。但用組件庫能極大的提升開發的速度,聽大佬說wux這個組件庫很好用,同行們可以試試。感覺“真香”的記得告訴我
看看效果圖:(沒有展示全,下面有更多配圖以供學習這個項目)
二. 先聊聊雲開發
小程序雲開發是什么???
開發者可以使用雲開發開發微信小程序、小游戲,無需搭建服務器,即可使用雲端能力。
雲開發為開發者提供完整的雲端支持,弱化后端和運維概念,無需搭建服務器,使用平台提供的 API
進行核心業務開發,即可實現快速上線和迭代,同時這一能力,同開發者已經使用的雲服務相互兼容 > ,並不互斥。目前提供三大基礎能力支持:
- 雲函數:在雲端運行的代碼,微信私有協議天然鑒權,開發者只需編寫自身業務邏輯代碼
- 數據庫:一個既可在小程序前端操作,也能在雲函數中讀寫的 JSON 數據庫
- 存儲:在小程序前端直接上傳/下載雲端文件,在雲開發控制台可視化管理
這是官方文檔的描述
其實簡單的來說小程序雲開發是一款Serverless服務,開發者可以使用它開發微信小程序、小游戲,無需搭建服務器,即可使用雲端能力。目前提供雲函數、數據庫、存儲三大基礎能力支持。,並且將這些能力封裝成特定的接口,以wx.cloud.xxx來進行調用。
三.數據庫建立
根據需求建立了三個集合
- 文章基本信息articles
- 文章詳情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有優點有缺點,用的時候要考慮好。注意以下三點。
- wxs 與 javascript 是不同的語言,有自己的語法,並不和 javascript 一致。
- wxs 的運行環境和其他 javascript 代碼是隔離的,wxs 中不能調用其他 javascript 文件中定義的函數,也不能調用小程序提供的API。
- 由於運行環境的差異,在 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.登陸頁面
頁面布局就沒啥好說的,
- 登錄(知識點)
- 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 數據驅動頁面
將平凡的事堅持下去,就會變的不平凡,路漫漫其修遠兮,吾將上下而求索。
您的鼓勵是我前行最大的動力,歡迎點贊,歡迎送小星星✨ ~