做者:鍾鑫css
hi, 你們好。我是來自京東凹凸實驗室的鐘鑫,Taro 框架核心開發成員。 目前我主要負責 Taro 框架多端組件及 API 相關。還有京東購物小程序首頁和搜索的相關研發。 電商類的應用,在在全部應用中比較常見,也是比較複雜的場景之一。那本次課程,基於 Taro 框架和 雲開發,來次電商小程序的實戰,教你搭建的電商小程序。前端
微信小程序是一種不須要安裝便可使用的應用,它的優點有不少。好比:git
本次課程,咱們使用 Taro 框架開發小程序。那 Taro 是什麼? 來看看官方文檔描述github
Taro 是一套遵循 React 語法規範的
多端開發
解決方案。現現在市面上端的形態多種多樣,Web、React-Native、微信小程序等各類端大行其道,當業務要求同時在不一樣的端都要求有所表現的時候,針對不一樣的端去編寫多套代碼的成本顯然很是高,這時候只編寫一套代碼就可以適配到多端的能力就顯得極爲須要。
使用 Taro,咱們能夠只書寫一套代碼,再經過 Taro 的編譯工具,將源代碼分別編譯出能夠在不一樣端(微信/百度/支付寶/字節跳動小程序、H五、React-Native 等)運行的代碼。數據庫
Taro 有一套完善的開發流程,在開發的時候也有很好的代碼智能提示,實時的代碼檢查,開發效率大幅提高。使用 Taro 能夠快速的發開小程序,未來若有其餘端的需求,咱們也只要維護一份代碼就行了~json
其次,本次課程選用的是小程序·雲開發做爲咱們的後臺服務。 那小程序·雲開發是什麼呢? 先來看看官方文檔的描述小程序
小程序·雲開發爲開發者提供完整的原生雲端支持和微信服務支持,弱化後端和運維概念,無需搭建服務器,使用平臺提供的 API 進行核心業務開發,便可實現快速上線和迭代,同時這一能力,同開發者已經使用的雲服務相互兼容,並不互斥後端
其實翻譯過來就是,一個在小程序中使用的,不用購買服務器,不用運維的簡易後端體系,主要是爲了突出快和簡便。因此小程序·雲開發,就很是適合那些對數據自己弱依賴的,中小型的功能性小程序使用。微信小程序
小程序·雲開發主要有幾大部分組成,分別是雲控制檯、數據庫、雲函數、存儲、雲調用。以及分別在小程序端,和雲端使用的 SDK。關於這幾部分的具體內容,能夠在官方文檔中查看。
與傳統的電商後端開發相比,小程序·雲開發有如下區別
傳統電商後端開發 | 小程序·雲開發 | |
---|---|---|
後端代碼 | 自主編寫、開發接口 | 開發接口,雲函數部署 |
服務器 | 自主購買、部署 | 官方提供,部署 |
數據監控 | 自主搭建 | 官方提供,控制檯查看 |
調用日誌 | 自主搭建 | 官方提供,控制檯查看 |
費用 | 服務器購買成本 | 免費配額,可申請上調 |
使用小程序•雲開發,咱們能夠省略後端部署、運維等步驟,能夠快速地構建所須要的後端應用。同時,雲函數的開發都是很是簡單的,官方提供的API可讓咱們便捷地進行操做。它能夠很快速上手。只需掌握 JavaScript 和一些異步處理相關的知識,對前端同窗比較友好。小程序·雲開發是小程序官方推出的一種解決方案,不用擔憂是否會繼續維護、升級迭代等的問題。
說了這麼多,是否是有點火燒眉毛的想體驗一下了?那接下來,開始搭建咱們的小程序。
要進行 Taro 的項目開發,首先天然要安裝 taro-cli,具體的安裝方法可參照 Taro 文檔,這裏不作過多介紹了,默認你已經裝好了 taro-cli 並能運行命令。 而後咱們用 cli 新建一個項目, 選擇雲開發模板。
而後咱們會獲得這樣的項目模板
├── client
│ ├── config
│ │ ├── dev.js
│ │ ├── index.js
│ │ └── prod.js
│ ├── index.html
│ ├── package.json
│ └── src
│ ├── app.js
│ ├── app.scss
│ ├── components
│ │ └── login
│ │ └── index.weapp.js
│ └── pages
│ └── index
│ ├── index.js
│ └── index.scss
├── cloud
│ └── functions
│ └── login
│ ├── index.js
│ └── package.json
└── project.config.json
複製代碼
能夠看到目錄裏主要分了兩大塊 client和 cloud:
client 裏和咱們日常小程序的開發目錄,存放的都是小程序裏業務代碼。
cloud 裏則是放雲函數相關的代碼,而且是以模板進行分割,每一個模塊一個雲函數。
pages裏面是各個頁面的入口文件,簡單的頁面就直接一個入口文件能夠了,假若頁面比較複雜那麼入口文件就會做爲組件的聚合文件
組件都放在components裏面。裏面的目錄是這樣的,假若有個 search 搜索頁面,在 pages 天然先有個 search,做爲頁面入口,而後它的組件就會存放在 components/search 裏面,就是components裏面也會按照頁面分模塊,公共的組件能夠建一個 components/* 文件夾,進行復用。這樣的好處是頁面之間互相獨立,互不影響。
接下來咱們開始添加頁面代碼。
首先咱們在搭建小程序的時候,須要把總體的流程給梳理清楚。大體的流程如圖所示:
固然,實際的業務會有更加複雜的流程,這裏咱們不細談。接下來咱們分別來看看相應的後臺服務如何去搭建。
咱們知道一個最簡單的後端程序就是,開啓一個 HTTP服務,鏈接上數據庫,而後根據收到的請求進行相關操做,例如數據庫的增刪查改,返回 HTML,返回接口數據之類,若是要知足外網訪問還要部署上線等等。
而用上了小程序·雲開發以後,由於雲函數這個概念,咱們免去了開啓服務器和部署的步驟。同時,小程序是自然先後端分離的,也不須要返回HTML。因此在這種狀況下,咱們所搭建的後臺服務最主要爲了實現兩個部分的內容,分別是數據庫的創建和先後端的數據交互。
數據庫創建,指的是數據集合及一些初始數據的建立。在本次搭建的示例中,主要含有一下數據集合:
以上基本就涵蓋了一個最簡單的電商所須要的各類數據,能夠構成一個完整的購物流程。 同時以下圖,還能夠設置數據集權限。例如將 Information、 Shop、Commodity設置爲全部用戶可讀、僅管理員可寫;將 Cart、 Order、 User改爲僅建立者及管理員可讀寫。經過權限限制,加強了數據集的可靠性。
數據集創建起來後,再往裏面填充一些假數據,基本的數據就有了,那麼在小程序中如何進行數據交互?
若是不是用小程序·雲開發,天然是經過request拉取接口數據,進行展現。而在使用了小程序·雲開發的狀況下,經過官方提供的 sdk,主要有兩種辦法進行數據拉取:
1.直接在小程序端操做數據庫,獲取所需數據,並進行增刪查改等操做。
2.使用雲函數,把數據庫的操做放到雲端;而後在小程序端調用雲函數,達到相似調用接口的效果。
第一種方法其實比較適合一些簡單的、對數據要求不高、量也不大的小程序。否則在小程序的代碼中混合着數據庫操做,實踐起來不太優雅,也不利於維護。
這裏咱們使用第二種方法。所謂雲函數,就是將一個函數放在 Node.js(即服務端)環境下運行。所以,咱們能夠將數據庫的操做放到雲函數中執行,而後在小程序中調用雲函數,達到一種相似調用接口的效果。
有了大體的思路以後,咱們就開始動手寫碼了~ 先來配置整個小程序的配置。在 src 的 app.js 中設置好相關信息,並初始化雲函數
class App extends Component {
config = {
pages: [
'pages/index/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#ffffff',
navigationBarTitleText: 'Taro商城',
navigationBarTextStyle: 'black'
},
tabBar: {
color: '#7b7b7a',
selectedColor: '#c0a369',
backgroundColor: '#222222',
list: [
{
pagePath: 'pages/index/index',
text: '首頁',
iconPath: 'asset/home.png',
selectedIconPath: 'asset/home_active.png'
},{
pagePath: 'pages/cart/cart',
text: '購物車',
iconPath: 'asset/shoppingbag.png',
selectedIconPath: 'asset/shoppingbag_active.png'
}, {
pagePath: 'pages/user/order/list/list',
text: '訂單',
iconPath: 'asset/mine.png',
selectedIconPath: 'asset/mine_active.png'
}]
},
cloud: true,
networkTimeout: {
request: 6000,
connectSocket: 10000,
uploadFile: 10000,
downloadFile: 10000
}
}
constructor () {
super(...arguments)
}
componentDidMount () {
Taro.cloud.init({
env: 'eshop-env-wuivn', // 獲取環境ID:前往 雲開發控制檯-設置-環境ID
traceUser: true // 是否要捕捉每一個用戶的訪問記錄。設置爲true,用戶可在管理端看到用戶訪問記錄
})
}
}
複製代碼
如題所示,首頁大體分爲頂部的搜索的組件,以及店鋪和商品展現的樓層組件。那很明顯能夠看出,搜索的組件,應該是一個公用的模塊,它會在搜索頁,分類頁之類的地方出現。那能夠把這塊組件抽離出來,進行復用。這裏由於時間關係,就不詳細展開。 而後下方的樓層組件,也是一些樣式佈局。由於時間關係,這裏咱們就用圖片代替。
index.js
<View className={indexClassNames}>
<View className='index-search_into'> <SearchInto placeholder='搜索框' type='index' /> </View> <ScrollView scrollY className='index_list'> { floorList.map((floor, index) => { return ( <View key={index} className={floor.className} onClick= {this.onGotoPage.bind(this, floor.venderId)}> <Image mode='widthFix' className='index_item_img' src={floor.image} lazyLoad /> </View> ) })} </ScrollView> </View> 複製代碼
從首頁進商詳的店鋪入口,那這裏的也是店鋪內的搜索加上展現樓層,樣式佈局也很少說,擼起來。 到這裏你能夠看到,這兩個頁面的邏輯只是簡單的根據 id 拉取數據並返回,由於總體也並無過多與用戶發生交互的部分,也沒有須要後端邏輯處理的部分,總的來講仍是比較簡單的,在這裏便不做過多介紹。
從店鋪進到商品詳情頁,這裏在加入購物車時,須要選擇商品的一些具體規格,默認地址等等。 那這裏咱們就簡單的只選擇下單的商品的一些詳情。這裏增長了下浮層交互,其餘的仍是一些拉取數據展現,也很少細講,還有不少細節部分大家能夠額外時間去研究下。
購物車頁相較於首頁和商詳頁,其邏輯一定是複雜了不少,下面結合頁面結構來分析一下。 上面的圖是購物車的截圖。能夠看到在購物車裏,小程序·雲開發端須要處理的邏輯有商品的選擇與反選、商品刪除、商品數量的更改、商品型號的更改等等。所以,咱們把購物車操做分類,獲得以下一個 map:
const typeMap = {
ADD: '2', // 加車
CHANGE_NUM: '3', // 改變數據
DEL: '4', // 刪除商品
CHECK: '5', // 選中商品
INVERT_CHECK: '6', // 反選商品
...
}
複製代碼
而後,在用戶執行相應的操做時,咱們便會執行到對應的操做函數:
switch (type) {
case typeMap['CHANGE_NUM']: newCartInfo = changCartNum(oldCartInfo, skus)
break
case typeMap['ADD']: newCartInfo = changCartNum(oldCartInfo, skus)
...
}
複製代碼
數組)。而後返回處理後、最新的 newCartInfo (新的購物車裏的商品)。具體的操做函數的邏輯咱們便再也不闡述了,主要就是對數組進行遍歷而後根據相關操做處理數據,更新完數據庫後,便會返回給前端最新的購物車數據。若是後續有新的購物車操做須要迭代,或者處理邏輯須要變動,咱們也只須要改變小程序·雲開發端執行函數 這一部分裏面的內容便可。
訂單頁這塊主要處理的是生成訂單的邏輯。每一個用戶的購物車中,已勾選的商品數據都是存放在數據庫中的,因此當用戶點擊了去結算按鈕,觸發告終算請求時,後端會直接從用戶數據庫中的購物車數據,生成一份訂單。詳細的流程能夠用以下的流程圖描述:
下面咱們來看具體代碼:
let cartData = await cartColl.doc(_id).get()
cartData = cartData.data
// 獲取購物車中被選中的數據
const payInfo = cartData.cartInfo.filter((item) => {
return item.isCheck
})
// 使用新的商品map
const oldShopMap = cartData.shopMap[0]
const newShop = {}
payInfo.forEach(item => {
newShop[item.venderId] = oldShopMap[item.venderId]
})
if (payInfo.length === 0) {
return {
code: -1,
msg: '購物車中沒有勾選物品'
}
}
const orderId = Math.random().toString(36).substr(2)
const orderData = {
_id: orderId,
dateSubmit: db.serverDate(),
orderId,
orderState: 1,
ownerId: _id,
payType,
shopInfo: newShop,
shouldPayPrice: cartData.totalPrice + freightPrice,
skuInfoList: payInfo,
cancelReasonText: '提交申請'
}
// 新插入訂單
await orderColl.add({data: orderData}).catch(err => console.log(err))
// 購物車中除移生成了訂單的商品
let newCartNum = 0
let newCartShopMap = {}
const newCartInfo = cartData.cartInfo.filter((item) => {
if (!item.isCheck) {
newCartShopMap[item.venderId] = oldShopMap[item.venderId]
newCartNum += item.num
return true
}
return false
})
await cartColl.doc(_id).update({data: {
cartInfo: newCartInfo,
cartNum: newCartNum,
shopMap: [newCartShopMap],
totalPrice: 0
}})
return {
code: 0,
msg: '成功生成訂單',
data: orderData
}
複製代碼
從代碼中能夠看到,先是遍歷當前購物車中的商品,而後把已經勾選的商品存放到 payInfo中。接着根據 payInfo 生成訂單數據,同時除移購物車中已被結算的商品,並更新購物車數據庫。
總體來講,並無太複雜的操做,不過須要注意的是,由於存在不少異步的操做,因此會有使用不少 async/await 命令來進行同步書寫。
除了生成訂單以外,還有取消訂單、刪除訂單等操做。相較於生成訂單,這些就只是讀取訂單、更改狀態而已,便不贅敘。
到這裏,今天的課程差很少也結束了。今天先談了 Taro 爲何選擇使用React語法,而後再從Taro項目的代碼組織,小程序•雲開發,項目的總體搭建思路,以及一些實現細節。 一個完整的電商小程序就算完成了,不過還有不少細節還能夠完善。好比,用戶的受權登陸,數據狀態管理器等等,這就算一些課外做業吧~ 最後,感謝你們參與本次課程,謝謝。