热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

記一次基於mpvue的小順序開闢及上線實戰

小順序稱號:一同打車吧項目地點:客戶端:https:github.comjrainlaut…服務端:https:github.comjrainlaut…小順序二維碼:經由為期兩個晚
  • 小順序稱號:一同打車吧
  • 項目地點:

    客戶端:https://github.com/jrainlau/t…

    服務端:https://github.com/jrainlau/t…

  • 小順序二維碼:

    《記一次基於mpvue的小順序開闢及上線實戰》

經由為期兩個晚上下班時候的勤奮,終究把我第一個小順序開闢完成並宣布上線了。全部歷程還算順遂,因為運用了mpvue計劃舉行開闢,故可以享用和vue一致的流通開闢體驗;背景體系運用了python3+flask框架舉行,運用起碼的代碼完成了小順序的背景邏輯。除了開闢以外,還實實在在地體驗了一把微信小順序的開闢流程,包含開闢者東西的運用、體驗版的宣布、上線的要求等等。這些開闢體驗都異常值得被記錄下來,因而便一氣呵成,寫下這篇文章。

一、需求&功用

因為公司里有相當多的同事都住在同一個小區,所以上下班的時刻常常會在公司群里組織拼車。然則因為完全依靠聊天記錄,且上下班拼車的同事也許多,依靠群聊很輕易把音訊刷走,而且輕易形成信息紊亂。既然如此,那末完全可以開闢一個小東西把這些問題解決。

提議拼車的人把動身地點、目標地點、打車信息以卡片的情勢分享出來,介入拼車的人點擊卡片就可以挑選列入拼車,而且能看到同車拼友是誰,拼單的信息等等內容。

交互流程以下:

《記一次基於mpvue的小順序開闢及上線實戰》

可以看到,邏輯是異常簡樸的,我們只須要保證天生拼單、分享拼單、進入拼單和退出拼單這四個功用就好。

需乞降功用已肯定好,起首依據小順序官網的引見,註冊好小順序並拿到appId,接下來可以最先舉行背景邏輯的開闢。

二、背景邏輯開闢

因為時候急急,功用又簡樸,所以並沒有斟酌任何高併發等龐雜場景,僅僅斟酌功用的完成。從需求的邏輯可以曉得,實在背景只須要保護兩個列表,離別存儲當前一切拼車單以及當前一切介入了拼車的用戶即可,其數據結構以下:

  • 當前一切拼單列表billsList

    《記一次基於mpvue的小順序開闢及上線實戰》

  • 當前一切介入了拼車的用戶列表inBillUsers

    《記一次基於mpvue的小順序開闢及上線實戰》

當用戶肯定並分享了一個拼單今後,會直接新建一個拼單,同時把該用戶增加到當前一切介入了拼車的用戶列表列表內里,而且增加到該拼單的成員列表當中:

《記一次基於mpvue的小順序開闢及上線實戰》

只需保護好這兩個列表,接下來就是詳細的營業邏輯了。

為了疾速開闢,這裏我運用了python3+flask框架的計劃。不懂python的讀者看到這裏也不必慌張,代碼異常簡樸且直白,看看也不妨。

起首新建一個BillController類:

class BillController:
billsList = []
inBillUsers = []

接下來會在這個類的內部增加建立拼單獵取拼單介入拼單退出拼單推斷用戶是不是在某一拼單中圖片上傳的功用。

1、獵取拼單getBill()

該要領吸收客戶端傳來的拼單ID,然後拿這個ID去檢索是不是存在對應的拼單。若存在則返回對應的拼單,不然報錯給客戶端。

def getBill(self, ctx):
ctxBody = ctx.form
billId = ctxBody['billId']
try:
return response([item for item in self.billsList if item['billId'] == billId][0])
except IndexError:
return response({
'errMsg': '拼單不存在!',
'billsList': self.billsList,
}, 1)

2、建立拼單createBill()

該要領會吸收來自客戶端的用戶信息拼單信息,離別增加到billsListinBillUsers當中。

def createBill(self, ctx):
ctxBody = ctx.form
user = {
'userId': ctxBody['userId'],
'billId': ctxBody['billId'],
'name': ctxBody['name'],
'avatar': ctxBody['avatar']
}
bill = {
'billId': ctxBody['billId'],
'from': ctxBody['from'],
'to': ctxBody['to'],
'time': ctxBody['time'],
'members': [user]
}
if ctxBody['userId'] in [item['userId'] for item in self.inBillUsers]:
return response({
'errMsg': '用戶已在拼單中!'
}, 1)
self.billsList.append(bill)
self.inBillUsers.append(user)
return response({
'billsList': self.billsList,
'inBillUsers': self.inBillUsers
})

建立完成后,會返回當前的billsListinBillUsers到客戶端。

3、介入拼單joinBill()

吸收客戶端傳來的用戶信息拼單ID,把用戶增加到拼單和inBillUsers列表中。

def joinBill(self, ctx):
ctxBody = ctx.form
billId = ctxBody['billId']
user = {
'userId': ctxBody['userId'],
'name': ctxBody['name'],
'avatar': ctxBody['avatar'],
'billId': ctxBody['billId']
}
if ctxBody['userId'] in [item['userId'] for item in self.inBillUsers]:
return response({
'errMsg': '用戶已在拼單中!'
}, 1)
theBill = [item for item in self.billsList if item['billId'] == billId]
if not theBill:
return response({
'errMsg': '拼單不存在'
}, 1)
theBill[0]['members'].append(user)
self.inBillUsers.append(user)
return response({
'billsList': self.billsList,
'inBillUsers': self.inBillUsers
})

4、退出拼單leaveBill()

吸收客戶端傳來的用戶ID拼單ID,然後刪撤除兩個列表內里的該用戶。

這個函數另有一個功用,假如推斷到這個拼單ID所對應的拼單成員為空,會以為該拼單已取消,會直接刪撤除這個拼單以及所對應的車輛信息圖片。

def leaveBill(self, ctx):
ctxBody = ctx.form
billId = ctxBody['billId']
userId = ctxBody['userId']
indexOfUser = [i for i, member in enumerate(self.inBillUsers) if member['userId'] == userId][0]
indexOfTheBill = [i for i, bill in enumerate(self.billsList) if bill['billId'] == billId][0]
indexOfUserInBill = [i for i, member in enumerate(self.billsList[indexOfTheBill]['members']) if member['userId'] == userId][0]
# 刪除拼單內里的該用戶
self.billsList[indexOfTheBill]['members'].pop(indexOfUserInBill)
# 刪除用戶列表內里的該用戶
self.inBillUsers.pop(indexOfUser)
# 假如拼單內里用戶為空,則直接刪除這筆拼單
if len(self.billsList[indexOfTheBill]['members']) == 0:
imgPath = './imgs/' + self.billsList[indexOfTheBill]['img'].split('/getImg')[1]
if os.path.exists(imgPath):
os.remove(imgPath)
self.billsList.pop(indexOfTheBill)
return response({
'billsList': self.billsList,
'inBillUsers': self.inBillUsers
})

5、推斷用戶是不是在某一拼單中inBill()

吸收客戶端傳來的用戶ID,接下來會依據這個用戶ID去inBillUsers內里去檢索該用戶所對應的拼單,假如能檢索到,會返回其地點的拼單。

def inBill(self, ctx):
ctxBody = ctx.form
userId = ctxBody['userId']
if ctxBody['userId'] in [item['userId'] for item in self.inBillUsers]:
return response({
'inBill': [item for item in self.inBillUsers if ctxBody['userId'] == item['userId']][0],
'billsList': self.billsList,
'inBillUsers': self.inBillUsers
})
return response({
'inBill': False,
'billsList': self.billsList,
'inBillUsers': self.inBillUsers
})

6、圖片上傳uploadImg()

吸收客戶端傳來的拼單ID圖片資本,先存儲圖片,然後把該圖片的途徑寫入對應拼單ID的拼單當中。

def uploadImg(self, ctx):
billId = ctx.form['billId']
file = ctx.files['file']
filename = file.filename
file.save(os.path.join('./imgs', filename))
# 把圖片信息掛載到對應的拼單
indexOfTheBill = [i for i, bill in enumerate(self.billsList) if bill['billId'] == billId][0]
self.billsList[indexOfTheBill]['img'] = url_for('getImg', filename=filename)
return response({
'billsList': self.billsList
})

完成了營業邏輯的功用,接下來就是把它們分發給差別的路由了:

@app.route('/create', methods = ['POST'])
def create():
return controller.createBill(request)
@app.route('/join', methods = ['POST'])
def join():
return controller.joinBill(request)
@app.route('/leave', methods = ['POST'])
def leave():
return controller.leaveBill(request)
@app.route('/getBill', methods = ['POST'])
def getBill():
return controller.getBill(request)
@app.route('/inBill', methods = ['POST'])
def inBill():
return controller.inBill(request)
@app.route('/uploadImg', methods = ['POST'])
def uploadImg():
return controller.uploadImg(request)
@app.route('/getImg/')
def getImg(filename):
return send_from_directory('./imgs', filename)

完全的代碼可以直接到堆棧檢察,這裏僅展現癥結的內容。

三、前端營業開闢

前端藉助vue-cli直接運用了mpvue的mpvue-quickstart來初始化項目,詳細歷程不再細述,直接進入營業開闢部份。

起首,微信小順序的API都是callback作風,為了運用方便,我把用到的小順序API都包裝成了Promise,一致放在src/utils/wx.js內部,相似下面如許:

export const request = obj => new Promise((resolve, reject) => {
wx.request({
url: obj.url,
data: obj.data,
header: { 'content-type': 'application/x-www-form-urlencoded', ...obj.header },
method: obj.method,
success (res) {
resolve(res.data.data)
},
fail (e) {
console.log(e)
reject(e)
}
})
})

1、註冊全局Store

因為開闢習氣,我喜好把一切接口要求都放在store內里的actions當中,所以這個小順序也是須要用到Vuex。但因為小順序每個Page都是一個新的Vue實例,所以依據Vue的體式格局,用全局Vue.use(Vuex)是不會把$store註冊到實例當中的,這一步要手動來。

src/目次下新建一個store.js文件,然後在內里舉行運用註冊:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({})

接下來在src/main.js當中,手動在Vue的原型里註冊一個$store

import Vue from 'vue'
import App from './App'
import Store from './store'
Vue.prototype.$store = Store

如許,今後在任何的Page里都可以經由過程this.$store來操縱這個全局Store了。

2、構建好要求的API接口

和背景體系的邏輯對應,前端也要組織好各個要求的API接口,如許的做法可以防止把API邏輯疏散到頁面四周,具有清楚、易保護的上風。

/**
* @param {} {commit}
* 獵取用戶公然信息
*/
async getUserInfo ({ commit }) {
const { userInfo } = await getUserInfo({
withCredenitals: false
})
userInfo.avatar = userInfo.avatarUrl
userInfo.name = userInfo.nickName
userInfo.userId = encodeURIComponent(userInfo.nickName + userInfo.city + userInfo.gender + userInfo.country)
commit('GET_USER_INFO', userInfo)
return userInfo
},
/**
* @param {} {commit}
* @param { String } userId 用戶ID
* 搜檢用戶是不是已存在於某一拼單中
*/
async checkInBill ({ commit }, userId) {
const res = await request({
method: 'post',
url: `${apiDomain}/inBill`,
data: {
userId
}
})
return res
},
/**
* @param {} {commit}
* @param { String } userId 用戶ID
* @param { String } name 用戶昵稱
* @param { String } avatar 用戶頭像
* @param { String } time 動身時候
* @param { String } from 動身地點
* @param { String } to 目標地點
* @param { String } billId 拼單ID
* 建立拼單
*/
async createBill ({ commit }, { userId, name, avatar, time, from, to, billId }) {
const res = await request({
method: 'post',
url: `${apiDomain}/create`,
data: {
userId,
name,
avatar,
time,
from,
to,
billId
}
})
commit('GET_BILL_INFO', res)
return res
},
/**
* @param {} {commit}
* @param { String } billId 拼單ID
* 獵取拼單信息
*/
async getBillInfo ({ commit }, billId) {
const res = await request({
method: 'post',
url: `${apiDomain}/getBill`,
data: {
billId
}
})
return res
},
/**
* @param {} {commit}
* @param { String } userId 用戶ID
* @param { String } name 用戶昵稱
* @param { String } avatar 用戶頭像
* @param { String } billId 拼單ID
* 列入拼單
*/
async joinBill ({ commit }, { userId, name, avatar, billId }) {
const res = await request({
method: 'post',
url: `${apiDomain}/join`,
data: {
userId,
name,
avatar,
billId
}
})
return res
},
/**
* @param {} {commit}
* @param { String } userId 用戶ID
* @param { String } billId 拼單ID
* 退出拼單
*/
async leaveBill ({ commit }, { userId, billId }) {
const res = await request({
method: 'post',
url: `${apiDomain}/leave`,
data: {
userId,
billId
}
})
return res
},
/**
* @param {} {commit}
* @param { String } filePath 圖片途徑
* @param { String } billId 拼單ID
* 列入拼單
*/
async uploadImg ({ commit }, { filePath, billId }) {
const res = await uploadFile({
url: `${apiDomain}/uploadImg`,
header: {
'content-type': 'multipart/form-data'
},
filePath,
name: 'file',
formData: {
'billId': billId
}
})
return res
}

3、填寫拼單並完成分享功用完成

新建一個src/pages/index目次,作為小順序的首頁。

該首頁的營業邏輯以下:

  1. 進入首頁的時刻先獵取用戶信息,獲得userId
  2. 然後用userId去要求推斷是不是已處於拼單
  3. 如果,則跳轉到對應拼單Id的詳情頁
  4. 若否,才許可新建拼單

onShow的生命周期鈎子中完成上述邏輯:

async onShow () {
this.userInfo = await this.$store.dispatch('getUserInfo')
const inBill = await this.$store.dispatch('checkInBill', this.userInfo.userId)
if (inBill.inBill) {
wx.redirectTo(`../join/main?billId=${inBill.inBill.billId}&fromIndex=true`)
}
},

當用戶填寫完拼單后,會點擊一個帶有open-type="share"屬性的button,然後會觸發onShareAppMessage生命周期鈎子的邏輯把拼單構形成卡片分享出去。當分享勝利後會跳轉到對應拼單ID的列入拼單頁。

onShareAppMessage (result) {
let title = '一同拼車'
let path = '/pages/index'
if (result.from === 'button') {
this.billId = 'billId-' + new Date().getTime()
title = '我提議了一個拼車'
path = `pages/join/main?billId=${this.billId}`
}
return {
title,
path,
success: async (res) => {
await this.$store.dispatch('createBill', { ...this.userInfo, ...this.billInfo })
// 上傳圖片
await this.$store.dispatch('uploadImg', {
filePath: this.imgSrc,
billId: this.billId
})

// 分享勝利后,會帶着billId跳轉到列入拼單頁
wx.redirectTo(`../join/main?billId=${this.billId}`)
},
fail (e) {
console.log(e)
}
}
},

4、介入拼單&退出拼單功用完成

新建一個src/pages/join目次,作為小順序的“列入拼單頁”。

該頁面的運轉邏輯以下:

  1. 起首會獵取從url內裡帶來的billId
  2. 其次會要求一次userInfo,獵取userId
  3. 然後拿這個userId去搜檢該用戶是不是已處於拼單
  4. 假如已處於拼單,那末就會獵取一個新的billId替代從url獵取的
  5. 拿當前的billId去查詢對應的拼單信息
  6. 假如billId都無效,則redirect到首頁

因為要獵取url照顧的內容,親測onShow()是不可的,只能在onLoad()內里獵取:

async onLoad (options) {
// 1. 起首會獵取從url內裡帶來的billId
this.billId = options.billId
// 2. 其次會要求一次userInfo,獵取userId
this.userInfo = await this.$store.dispatch('getUserInfo')
// 3. 然後拿這個userId去搜檢該用戶是不是已處於拼單
const inBill = await this.$store.dispatch('checkInBill', this.userInfo.userId)
// 4. 假如已處於拼單,那末就會有一個billId
if (inBill.inBill) {
this.billId = inBill.inBill.billId
}
// 5. 假如沒有處於拼單,那末將要求當前billId的拼單
// 6. 假如billId都無效,則redirect到首頁,不然搜檢當前用戶是不是處於該拼單當中
await this.getBillInfo()
}

另外,當用戶點擊“介入拼車”后,須要從新要求拼單信息,以革新視圖拼車職員列表;當用戶點擊“退出拼車”后,要重定向到首頁。

經由上面幾個步驟,客戶端的邏輯已完成,可以舉行預宣布了。

四、預宣布&要求上線

假如要宣布預宣布版本,須要運轉npm run build敕令,打包出一個臨盆版本的包,然後經由過程小順序開闢者東西的上傳按鈕上傳代碼,並填寫測試版本號:

《記一次基於mpvue的小順序開闢及上線實戰》

接下來可以在小順序治理背景→開闢治理→開闢版本當中看到體驗版小順序的信息,然後挑選宣布體驗版即可:

《記一次基於mpvue的小順序開闢及上線實戰》

當肯定預宣布測試無誤今後,就可以夠點擊“提交考核”,正式把小順序提交給微信團隊舉行考核。考核的時候異常快,在3小時內基礎都可以有回復。

值得注意的是,小順序一切要求的API,都必須經由域名備案運用https證書,同時要在設置→開闢設置→服務器域名內里把API增加到白名單才可以一般運用。

五、跋文

這個小順序如今已宣布上線了,算是完全體驗了一把小順序的開闢興趣。小順序獲得了微信團隊的大力支持,今後的生態只會愈來愈繁華。當初小順序上線的時刻我也對它有一些抵牾,但厥後想了想,這隻不過是前端工程師所需面臨的又一個“端“罷了,沒有必要為它戴上有色眼鏡,多控制一些老是好的。

“一同打車吧”微信小順序依然是一個玩具般的存在,僅供本身進修和探究,固然也迎接列位讀者可以孝敬代碼,介入開闢~


推荐阅读
  • 微信民众号商城/小顺序商城开源项目介绍及使用教程
    本文介绍了一个基于WeiPHP5.0开发的微信民众号商城/小顺序商城的开源项目,包括前端和后端的目录结构,以及所使用的技术栈。同时提供了项目的运行和打包方法,并分享了一些调试和开发经验。最后还附上了在线预览和GitHub商城源码的链接,以及加入前端交流QQ群的方式。 ... [详细]
  • 小程序获取用户信息按钮返回中文地址
    1.我是根据官方文档中描述去写的按钮 可以看到button中加了zh_CNopen-typegetUserInfobindgetuserinfogetU ... [详细]
  • 起因由于我录制过一个小程序的课程,里面有消息模板的讲解。最近有几位同学反馈官方要取消消息模板,使用订阅消息。为了方便大家容易学 PythonFlask构建微信小程序订餐系统 课程。 ... [详细]
  • 最近做项目时遇到一个问题,产品搜索后出来相关的列表,点击相关商品进入它的详情,返回后组件被重新创建,但产品需求是需要保留进入 ... [详细]
  • 云开发与
    大家好,今天我来为大家分享一下,Linux命令查询小程序中的WePY云开发实践。WhyWePY首先,先分享一下为什么要选择WePY?在项目开始进行选型的时候,我可选的底层框架有We ... [详细]
  • Linux命令如何查询小程序中的WePY云开发
    这篇文章给大家分享的是有关Linux命令如何查询小程序中的WePY云开发的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。W ... [详细]
  • mpvue框架:搭建流程
    mpvue介绍mpvue(github地址请参见)是一个使用Vue.js开发小程序的前端框架。框架基于Vue.js核心,mpvue修改了 ... [详细]
  • 要论2018年最吸引人的技术是什么?绝对非微信小程序莫属。小程序从2016年开始内测公测,到2017年的不温不火,一直到2017年低&#x ... [详细]
  • 小程序mpvue图片绘制水印_16【微信小程序全栈开发课程】mpvue小程序框架搭建及介绍...
    mpvue是美团开源的一个快捷开发小程序的框架,让我们可以使用vue.js语法编写小程序。大大降低了开发小程序的门槛,非常给力的一个框架。1、首先需要安 ... [详细]
  • uni-app入门uni,从这个单词的意思,就能看的出来,Dcoud社区的野心这个试图统治整个前端界的技术,到底有没有那么好呢࿱ ... [详细]
  • 做了一个类似微信通讯录的效果,用的时mpvue做的页面滚动,当滚动到A字母时,右侧A字母会出现一个蓝底的样式,但是在滚动的时候,数据渲染延迟了, ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 用ESP32与Python实现物联网(IoT)火焰检测报警系统
    下图是本案例除硬件连线外的3步导学开发过程,每个步骤中实现的功能请参考图中的说明。在硬件连线完成之后我们建议您先使用“一分钟上云体验”功能预先体验本案例的实际运行效果 ... [详细]
  • wx.showToast不能超过7个字的BUG何时解决?如何用别的代替?后端返回的message一般都比较长但是带图标的wx.showToast不能超过7个字只能去 ... [详细]
  • 怎么将iconfont字体图标引入到mpvue小程序中
    今天就跟大家聊聊有关怎么将iconfont字体图标引入到mpvue小程序中,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望 ... [详细]
author-avatar
小强
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有