做者:钟鑫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项目的代码组织,小程序•云开发,项目的总体搭建思路,以及一些实现细节。 一个完整的电商小程序就算完成了,不过还有不少细节还能够完善。好比,用户的受权登陆,数据状态管理器等等,这就算一些课外做业吧~ 最后,感谢你们参与本次课程,谢谢。