综述
前面我们介绍了微信小程序的简介与开发准备工作,本文我们主要介绍如何创建一个小程序以及一个小程序工程的基本结构(开发工具版本:1.05.2204250 | 1.06.2204250)。
创建小程序工程
- 打开微信开发者工具
- 点击左上角的项目->新建项目
-
选择代码存放的硬盘路径,填入刚刚申请到的小程序的AppID,给你的项目起一个名字,勾选 “不使用云服务”(注意:你要选择一个空的目录才可以创建项目),点击新建,你就得到了你的第一个小程序了。
小程序编译预览
微信小程序开发通过工具进行编译与预览非常方便,只需点击工具上的编译按钮,就可以在工具的左侧模拟器界面看到这个小程序的表现了,当然也可以点击预览按钮,通过微信的扫一扫在手机上体验你的第一个小程序。
小程序代码构成
通过上面创建的小程序工程,我们可以通过工具左侧的工程目录看到工程的目录结构
小程序包含一个描述整体程序的 app 和多个描述各自页面的page。一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下:
文件 | 必须 | 作用 |
---|---|---|
app.ts | 是 | 小程序逻辑 |
app.json | 是 | 小程序公共配置 |
app.wxss | 否 | 小程序公共样式表 |
一个小程序页面由四个文件组成,分别是:
文件类型 | 必须 | 作用 |
---|---|---|
ts | 是 | 页面逻辑 |
wxml | 是 | 页面结构 |
json | 否 | 页面配置 |
wxss | 否 | 页面样式表 |
注意:为了方便开发者减少配置项,描述页面的四个文件必须具有相同的路径与文件名。
小程序配置
全局配置
小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。完整配置项说明请参考小程序全局配置
以下是本例小程序配置选项的app.json :
{
"pages": [
"pages/index/index",
"pages/logs/logs"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "Weixin",
"navigationBarTextStyle": "black"
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}
主要字段含义:
- pages字段——用于描述当前小程序所有页面路径,这是为了让微信客户端知道当前你的小程序页面定义在哪个目录。
- window字段——定义小程序所有页面的顶部背景颜色,文字颜色定义等。
页面配置
每一个小程序页面也可以使用同名 .json 文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json的window中相同的配置项。
完整配置项说明请参考小程序页面配置
示例:
{
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "微信接口功能演示",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light"
}
sitemap配置
小程序根目录下的 sitemap.json 文件用来配置小程序及其页面是否允许被微信索引。
完整配置项说明请参考小程序sitemap配置
示例:
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}
项目配置project.config.json
- 项目根目录中的project.config.json和project.private.config.json文件可以对项目进行配置
- project.private.config.json中的相同设置优先级高于 project.config.json
- 可以在 project.config.json文件中配置公共的配置,在project.private.config.json配置个人的配置,可以将 project.private.config.json写到.gitignore避免版本管理的冲突
- project.private.config.json中有的字段,开发者工具内的设置修改会优先覆盖project.private.config.json 的内容。如在 project.private.config.json有appid字段,那么在 详情 - 基本信息中修改了appid,会写到 project.private.config.json中,不会覆盖掉project.config.json的appid字段的内容
- 开发阶段相关的设置修改优先同步到 project.private.config.json 中,与最终编译产物有关的设置无法在 project.private.config.json 中生效
其他配置项细节可以参考项目配置文件
示例:
{
"description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"packOptions": {
"ignore": [],
"include": []
},
"miniprogramRoot": "miniprogram/",
"compileType": "miniprogram",
"projectname": "ts-demo",
"setting": {
"useCompilerPlugins": [
"typescript"
],
"urlCheck": true,
"coverView": true,
"es6": true,
"postcss": true,
"lazyloadPlaceholderEnable": false,
"preloadBackgroundData": false,
"minified": true,
"autoAudits": false,
"uglifyFileName": false,
"uploadWithSourceMap": true,
"enhance": true,
"useMultiFrameRuntime": true,
"showShadowRootInWxmlPanel": true,
"packNpmManually": false,
"packNpmRelationList": [],
"minifyWXSS": true,
"useStaticServer": true,
"showES6CompileOption": false,
"checkInvalidKey": true,
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
},
"disableUseStrict": false,
"minifyWXML": true
},
"simulatorType": "wechat",
"simulatorPluginLibVersion": {},
"condition": {},
"srcMiniprogramRoot": "miniprogram/",
"appid": "********",
"libVersion": "2.24.3",
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
}
}
JSON语法
这里说一下小程序里JSON配置的一些注意事项。
JSON文件都是被包裹在一个大括号中 {},通过key-value的方式来表达数据。JSON的Key必须包裹在一个双引号中,在实践中,编写 JSON 的时候,忘了给 Key 值加双引号或者是把双引号写成单引号是常见错误。JSON的值只能是以下几种数据格式,其他任何格式都会触发报错,例如JavaScript中的undefined。
- 数字:包含浮点数和整数
- 字符串:需要包裹在双引号中
- Bool值:true 或者 false
- 数组:需要包裹在方括号中 []
- 对象:需要包裹在大括号中 {}
- Null
还需要注意的是 JSON 文件中无法使用注释,试图添加注释将会引发报错。
WXML模板
从事过网页编程的人知道,网页编程采用的是HTML + CSS + JS这样的组合,其中HTML是用来描述当前这个页面的结构,CSS用来描述页面的样子,JS通常是用来处理这个页面和用户的交互。同样道理,在小程序中也有同样的角色,其中 WXML 充当的就是类似 HTML 的角色。 打开pages/index/index.wxml ,会看到以下的内容:
<!--index.wxml-->
<view class="container">
<view class="userinfo">
<block wx:if="{{canIUseOpenData}}">
<view class="userinfo-avatar" bindtap="bindViewTap">
<open-data type="userAvatarUrl"></open-data>
</view>
<open-data type="userNickName"></open-data>
</block>
<block wx:elif="{{!hasUserInfo}}">
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
<button wx:elif="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
<view wx:else> 请使用1.4.4及以上版本基础库 </view>
</block>
<block wx:else>
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
和HTML 非常相似,WXML 由标签、属性等等构成。但是也有很多不一样的地方:
- 标签名字有点不一样
往往写HTML的时候,经常会用到的标签是div , p , span ,开发者在写一个页面的时候可以根据这些基础的标签组合出不一样的组件,例如日历、弹窗等等。换个思路,既然大家都需要这些组件,为什么我们不能把这些常用的组件包装起来,大大提高我们的开发效率。从上边的例子可以看到, 小程序的WXML 用的标签是 view , button , text 等等, 这些标签就是小程序给开发者包装好的基本能力, 我们还提供了地图、 视频、 音频等等组件能力。更多详细的组件讲述参考下个章节 小程序的能力 - 多了一些 wx:if 这样的属性以及 {{ }} 这样的表达式
在网页的一般开发流程中,我们通常会通过JS操作 DOM (对应HTML的描述产生的树), 以引起界面的一些变化响应用户的行为。例如,用户点击某个按钮的时候,JS会记录一些状态到 JS 变量里边,同时通过 DOM API 操控 DOM 的属性或者行为, 进而引起界面一些变化。 当项目越来越大的时候, 你的代码会充斥着非常多的界面交互逻辑和程序的各种状态变量,显然这不是一个很好的开发模式, 因此就有了MVVM 的开发模式(例如 React, Vue),提倡把渲染和逻辑分离。简单来说就是不要再让 JS 直接操控DOM ,JS只需要管理状态即可,然后再通过一种模板语法来描述状态和界面结构的关系即可。小程序的框架也是用到了这个思路,如果你需要把一个Hello World的字符串显示在界面上。
WXML 是这么写 :
<text>{{msg}}</text>
TS只需要管理状态即可:
this.setData({ msg: "Hello World" })
通过 {{ }} 的语法把一个变量绑定到界面上,我们称为数据绑定。仅仅通过数据绑定还不够完整的描述状态和界面的关系,还需要 if / else , for 等控制能力,在小程序里边,这些控制能力都用 wx: 开头的属性来表达。更详细的文档可以参考WXML
WXSS样式
WXSS具有CSS大部分的特性,小程序在WXSS也做了一些扩充和修改。
- 新增了尺寸单位。在写 CSS 样式时,开发者需要考虑到手机设备的屏幕会有不同的宽度和设备像素比,采用一些技巧来换算一些像素单位。 WXSS 在底层支持新的尺寸单位 rpx ,开发者可以免去换算的烦恼,只要交给小程序底层来换算即可,由于换算采用的浮点数运算,所以运算结果会和预期结果有一点点偏差
- 提供了全局的样式和局部样式。 和前边 app.json , page.json 的概念相同, 你可以写一个 app.wxss
作为全局样式, 会作用于当前小程序的所有页面, 局部页面样式 page.wxss 仅对当前页面生效。 - 此外 WXSS 仅支持部分 CSS 选择器
更详细的文档可以参考WXSS
TS逻辑交互
一个服务仅仅只有界面展示是不够的,还需要和用户做交互:响应用户的点击、获取用户的位置等等。 在小程序里边,我们就通过编写TS脚本文件来处理用户的操作。
<view>{{ msg }}</view>
<button bindtap="clickMe">点击我</button>
点击button按钮的时候,我们希望把界面上msg显示成 "Hello World" ,于是我们在 button 上声明一个属性: bindtap,在 TS 文件里边声明了clickMe方法来响应这次点击操作:
Page({
clickMe: function() {
this.setData({ msg: "Hello World" })
}
})
响应用户的操作就是这么简单, 更详细的事件可以参考文档 WXML-事件。
此外你还可以在TS中调用小程序提供的丰富的 API,利用这些 API 可以很方便的调起微信提供的能力,例如获取用户信息、本地存储、微信支付等。在前边创建的例子中,在pages/index/index.ts 就调用了wx.getUserInfo获取微信用户的头像和昵称,最后通过setData把获取到的信息显示到界面上。更多 API可以参考文档 小程序的API 。
至此我们对小程序的开发流程和代码结构有了一个较为系统的了解,后面便可以根据业务需要进行实际的开发工作了。