前几天学习了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.jsconst 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;}我的第一个小程序展示














