本文將對微信小程序從開始開發到發佈上線的詳細過程進行講解,歡迎大家加入微信羣交流討論,點擊獲取入羣二維碼
《超級顏值計算器》小程序源碼託管在Github上,可自行clone修改: https://github.com/dreamans/BeautyCalculator
開發前的準備工作
開發前準備工作請參考以下文章:
微信小程序開發: 開發前準備工作
微信小程序開發: 小程序源文件結構及含義
小程序預覽
小程序名稱:《超級顏值計算器》
小程序碼:
UI預覽:
賬號申請
註冊小程序
註冊小程序, 註冊成功後進入郵箱查找激活郵件,如實填寫相關信息,如下:
設置小程序信息
註冊成功後會進入小程序發佈流程
,按要求設置小程序相關信息即可,如下:
AppID&&AppSecret
在 設置
- 開發設置
中獲取小程序的AppID和AppSecret
其他接口申請
小程序依賴face++的圖像面部識別接口,小夥伴可到其官網上自行申請賬號,申請地址,接口文檔地址
註冊成功後登錄face++的Console平臺,進入應用管理
- API Key
獲取接口所需的key和secret。
有一點問題需要注意,免費版用戶被限制了調用併發量,會經常出現 CONCURRENCY_LIMIT_EXCEEDED 併發數超過限制
錯誤。
開始開發
開發者工具
運行 開發者工具
, 選擇 小程序項目
,填寫項目目錄、AppID(mp平臺中獲取)、項目名稱等。
小程序配置文件
在根目錄下創建小程序配置文 app.json
,並配置相關信息
小程序頁面列表
每一項代表一個頁面,第一項代表程序的初始頁面,此處我們設置了兩個頁面,分別是:
pages/index/index
程序主頁面
pages/reward/reward
程序打賞頁面
"pages": [
"pages/index/index",
"pages/reward/reward"
],
window 設置
接下來我們來設置小程序的導航欄樣式和標題名稱等window屬性:
"window": {
"navigationBarTitleText": "超級顏值計算器",
"navigationBarBackgroundColor": "#ff8c00",
"navigationBarTextStyle": "white",
"navigationStyle": "default",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light",
"enablePullDownRefresh": false
},
tabBar 設置
此次我們開發的小程序是一個多tab的應用,以下是tabBar的設置信息:
"tabBar": {
"color": "#9ca0a3",
"selectedColor": "#00ae66",
"list": [
{
"pagePath": "pages/index/index",
"text": "首頁",
"iconPath": "asset/icon/home.png",
"selectedIconPath": "asset/icon/home_selected.png"
},
{
"pagePath": "pages/reward/reward",
"text": "打賞",
"iconPath": "asset/icon/reward.png",
"selectedIconPath": "asset/icon/reward_selected.png"
}
]
},
其他配置信息請見源文件
全局樣式設置
在根目錄下創建全局樣式文件 app.wxss
,會作用於當前小程序的所有頁面。
當前小程序所使用的全局樣式:
.icon-arrow:after{
content: "\2715";
}
.icon-love:after {
content: "\2740";
}
.icon-male:after {
content: "\2642";
}
.icon-female:after {
content: "\2640";
}
全局註冊小程序函數
小程序啓動之後,在 app.js 中執行App函數用來註冊一個小程序,onLaunch
回調會在小程序初始化完成時觸發,並且全局只觸發一次。
在根目錄下創建 app.js
App({
onLaunch() {
let self = this;
wx.getSystemInfo({
success: function (res) {
self.globalData.screenWidth = res.windowWidth;
self.globalData.screenHeight = res.windowHeight;
}
});
},
globalData: {
screenWidth: null,
screenHeight: null
}
});
代碼說明:
小程序在初始化完成後會調用微信獲取系統信息API(wx.getSystemInfo
) ,獲取窗口的寬高,並存放到globalData
屬性中,供其他page使用。
主頁面開發
文件列表:
pages/index/index.js 核心js業務邏輯
pages/index/index.wxml 模板文件
pages/index/index.wxss 樣式文件
pages/index/index.json (暫未用到)
創建視圖
創建 pages/index/index.wxml
文件,代碼如下:
<view class="container">
<view class="pic-info" style="width: {{ picSelfAdaptWidth }}vw; height: {{ picSelfAdaptHeight }}vh">
<image wx:if="{{ !testPicFile }}" class="pic-none" src="../../asset/icon/pic_bg.png"></image>
<image wx:else class="pic-inner" src="{{ testPicFile }}"></image>
</view>
<view wx:if="{{ testPicFile && !testPicResult }}" class="close" bindtap="handleCancelPic">
<i class="arrow">×</i>
</view>
<view class="pic-result" wx:if="{{ testPicResult }}">
<view class="score-box"><i class="icon-love"></i> 顏值 <span class="score">{{ testPicResult.beauty }}分</span>, 擊敗 {{ testPicResult.defeat}}% 用戶</view>
<view class="score-ext">
<span wx:if="{{ userInfo }}">用戶: {{userInfo.nickName}}</span>
<span>性別: <i class="icon-{{ testPicResult.gender }}"></i></span>
<span>年齡: {{ testPicResult.age }}</span>
</view>
</view>
<view>
<button wx:if="{{ !testPicFile }}" class="btn btn-select" bindtap="handleUploadPic">選擇照片/拍照</button>
<button wx:if="{{ testPicFile && !testPicResult }}" class="btn btn-compute" open-type="getUserInfo" bindgetuserinfo="handleGetUserInfo">計算顏值</button>
<button open-type="share" wx:if="{{ testPicResult }}" class="btn btn-share">邀請好友來玩</button>
<button wx:if="{{ testPicResult }}" class="btn btn-bottom" bindtap="handlePlayAgain">再試一次</button>
</view>
</view>
變量說明
picSelfAdaptWidth
爲圖片容器顯示寬度,默認爲 70vw
;
picSelfAdaptHeight
爲圖片容器顯示高度,根據圖片真實寬高和默認寬度計算得來,具體計算方法見 源代碼;
testPicFile
爲用戶選取的照片臨時地址;
testPicResult
爲照片識別結果集對象,所包含的屬性有 beauty:顏值(0-100)
, defeat: 擊敗用戶百分比
, gender: 性別
, age: 年齡
;
userInfo
爲用戶基本信息,包括 nickName: 用戶暱稱
;
事件說明
handleUploadPic
點擊選取照片時觸發的事件;
handleGetUserInfo
點擊計算顏值時觸發的事件;
handlePlayAgain
點擊再試一次時觸發的事件;
handleCancelPic
選取完照片後點擊右上角紅叉時觸發的事件;
創建樣式
創建 pages/index/index.wxss
文件,代碼如下:
page {
background-color: #ff8c00;
}
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
}
.pic-info {
margin-top: 6vh;
border: solid #fff;
border-width: 30rpx 30rpx 30rpx 30rpx;
box-shadow: 10rpx 10rpx 15rpx #333;
background: #fff;
display: flex;
align-items: center;
justify-content:center;
border-radius: 20rpx;
}
.btn {
background: #dd5900;
color: #fff;
border: 1px solid #fff;
}
.btn-select {
margin-top: 80rpx;
}
.btn-compute {
margin-top: 50rpx;
margin-bottom: 50rpx
}
.btn-share {
margin-top: 50rpx;
}
.btn-bottom {
margin-top: 30rpx;
margin-bottom: 50rpx;
}
.pic-none {
width: 90%;
height: 90%;
}
.pic-inner {
width: 100%;
height: 100%;
}
.pic-result {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50rpx;
color: #fff;
}
.pic-result .score-box{
font-size: 34rpx;
}
.pic-result .score {
font-size: 50rpx;
}
.pic-result .score-ext {
margin-top: 30rpx;
font-size: 28rpx;
}
.pic-result .score-ext span {
margin-right: 30rpx;
}
.pic-result .score-box {
background: #fff;
padding: 10rpx 20rpx;
border-radius: 20rpx;
color: #dd5900;
}
.close {
position: absolute;
top: 7vh;
right: 12vw;
}
.close .arrow {
display: flex;
align-items: center;
justify-content:center;
font-size: 38rpx;
width: 50rpx;
height: 50rpx;
border-radius: 25rpx;
background: #dd5900;
color: #fff;
}
創建視圖JS邏輯文件
創建 pages/index/index.js
文件,代碼如下:
const app = getApp()
const picDefaultWidth = 50;
const picDefaultHeight = 30;
const picTestFileDefaultWidth = 70;
Page({
onShareAppMessage(res) {
return {
title: '我的顏值擊敗了全國 94% 的用戶,不服來戰!',
path: '/pages/index/index',
imageUrl: '../../asset/img/prview.png'
}
},
data: {
picSelfAdaptWidth: picDefaultWidth,
picSelfAdaptHeight: picDefaultHeight,
testPicFile: '',
testPicResult: null,
userInfo: null
},
handleGetUserInfo(e) {
this.setData({
userInfo: e.detail.userInfo
});
this.handleComputePic();
},
handleCancelPic() {
this.setData({
testPicFile: '',
testPicResult: null,
picSelfAdaptHeight: picDefaultHeight,
picSelfAdaptWidth: picDefaultWidth
});
},
handleUploadPic() {
let self = this;
let ret = wx.chooseImage({
count: 1,
sizeType: "compressed",
success: function(res) {
self.setData({
testPicFile: res.tempFiles[0].path
});
self.getImageInfo(res.tempFiles[0].path, function(res) {
self.setPicAdaptHeight(res.width, res.height);
});
}
});
},
handlePlayAgain() {
this.setData({
testPicFile: '',
testPicResult: null,
picSelfAdaptHeight: picDefaultHeight,
picSelfAdaptWidth: picDefaultWidth
});
},
handleComputePic() {
let self = this;
wx.showLoading({
title: "顏值計算中",
mask: true
});
wx.uploadFile({
url: 'https://api-cn.faceplusplus.com/facepp/v3/detect', //僅爲示例,非真實的接口地址
filePath: self.data.testPicFile,
name: 'image_file',
formData: {
'api_key': 'DVc8JblEbcBjgq55TtDW0sheUhBeCaGe',
'api_secret': 'lMUVhSAg_ruN4PmwgNCk0IiWPNAF2_Sr',
'return_attributes': 'gender,age,beauty'
},
success: function (res) {
if (res.statusCode != 200) {
wx.showToast({
title: '服務器被擠爆了,請稍後再試',
icon: 'none',
duration: 2000
});
return false;
}
let data = JSON.parse(res.data);
console.log(data)
console.log(res)
if (!data.faces || data.faces.length == 0) {
wx.showToast({
title: '沒有識別到人臉,請更換照片重試',
icon: 'none',
duration: 2000
});
return false;
}
let human = [];
data.faces.forEach(item => {
let beauty = 50;
if (item.attributes.gender.value == 'Male') {
beauty = item.attributes.beauty.female_score;
} else {
beauty = item.attributes.beauty.male_score;
}
human.push(beauty);
});
let beautyIndex = human.indexOf(Math.max.apply(null, human));
let maxBeautyHuman = data.faces[beautyIndex];
let humanAttr = {
age: maxBeautyHuman.attributes.age.value,
gender: maxBeautyHuman.attributes.gender.value,
beauty: 50
};
if (humanAttr.gender == 'Male') {
humanAttr.beauty = maxBeautyHuman.attributes.beauty.female_score;
} else {
humanAttr.beauty = maxBeautyHuman.attributes.beauty.male_score;
}
humanAttr.gender = humanAttr.gender == 'Male' ? "male" : "female";
humanAttr.beauty = Math.ceil(humanAttr.beauty) + 15;
humanAttr.beauty = humanAttr.beauty > 97 ? 97 : humanAttr.beauty;
humanAttr.defeat = self.computeBeautyDefeatRatio(humanAttr.beauty);
self.setData({
testPicResult: humanAttr
});
wx.hideLoading();
},
fail: function() {
wx.showToast({
title: '網絡異常,請稍後再試',
icon: 'none',
duration: 2000
});
}
})
},
getImageInfo(imgSrc, scb, ecb) {
wx.getImageInfo({
src: imgSrc,
success: scb,
fail: ecb
});
},
setPicAdaptHeight(picWidth, picHeight) {
let h = (app.globalData.screenWidth * 0.7 / picWidth) * picHeight / app.globalData.screenHeight * 100;
this.setData({
picSelfAdaptHeight: h,
picSelfAdaptWidth: picTestFileDefaultWidth
});
},
computeBeautyDefeatRatio(beauty) {
return Math.ceil(Math.sqrt(beauty) * 10);
}
})
執行流程
啓動小程序
- App()函數執行並且
onLaunch
回調被觸發,獲取window的寬高,存入globalData
屬性中;
首頁渲染
爲
picSelfAdaptWidth
和picSelfAdaptHeight
分別賦默認值,顯示照片顯示區顯示默認圖片;此時
testPicFile
,testPicResult
均爲空,視圖將只顯示 “選擇照片/拍照” 按鈕;
點擊”選擇照片/拍照”按鈕
觸發
handleUploadPic
事件, 通過調用wx.chooseImage
來選擇本地圖片或者拍照,然後將選取的照片臨時路徑賦值給testPicFile
;然後調用自定義方法
getImageInfo
來獲取圖片的寬高等信息,再調用setPicAdaptHeight
傳入寬高來計算圖片自適應高的值picSelfAdaptHeight
;此時由於
testPicFile
非空,”選擇照片/拍照”按鈕將隱藏,”計算顏值”按鈕顯示;同時圖片預覽區右上角出現”紅叉”按鈕;
點擊”紅叉”按鈕
- 將會觸發
handleCancelPic
事件,會重置data對象中所有屬性值,回到最初始狀態;
點擊”計算顏值”按鈕
- 首先使用open-type(微信開放能力)開放的功能獲取用戶信息(從bindgetuserinfo綁定的回調函數中獲取用戶信息),此時會觸發
handleGetUserInfo
, 獲取用戶信息後會執行this.handleComputePic
顏值計算方法,
顏值計算方法核心邏輯
調起Loading,顯示
顏值計算中
;通過微信API
wx.uploadFile
向face++接口發送請求,查看源代碼;對face++API的返回值進行進一步處理:
- 顏值數據中會有同性顏值打分和異性顏值打分,我們取異性顏值打分數據;
- 返回數據中若有多組面部打分數據的話,我們取顏值最高一組;
- 爲原始顏值分
+15
分的 buff, 最高不超過97分; - 計算擊敗率,具體算法請見源碼;
邀請好友
- 使用
button
組件的open-type
功能來觸發用戶轉發; - 在 Page 中定義
onShareAppMessage
函數,設置該頁面的轉發信息 參見文檔
Page({
onShareAppMessage(res) {
return {
title: '我的顏值擊敗了全國 94% 的用戶,不服來戰!',
path: '/pages/index/index',
imageUrl: '../../asset/img/prview.png'
}
},
...
點擊”再試一次”按鈕
- 觸發
handlePlayAgain
事件,重置data中全部屬性值;
handlePlayAgain() {
this.setData({
testPicFile: '',
testPicResult: null,
picSelfAdaptHeight: picDefaultHeight,
picSelfAdaptWidth: picDefaultWidth
});
}
打賞頁面開發
打賞頁面比較簡單,不進行講解,可自行參考源碼
測試
在開發者工具中有 測試
按鈕,可點擊申請測試報告,如下:
報告每24小時可申請一次,內容如下:
發佈
上傳代碼
首先需要上傳小程序代碼,點擊 上傳
按鈕進行上傳
填寫版本號,項目備註後就開始上傳代碼
提交審覈
登錄微信公衆平臺,進入 開發管理
找到開發版本卡片,點擊 提交審覈
如實填寫審覈信息
等待審覈通過後會有微信通知,大概1個工作日我就收到審覈通過的通知了(贊一下微信的審覈速度),然後登陸公衆平臺,進入 開發管理
,你會看小程序的狀態是審覈通過待發布,點擊 發佈
即可。
可以打開微信在搜索框中輸入小程序名稱,如果能正常搜索到,說明此次發佈成功。
結尾
至此,小程序就順利誕生了,希望此文章對剛入坑小程序開發的夥伴們有所幫助,也歡迎大家加微信羣討論 獲取入羣二維碼
請作者喝杯咖啡