摘要:在這里詳細介紹一下操作云函數提取數據庫的流程這里我們以獲取首頁數據為例先在云函數目錄新建一個函數打開該云函數的我這里用的是環境。
寫在前面:
??小程序云開發發布有一段時間了,最近著手做了一個基于云開發的小程序項目--仿《微博鮮知》,來自新浪的這款全新風格的小程序雖然界面非常簡約清新,但是內部還是內藏了很多玄機,在實現的路上遇上了不少坎坷,在這里分享給大家。希望給大家提供一些思路。
先展示一下最終結果:更多圖片資源在這里
一、 組件化思想開發一個完整的小程序時,我們應該先分析其內部的結構。重復的結構抽離出來作為組件,組件非常的靈活,可以嵌入一個頁面或多個頁面。
??在上面的gif圖中我們可以看到首頁的內容是一個個的新聞塊。
雖然這個新聞塊只在首頁中使用到,但是我還是把它抽離成了一個組件。這樣做的好處是頁面結構將會更加的清晰,并且耦合度降低,比如想換個主界面風格時,你可以直接換另一個組件添加進來。
??還有新聞內部頁面中,有多個小標題,每個小標題里面嵌入了不等數量的新聞。如果不是采用組件化的話,到時候inner頁面的wxml結構就會亂成一鍋粥。所以這里的建議是盡量組件化分離開來。
對于組件很陌生可以先看我的之前的這篇文章 組件化開發tabbar
下面是項目的頁面與組件目錄:
既然是“全棧”,后端肯定要搞搞。后端的核心就是數據。那么我們就先把數據庫分析一下。這里我是這樣分析的,
從頁面獲得字段,
然后再理解數據間的關聯,如一對多,一對一。
這里我構建了5個集合
fresh-mainNews 主頁新聞集合
subNews字段是一個數列,存儲著fresh-subNews Doc的_id,這樣就將這兩個集合綁定了起來,在后面我們會講到在云函數中把這兩個集合融合起來返回一個新的數據變得完整一些的集合。
有人可能會問,云數據庫不是noSQL嗎,為什么不把所有數據全部整合到一個全部的JSON,那樣就可以只調用一次JSON。
我的理解是:
??我們查詢只是需要查詢我們想要的數據,不需要的數據可以等需要的時候再根據關聯去請求。
比如這個項目中的首頁新聞塊,每一個新聞塊內部都關聯著大量的子新聞,第一次加載就全部把這個小程序需要的所有數據都加載出來就有點瘋狂了。
fresh-subNews ? ? 內部頁面新聞小標題集合
fresh-comments ? ?評論集合
fresh-detailNews ? ?詳細新聞集合
fresh-users ? ? ? ?用戶集合
這里查看更多的數據庫信息
三、頁面構建??講到這里就該說頁面的構建了。頁面可以想象成一個架子,一個承載數據的容器。頁面通上數據,就變得活起來。MVVM,數據驅動視圖。交互靠數據,組件間的通信,組件與頁面間的通信都是數據。
??{{}} -> 就像是流浪法師大招神奇的傳送門。后面會將給出一個精彩的組件通信例子(點擊目錄如何實現標題欄置頂)。
云開發三大核心:
云函數:通俗的理解就是你寫的函數在云端運行,可以把復雜的業務邏輯放在云函數里
數據庫:一個既可在小程序前端操作,也能在云函數中讀寫的 JSON 數據庫
存儲:在小程序前端直接上傳/下載云端文件,在云開發控制臺可視化管理,可以上傳照片下載照片,或者一些其他文件。
在這里詳細介紹一下操作云函數提取數據庫的流程,
這里我們以獲取首頁數據為例:
先在云函數目錄新建一個函數:mianNewsGet
打開該云函數的index.js
我這里用的是vsCode+node+yarn環境。
open in terminal(在終端中打開),yarn一下,添加依賴。
或者參考云函數官方文檔
編寫云函數查詢數據
// 云函數入口文件 const cloud = require("wx-server-sdk") // 云函數初始化 cloud.init() //獲取數據庫句柄 const db = cloud.database() // 云函數入口函數 exports.main = async () => { const mainNewsList = []; //向fresh-mainNews集合中獲得全部數據、因為數據庫里面現在存的數據不多, //如果多的話可以設置一個limit以及skip來獲取特定數量的數據 const mainNews = await db.collection("fresh-mainNews").get(); for(let i = 0; i < mainNews.data.length; i++) { const mainNew = mainNews.data[i]; let user_id = mainNew.setMan; //條件查詢 獲取特定id的docments const user = await db.collection("fresh-users").where({ _id: user_id }).get(); //限定條件如果有多條,只添加一條進去 if (user.data.length > 0) { mainNew.setMan = user.data[0] } //這個循環是集合的拼接 for (let i = 0; i < mainNew.subNews.length; i++) { const subNews = await db.collection("fresh-subNews").where({ _id: mainNew.subNews[i] }).get(); if (subNews.data.length > 0) { mainNew.subNews[i] = subNews.data[0] } } //把拼好的docments挨個放進mainNewsList里面也就是形成了一個全新的 //融合的數據更為完整的JSON數組 mainNewsList.push(mainNew); } return mainNewsList; }
在首頁index.js里面onLoad函數里面調用云函數
var that = this; wx.cloud.callFunction({ // 聲明調用的函數名 name: "mainNewsGet", // data里面存放的數據可以傳遞給云函數的event 效果:event.a = 1 data: { a: 1 } }).then(res => { //res.result的值是云函數的return的值 //這里將查詢的結果放入mainNewsList中,然后就可以在wxml中調用數據 that.setData({ mainNewsList: res.result }) //打印一下結果看看有沒有成功獲取數據 console.log(this.data.mainNewsList) }).catch(err => { console.log(err) })
獲取的數據:
我們可以看到原本的subNews里面本來存放的是_id的數值,融合后變成_id對應的整個doc
變化:
[_id1.value,_id2.value] ---> [{_id1:value,key1:value1,key2:value2},~]
云函數的調用,數據庫的查詢。就是這么簡單的四步,云開發的門檻很低,功能也很強大,只要你去嘗試,很輕松的就能夠實現。
五、關于時間格式化。寫在utils文件夾里添加xx.js
const formatTime = date => { var dateNow = new Date(); var date = new Date(date); const hour = date.getHours() const minute = date.getMinutes() var times = (dateNow - date) / 1000; let tip = ""; if (times <= 0) { tip = "剛剛" return tip; } else if (Math.floor(times / 60) <= 0) { tip = "剛剛" return tip; } else if (times < 3600) { tip = Math.floor(times / 60) + "分鐘前" return tip; } else if (times >= 3600 && (times <= 86400)) { tip = Math.floor(times / 3600) + "小時前" return tip; } else if (times / 86400 <= 1) { tip = Math.ceil(times / 86400) + "昨天" } else if (times / 86400 <= 31 && times / 86400 > 1) { tip = Math.ceil(times / 86400) + "天前" } else if (times / 86400 >= 31) { tip = "好幾光年前~~" } else tip = null; return tip + [hour, minute].map(formatNumber).join(":") } const formatNumber = n => { n = n.toString() return n[1] ? n : "0" + n } //將這個接口暴露 module.exports = { formatTime: formatTime, }
在需要的頁面的xx.js里面引入
import { formatTime } from "../../utils/api.js";
格式化獲取的時間數據
let mainNewsList = that.data.mainNewsList for(let i =0; i < mainNewsList.length;i++) { let time = formatTime(mainNewsList[i].time) //這是setData()的數組用法,會經常用到 var str = "mainNewsList["+i+"].time" that.setData({ [str]:time }) }六、 關于一些很有用但是你可能不知道的小程序技巧
全屏顯示圖片,能夠實現多張圖片左右滑動并且還有數字索引現在在屏幕上,并且長按還能收藏以及下載(之前不知道這個API還特地做了一個組件來實現類似功能,簡直吐血)
wx.previewImage({ current: imgUrl, // 當前顯示圖片的http鏈接 urls: imagePack // 需要預覽的圖片http鏈接列表 })
非常方便的一個API能夠滑動到某個位置
wx.pageScrollTo({ scrollTop: 一個數值(自帶px單位), //滾動到數值所在的位置 duration: 50 //執行滾動所花的時間 })
查詢節點query.selectAll("類名")及query.select("#id")
官方文檔
var that = this let catalogIndex = that.data.catalogIndex; query.selectAll("類名").boundingClientRect(function (rects) { rects.forEach(function (rect) { rect.top // 節點的上邊界坐標st, //還有一些別的屬性,這個查詢節點是后面講到的目錄跳轉關鍵API }) }) }).exec() },
setData()一些技巧。
//給數組設置值 還可以有var xx = "xx["+idx+"].key"的形式 var doneList = "doneList["+idx+"]" that.setData({ [doneList]: true, })
有時候我們還可以先改變某個數的值再去setData()它,這是setData()的一個很好用的技巧,不過需要去運用一下才好理解
如:
dataPack.likeNum = (supLikeNum===-1 ? dataPack.likeNum: supLikeNum); this.setData({ comment: dataPack, })七、 項目最精彩的兩個部分 1.點擊目錄欄頁面將相應新聞欄置頂,先看下效果
??這個效果在別的小程序里面都沒有見過,應該是微博鮮知獨創的,在這里先對原作者表達一下敬意。內部的構造也是非常巧妙,不同于我們常見的外賣的錨點定位。
我們先來分析一波:
mvvm,視圖是由數據驅動的,我們要透過現象看本質,去思考底層的數據,這樣我們很快就會有思路:
點擊目錄欄的item項如果綁定了一個data-idx等于循環的索引,可以在e.currentTarget.dataset.idx拿到這個item的索引。
我們把這個數據通過組件通信傳遞到inner頁面,然后在由inner頁面把數據轉交給subNews
并且在inner頁面的js中綁定subNews的goTop事件,這樣產生了一個catalog組件->inner頁面->subNews的關聯,數據為item的索引。觸發catalog就能夠控制subNews組件的移動,是不是還有點繞, ok
show the code:
1.catalog/index.wxml
{{subNewsItem.title}}
獲得索引,并綁定inner頁面
catalog/index.js
scrollFind: function(e) { //點擊后 實現inner頁面特定新聞小標題置頂 let curIndex = e.currentTarget.dataset.hi // 關鍵2: 與inner頁面取得聯系 var myEventDetail = {index: curIndex} // detail對象,提供給事件監聽函數 var myEventOption = {} // 觸發事件的選項 this.triggerEvent("catalog", myEventDetail) }
inner/inner.js 取得與catalog的通信
onCatalog: function(e) { e.detail // 自定義組件觸發事件時提供的detail對象 console.log(e.detail.index) //關鍵:3 把索引存儲到data this.setData({ catalogIndex : e.detail.index }) //關鍵4: 頁面可以通過組件的id取得其頁面引用組件的方法 // this.subNews=this.selectComponent("#subNews") this.subNews.goTop(); },
給subNews傳catalogIndex,并且標上id
在subNews中先定義一個圖片加載事件,這樣在頁面加載完成時會觸發其綁定的事件,這是來自瀑布流的靈感??梢栽趫D片加載出來的時候觸發onImageLoad函數,而在這個函數里我們可以干一些準備的事情。
//subNews/index.wxml //一個看不見的圖片,來自瀑布流的靈感,能夠產生主動觸發的事件
//subNews/index.js onImageLoad: function () { var that = this let offsetList = that.data.offsetList; const query = wx.createSelectorQuery().in(this) //之前講到過的API獲取節點信息,我們把它存儲到offsetList偏移量數組,他存儲著每一個節點在屏幕的位置, //配合wx.pageScrollTo可以達到新聞欄置頂的效果 query.selectAll(".subNews-wrapper").boundingClientRect(function (rects) { rects.forEach(function (rect) { rect.top // 節點的上邊界坐標 offsetList.push(rect.top) that.setData({ offsetList, }) }) }).exec() },
給標題欄綁定上goTop事件
goTop: function (e) { var that = this let catalogIndex = that.data.catalogIndex; //這里offsetList是一個data里面的數據,來保存所有的節點的上邊距坐標 let offsetList = that.data.offsetList; wx.pageScrollTo({ scrollTop: offsetList[catalogIndex], //滾動到具體數值所在的位置 duration: 50 //執行滾動所花的時間 }) }
至此,你就實現了這個看似簡單卻非常巧妙的功能,組件->頁面->組件,秀得眼花繚亂。如果還是有些不理解的話,等下可以下載我的代碼去看。
至于為什么要弄一個圖片的加載然后觸發那個事件呢,這是因為如果你把獲取offsetList偏移量數組的函數放在goTop里的話,進入頁面第一次的點擊會無效,這樣產生的體驗肯定是非常不舒服的。
先展示一下效果:
先說一下優化的是什么:點贊效果的延遲極大降低
因為點贊的變化是由用戶產生的一個交互,傳統的觀點就是用戶點贊->后端更新數據->前端拉取數據->數據驅動視圖的變化。
真實的體驗就是,非常的慢,慢到點擊后2秒才能看到點贊的效果,這種差勁的交互簡直就是一場災難。
先給傳統的、局部刷新優化的,效果還是很差的一段代碼:
for(let i = 0; i< that.data.comments.length; i++) { //當點擊該個評論時,只更新這一條數據 if (i == idx) { var str = "comments["+idx+"].likeNum" that.setData({ [str]:res.result.data.likeNum, }) console.log(likeNumList[idx]) } }
優化后:
data: { doneList: [], //是否按下 likeNumList: [], //模擬點贊數數組 likeAdd: 10, //點贊每次增加數,根據你的設置來,你后端每次加1這里就寫1 }, var doneList = "doneList["+idx+"]" likeNumList[idx] = (that.data.comments[idx].likeNum + that.data.likeAdd); that.setData({ likeNumList, [doneList]: true, likeAdd: that.data.likeAdd+10 })
{{likeNumList[idx]?likeNumList[idx]:item.likeNum}}
優化思路是怎么樣的呢?
??用一個數組來存放/模擬更新的數據,如果數字的索引位置被賦值,則頁面直接顯示這個更新的數字,也是異曲同工之妙。因為用戶關心的是數據的變化,我們可以先把數據的變化產生,至于數據后端的變化讓他異步慢慢的去做。
??從這里發散思想,是不是評論功能也能夠用這樣的思路同樣去達到極致的速度與交互體驗呢。
點贊的延遲幾乎為無,體驗到點贊的極致快感,讓人幾乎停不下來~~(暗示一波)
篇幅所限,文章到這里就差不多了。
項目地址:https://github.com/HappyBirdwe/newsDance/tree/master/weiboFresh奉上
精心寫的項目,細節很不錯喲,歡迎大家☆☆☆ star ☆☆☆☆
結語:
學習的道路上免不了坎坷,希望文章的分享能夠為大家提供一些思路,學習的過程減少一點彎路,這就是這篇文章最大的價值,歡迎大家提問及指正。
最后在這里感謝一下:
??????騰訊云提供的技術支持
????新浪團隊的微博鮮知作者
??掘金這個優秀的平臺
點贊動作超帥的你
微博鮮知小程序官方傳送門:
體驗真的很不錯哦,界面非常簡約,大家可以體驗一波
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99169.html
摘要:深圳已然成為全國范圍內智能硬件的大本營基地。這必然會是一個雙贏乃至多贏的典型案例,在百度飛槳的崛起過程中,國產深度學習框架成為全球領頭羊重構當下深度學習的世界秩序也不是不可期待。 對廣大消費者而言,AI已經不是一個陌生詞匯,我們生活中能夠接觸到的消費產品,已經有相當一部分得到了AI的賦能。從...
摘要:華為云華為云在云原生這場游戲中,最具競爭力的玩家之一。年,金山云在云原生領域推出了三款重磅產品星曜裸金屬服務器云服務器和云盤。在線上智博會上,浪潮云發布了經過全新迭代升級的浪潮云,進一步提升平臺云原生服務能力。面對數字時代復雜系統的不確定性,傳統的 IT 應用架構研發交付周期長、維護成本高、創新升級難,煙囪式架構,開放性差、組件復用度低,這些都成為了企業業務快速增長的瓶頸。而云原生以其敏捷、...
摘要:目錄如何用提高效率后端掘金經常有人說我應該學一門語言,比如之類,但是卻不知道如何入門。本文將通過我是如何開發公司年會抽獎系統的后端掘金需求出現年會將近,而年會抽獎環節必不可少,但是抽獎系統卻還沒有。 云盤一個個倒下怎么辦?無需編碼,手把手教你搭建至尊私享云盤 - 工具資源 - 掘金微盤掛了,360倒了,百度云盤也立了Flag。能讓我們在云端儲存分享文件的服務越來越少了。 買一堆移動硬盤...
閱讀 2563·2021-09-30 10:00
閱讀 3497·2021-09-22 10:54
閱讀 6249·2021-09-07 10:28
閱讀 2950·2019-08-29 13:53
閱讀 748·2019-08-29 12:42
閱讀 964·2019-08-26 13:51
閱讀 1261·2019-08-26 13:32
閱讀 3026·2019-08-26 10:39