前幾天學習了react這個開發框架,瞭解了JS語言的基本知識。想到最近3年小程序如火如荼的發展,進而決定入坑學習。
微信小程序簡介
微信小程序是以微信爲運行環境的一種應用,其實質是 Hybrid 技術的應用,Hybrid App 即混合模式移動應用,因此與 H5 類似,但又比 H5 擁有很多原生的能力,例如調用位置信息和攝像頭等。小程序的開發方式與 H5 十分相似,用的也是 JavaScript
、HTML
、CSS
語言。
微信小程序開發入門
1. 申請小程序賬號
申請小程序賬號需要一個未申請過公衆號和小程序賬號的郵箱,然後在小程序介紹頁的底部點擊 「前往註冊」 按鈕,前往註冊頁根據指引填寫信息。
填完信息,點擊「註冊」會提示去註冊的郵箱激活賬號,去郵箱激活即可。
2. 安裝開發者工具
微信開發者工具可以幫助開發者簡單和高效地開發和調試微信小程序,集成了公衆號網頁調試和小程序調試兩種開發模式。它可以實時查看頁面和功能效果,還能在開發者工具中進行 Debug。它使用 NW.js (previously known as node-webkit) 編寫,在調試時和 Chrome 幾乎無差別,很容易上手。
前往開發者工具下載頁面 ,根據自己的操作系統下載對應的安裝包進行安裝。
打開微信開發者工具,用微信掃碼登錄開發者工具,確認後會進入選擇「小程序項目」或「公衆號網友項目」的界面,這裏我們選擇「小程序項目」,出現如下界面:
點擊新建,出現一個示例項目的預覽,點擊頂部菜單「編譯」就可以在微信開發者工具中預覽你的第一個小程序。
3. 代碼構成
我們生成的項目的目錄如下:
├── pages 頁面目錄
| ├── index 首頁
| | ├── index.js 首頁js
| | ├── index.wxss 首頁樣式文件
| | └── index.wxml 首頁模板文件
├── utils 工具函數
| ├── utils.js
├── app.js app入口文件
├── app.json app配置文件
├── app.wxss app樣式文件
└── project.config.json 項目配置文件
如上面的目錄,一個小程序必須要有一個 app.js
入口文件,app.json
配置文件。除此之外,還有一個叫 project.config.json
的工具配置文件,是方便你在不同的電腦上開發時,開發者工具能擁有相同的設置。
每個頁面上,同樣會有 page.json
、page.js
、 page.wxml
、 page.wxss
這四種文件。分別是頁面配置,頁面邏輯,頁面模板和頁面樣式文件。除去頁面配置文件 page.json
, 後三者和我們 HTML 、 JavaScript 、 CSS 三劍客十分相像,只不過換了個後綴而已。
WXML 模板文件裏面,提供了數據綁定、列表渲染、條件渲染、模板、事件、引用等功能。
WXSS 樣式文件和 CSS 別無大異,能支持絕大多數的 CSS 、 CSS3 的語法。除此之外,還支持樣式引入,單位轉換的功能,小程序在 WXSS 上做了一些擴充和修改,新增了 rpx
尺寸單位,不需要再人工地使用類似rem
的適配方案來適配移動端的各種機型,給開發者提供了便利。
4. 代碼分析
1. app.json
這個文件是當前小程序的全局配置,包括了小程序的所有頁面路徑、界面表現、網絡超時時間、底部 Tab 等。
{
"pages": [
"pages/index/index",
"pages/userConsole/userConsole",
"pages/storageConsole/storageConsole",
"pages/databaseGuide/databaseGuide",
"pages/addFunction/addFunction",
"pages/deployFunctions/deployFunctions",
"pages/chooseLib/chooseLib",
"pages/openapi/openapi",
"pages/openapi/serverapi/serverapi",
"pages/openapi/callback/callback",
"pages/openapi/cloudid/cloudid",
"pages/im/im",
"pages/im/room/room"
],
"window": {
"backgroundColor": "#F6F6F6",
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#F6F6F6",
"navigationBarTitleText": "雲開發 QuickStart",
"navigationBarTextStyle": "black"
},
"sitemapLocation": "sitemap.json",
"style": "v2"
}
所有的頁面都需要在app.json
的pages
裏面增加入口,這樣才能讓頁面被加載
2. index.js
//index.js
const app = getApp()
Page({
data: {
avatarUrl: './user-unlogin.png',
userInfo: {},
logged: false,
takeSession: false,
requestResult: ''
},
onLoad: function() {
if (!wx.cloud) {
wx.redirectTo({
url: '../chooseLib/chooseLib',
})
return
}
// 獲取用戶信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已經授權,可以直接調用 getUserInfo 獲取頭像暱稱,不會彈框
wx.getUserInfo({
success: res => {
this.setData({
avatarUrl: res.userInfo.avatarUrl,
userInfo: res.userInfo
})
}
})
}
}
})
},
onGetUserInfo: function(e) {
if (!this.data.logged && e.detail.userInfo) {
this.setData({
logged: true,
avatarUrl: e.detail.userInfo.avatarUrl,
userInfo: e.detail.userInfo
})
}
},
onGetOpenid: function() {
// 調用雲函數
wx.cloud.callFunction({
name: 'login',
data: {},
success: res => {
console.log('[雲函數] [login] user openid: ', res.result.openid)
app.globalData.openid = res.result.openid
wx.navigateTo({
url: '../userConsole/userConsole',
})
},
fail: err => {
console.error('[雲函數] [login] 調用失敗', err)
wx.navigateTo({
url: '../deployFunctions/deployFunctions',
})
}
})
},
// 上傳圖片
doUpload: function () {
// 選擇圖片
wx.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: function (res) {
wx.showLoading({
title: '上傳中',
})
const filePath = res.tempFilePaths[0]
// 上傳圖片
const cloudPath = 'my-image' + filePath.match(/\.[^.]+?$/)[0]
wx.cloud.uploadFile({
cloudPath,
filePath,
success: res => {
console.log('[上傳文件] 成功:', res)
app.globalData.fileID = res.fileID
app.globalData.cloudPath = cloudPath
app.globalData.imagePath = filePath
wx.navigateTo({
url: '../storageConsole/storageConsole'
})
},
fail: e => {
console.error('[上傳文件] 失敗:', e)
wx.showToast({
icon: 'none',
title: '上傳失敗',
})
},
complete: () => {
wx.hideLoading()
}
})
},
fail: e => {
console.error(e)
}
})
},
})
可以見到,頁面中有一個 Page
包裹着一個對象,頁面的 data
、一些生命週期、一些方法,都掛載在該對象上。而小程序正是通過這樣的方式進行初始化的。 也就是說,當我們初始化的時候,要將初始狀態寫在這個文件中。
3. index.wxml
<!--index.wxml-->
<view class="container">
<!-- 用戶 openid -->
<view class="userinfo">
<button
open-type="getUserInfo"
bindgetuserinfo="onGetUserInfo"
class="userinfo-avatar"
style="background-image: url({{avatarUrl}})"
size="default"
></button>
<view class="userinfo-nickname-wrapper">
<button class="userinfo-nickname" bindtap="onGetOpenid">點擊獲取 openid</button>
</view>
</view>
<!-- 上傳圖片 -->
<view class="uploader">
<view class="uploader-text" bindtap="doUpload">
<text>上傳圖片</text>
</view>
<view class="uploader-container" wx:if="{{imgUrl}}">
<image class="uploader-image" src="{{imgUrl}}" mode="aspectFit" bindtap="previewImg"></image>
</view>
</view>
<!-- 操作數據庫 -->
<view class="uploader">
<navigator url="../databaseGuide/databaseGuide" open-type="navigate" class="uploader-text">
<text>前端操作數據庫</text>
</navigator>
</view>
<!-- 即時通信 -->
<view class="uploader">
<navigator url="../im/im" open-type="navigate" class="uploader-text">
<text>即時通信 Demo</text>
</navigator>
</view>
<!-- 新建雲函數 -->
<view class="uploader">
<navigator url="../addFunction/addFunction" open-type="navigate" class="uploader-text">
<text>快速新建雲函數</text>
</navigator>
</view>
<!-- 雲調用 -->
<view class="uploader">
<navigator url="../openapi/openapi" open-type="navigate" class="uploader-text">
<text>雲調用</text>
</navigator>
</view>
</view>
作爲一名移動端開發出生的工程師,這個就很熟悉了,本質就是頁面的佈局渲染。WXML 模板中,渲染了一些在 index.js
裏定義的頁面變量,綁定了多個事件。
4. index.wxss
這個是微信獨有的一個文件,個人理解爲style,規定一些空間的大小,顏色,風格等標準。值得一提的是微信小程序封裝了一個新單位rpx!改單位可以適配自動適配多個機型,作爲移動端開發出身的我,曾經被適配機型整的無語,給滿分!
/**index.wxss**/
page {
background: #f6f6f6;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.userinfo, .uploader, .tunnel {
margin-top: 40rpx;
height: 140rpx;
width: 100%;
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.1);
border-left: none;
border-right: none;
display: flex;
flex-direction: row;
align-items: center;
transition: all 300ms ease;
}
.userinfo {
padding-left: 120rpx;
}
.userinfo-avatar {
width: 100rpx;
height: 100rpx;
margin: 20rpx;
border-radius: 50%;
background-size: cover;
background-color: white;
}
.userinfo-avatar[size] {
width: 100rpx;
}
.userinfo-avatar:after {
border: none;
}
.userinfo-nickname {
font-size: 32rpx;
color: #007aff;
background-color: white;
background-size: cover;
text-align: left;
padding-left: 0;
margin-left: 10px;
}
.userinfo-nickname::after {
border: none;
}
.userinfo-nickname-wrapper {
flex: 1;
}
.uploader, .tunnel {
height: auto;
padding: 0 0 0 40rpx;
flex-direction: column;
align-items: flex-start;
box-sizing: border-box;
}
.uploader-text, .tunnel-text {
width: 100%;
line-height: 52px;
font-size: 34rpx;
color: #007aff;
}
.uploader-container {
width: 100%;
height: 400rpx;
padding: 20rpx 20rpx 20rpx 0;
display: flex;
align-content: center;
justify-content: center;
box-sizing: border-box;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.uploader-image {
width: 100%;
height: 360rpx;
}
.tunnel {
padding: 0 0 0 40rpx;
}
.tunnel-text {
position: relative;
color: #222;
display: flex;
flex-direction: row;
align-content: center;
justify-content: space-between;
box-sizing: border-box;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.tunnel-text:first-child {
border-top: none;
}
.tunnel-switch {
position: absolute;
right: 20rpx;
top: -2rpx;
}
.disable {
color: #888;
}
.service {
position: fixed;
right: 40rpx;
bottom: 40rpx;
width: 140rpx;
height: 140rpx;
border-radius: 50%;
background: linear-gradient(#007aff, #0063ce);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
display: flex;
align-content: center;
justify-content: center;
transition: all 300ms ease;
}
.service-button {
position: absolute;
top: 40rpx;
}
.service:active {
box-shadow: none;
}
.request-text {
padding: 20rpx 0;
font-size: 24rpx;
line-height: 36rpx;
word-break: break-all;
}
我的第一個小程序展示