前言
哈喽大家好,我是 SuperYing,我们继续小程序入门系列,本文将对小程序框架语法进行比较全面的介绍。在《小程序从入门到入坑》简介及工程创建中,我们提到小程序项目结构,主要包括 app.json,app.js,app.wxss 以及页面(组件)级的 .wxml,.wxss,.js,.json。接下来我将逐步介绍以上重点组成部分。
读完本文您将收获:
- 了解小程序项目主体文件,明确
app.json,app.js,app.wxss等全局文件的作用及使用方式。- 了解小程序页面结构
WXML语法,完成诸如 数据绑定、列表渲染、条件渲染 等常用开发方式。- 了解小程序样式
WXSS的使用以及基于css语法的扩展方面。- 了解小程序脚本
WXS的使用及典型应用场景。- 了解小程序常用开发技巧,基本可以独立完成小程序页面开发。
主体文件介绍
主体文件包括 app.json,app.js,app.wxss。
app.json
app.json 位于小程序工程的根目录下,负责对微信小程序进行全局配置。文件内容是一个 JSON 对象,编写时需要严格按照 JSON 格式规范。
app.json 的常用配置项主要分为以下几类:
- pages: 设置页面路径,必填项。
- window: 设置小程序外观。
- tabBar: 设置
tabBar表现及对应页面。 - networkTimeout: 设置网络请求的超时时间。
- debug: 设置是否开启
debug模式,默认关闭。
app.json 整体结构如下:
{ // 页面路径设置 "pages" : [], // 默认页面的窗口设置 "window" : {}, // 底部tab设置 "tabBar" : {}, // 设置网络请求API的超时时间 "networkTimeout" : {}, // 是否为debug模式 "debug" : false
}
pages 配置
用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。文件名不需要写文件后缀,框架会自动去寻找对应位置的 .json, .js, .wxml, .wxss 四个文件进行处理。
未指定 entryPagePath 配置时,数组的第一项代表小程序的初始页面,即首页。
配置示例:
"pages": ["pages/index/index","pages/logs/logs"
],
pages/index/index 即为小程序首页。
tip
使用微信开发者工具 增加
pages配置,会自动在小程序根目录(默认 miniprogram)的pages目录下创建对应页面文件,包括.wxml,.wxss,.js,.json。
小程序每次需要增加/删除页面时,都需要修改 pages 配置。另外,小程序路由也是基于 pages 配置的路径进行导航的,可以说 pages 是小程序不可或缺的重要配置。
window 配置
window 配置用于设置小程序的状态栏、导航条、标题、窗口背景色 等外观表现。
详细配置可参考小程序开发文档
配置示例:
{
"window": {// 导航栏标题、状态栏颜色,仅支持 `black` / `white`"navigationBarTextStyle": "black",// 导航栏背景颜色"navigationBarBackgroundColor": "#ffffff",// 导航栏标题文字内容"navigationBarTitleText": "miniprogram-study",// 窗口的背景色"backgroundColor": "#eeeeee",// 下拉 loading 的样式,仅支持 `dark` / `light`"backgroundTextStyle": "light"},
}
以下是 window 配置对应的小程序页面部分,小伙伴们可参考以验证配置是否正确。

注意
关于颜色的配置,应使用 十六进制 形式,如 #ffffff。
tabBar 配置
什么是 tabBar
tabBar 是移动端应用比较常见的页面效果,用于实现页面的快速切换。
在小程序中 tabBar 主要分为:
- 顶部
tabBar - 底部
tabBar
配置项
如果小程序是一个多 tab 应用,即客户端窗口的底部或顶部有 tab 栏可以切换页面,可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。
tabBar 常用配置项如下:
list配置tab列表,限制最少 2 个,最多 5 个tab。tab每个项目可配置以下内容:pagePath: 必填,页面路径,必须在pages配置中先定义。text: 必填,tab上按钮文字。iconPath:tab默认图标路径,icon大小限制为40kb,建议尺寸为 81px * 81px,不支持网络图片。当position为top时,不显示icon。selectedIconPath:tab选中时的图标路径,icon大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当position为top时,不显示icon。
color和selectedColor分别设置tab上的默认文字颜色及选中时的文字颜色。backgroundColor设置tab的背景色。borderStyle设置tab的边框的颜色, 仅支持black/white。position设置tab的tabBar 的位置,仅支持bottom/top。
配置示例:
{
"tabBar": {"list": [{"pagePath": "pages/index/index","text": "首页","iconPath": "images/tabs/home.png","selectedIconPath": "images/tabs/home-active.png"},{"pagePath": "pages/mine/mine","text": "我的","iconPath": "images/tabs/mine.png","selectedIconPath": "images/tabs/mine-active.png"}]},
}
tabBar 部分标注:

注意:
tabBar的数量应控制在 2 ~ 5 个之间。当渲染顶部 tabBar 时,不会渲染
icon,仅渲染文字。
networkTimeout 配置
小程序中各种网络请求 API 的超时时间只能通过 networkTimeout 统一设置,单位 毫秒(ms)。
配置项如下:
request:wx.request 的超时时间,默认60000ms。connectSocket:wx.connectSocket 的超时时间,默认60000ms。uploadFile:wx.uploadFile 的超时时间,默认60000ms。downloadFile:wx.downloadFile 的超时时间,默认60000ms。
配置示例:
{"networkTimeout": {"request": 60000,"connectSocket": 60000,"uploadFile": 60000,"downloadFile": 60000},
}
debug 配置
此配置可以在开发者工具中开启 debug 模式,默认 关闭。开启后,在开发者工具的控制台面板,调试信息以 info 的形式给出,包括 Page 的注册,页面路由,数据更新,事件触发 等。可以帮助开发者快速定位一些常见的问题。
配置示例:
{"debug": true
}
控制台开启 debug 后打印信息:

app.js
该文件是小程序应用的入口文件,在该文件中调用 App() 函数来 注册小程序实例,内容包括 全局生命周期函数,全局函数,全局属性 等。已注册的小程序实例可以在其他逻辑层代码中通过 getApp()获取。
示例:
App({globalData: '我是全局属性',onLaunch() {// 小程序初始化完成时触发,全局只触发一次},onShow() {// 小程序启动或从后台进入前台显示时触发},onHide() {// 小程序从前台进入后台时触发},onError(e) {// 小程序发生脚本错误或 API 调用报错时触发},onPageNotFound() {// 小程序要打开的页面不存在时触发},onUnhandledRejection() {// 小程序有未处理的 Promise 拒绝时触发},onThemeChange() {// 系统切换主题时触发}
})
app.wxss(可选)
该文件是 全局样式表,对项目中每个页面都有效,可将一些系统级别的统一样式风格写入 app.wxss。页面渲染时,页面(组件)级的 .wxss 文件样式会覆盖 app.wxss 中相同的选择器样式。关于 WXSS 使用,详见后文 「小程序样式 - WXSS」。
页面文件介绍
配置文件 - .json
页面配置文件与 app.json 配置文件一样,也是一个 json 文件。
app.json 中的部分配置,也支持在页面(组件)级的 .json 文件进行配置。.json 文件配置项在当前页面会覆盖 app.json 中相同的配置项。
.json 配置文件的配置项设计 window 部分的,即设置小程序的外观表现时,不需要在 .json 中显示声明 window 属性,直接设置指定配置即可。
配置示例:
{ "navigationBarBackgroundColor": "#000000", "navigationBarTextStyle": "black", "navigationBarTitleText": "我的页面", "backgroundColor": "#efefef", "backgroundTextStyle": "light"
}
注意:
页面(组件)级的
.json文件非必需,若页面相关配置与app.json完全形同,可省略该配置文件。
逻辑文件 - .js
小程序的每个页面都需要在对应的 .js 中进行注册。逻辑文件的主要功能包括:注册小程序页面,定义初始化数据,注册页面声明周期函数,注册事件处理函数 等。
小程序的逻辑文件使用 javascript 进行开发。所有的逻辑文件,包括 app.js 最终将会打包成一份 JavaScript 文件。在小程序启动时运行,直到小程序销毁,类似于 ServiceWorker,所以逻辑层也称为 App Service。
小程序中的每个逻辑文件,都有独立的作用域,具备模块化能力。由于小程序的逻辑层运行在 纯 javascript 引擎 中,而并非是浏览器环境,因此即便同样使用 javascript 编写,但在小程序中无法使用浏览器对象,如 document,window 等。同样的,基于浏览器特有对象的框架也无法使用,如 JQuery 等。因为无法通过操作 DOM 操作页面,小程序中需要通过 数据绑定 和 事件响应 来处理页面。
注册页面
.js 逻辑文件中需要调用 Page() 函数来注册页面,接受一个 Object 类型参数,指定页面的初始数据、生命周期回调、事件处理函数等。
示例代码(属性特性见对应注释):
Page({/*** 页面的初始数据* 页面加载时,`data` 将会以 `JSON` 字符串的形式由逻辑层传至渲染层,因此 `data` 中的数据必须是可以转成 `JSON` 的类型:字符串,数字,布尔值,对象,数组。* 渲染层可以通过 `WXML` 对数据进行绑定*/data: {},/*** 生命周期函数--监听页面加载* 一个页面只会调用一次,可以在 `onLoad` 的参数中获取打开当前页面路径中的参数*/onLoad() {},/*** 生命周期函数--页面初次渲染完成时触发。* 一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。 */onReady() {},/*** 生命周期函数--页面显示/切入前台时触发*/onShow() {},/*** 生命周期函数--页面隐藏/切入后台时触发,如 `wx.navigateTo` 或底部 `tab` 切换到其他页面,小程序切入后台等*/onHide() {},/*** 生命周期函数--页面卸载时触发,如 `wx.redirectTo` 或 `wx.navigateBack` 到其他页面时*/onUnload() {},/*** 页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh() {},/*** 页面上拉触底事件的处理函数*/onReachBottom() {},/*** 用户点击右上角分享*/onShareAppMessage() {},/*** 自定义事件响应*/handleButtonTap() {},/*** 自定义数据* 逻辑中可通过 this.customData 获取以下自定义数据*/customData() {hi: '我是自定义数据'},
})
获取当前页面栈
可在逻辑代码中调用 getCurrentPages() 获取当前页面栈的实例,页面栈以数组形式按栈顺序给出,数组第一个元素为 首页,最后一个元素为 当前页面。
注意:
- 不要尝试修改页面栈,会导致路由以及页面状态错误。
- 不要在
App.onLaunch的时候调用getCurrentPages(),此时page还没有生成。
触发页面渲染
在逻辑代码中,可以调用 this.setData() 函数触发页面渲染,不能直接修改 data 数据。因为 this.setData() 被调用时,会将数据从逻辑层发送到视图层触发视图层重绘,同时会修改 Page 的 data 值。
setData 函数接受一个对象参数,用于更新 data 中的指定数据。参数属性的键值非常灵活,以下情况均可生效:
data键索引:更新键对应的值。- 数组下标路径索引:更新数组指定下标对应的值。
- 对象属性路径索引:更新对象指定属性对应值。
- 动态路径索引:按结果路径更新对应的值。
代码示例:
Page({/*** 页面的初始数据*/data: {text: '123',userInfo: {name: 'SuperYing',age: '18'},hobbies: ['games', 'football', 'busketball'],},handleTextChange() {/** data 键值索引,更新 this.data.text 数据 */this.setData({text: '234'})},handleArrayChange() {/** 数组下标路径索引,更新 this.data.hobbies 第一个元素为 'run' */this.setData({'hobbies[0]': 'run'})},handleObjectChange() {/** 普通对象路径索引,更新 this.data.useInfo.name 为 'new name' */this.setData({'userInfo.name': 'new name',})},handleObjectChange2() {/** 动态路径索引,更新 this.data.useInfo.name 为 'new name' */const prop = 'name'this.setData({[`userInfo.${prop}`]: 'new name',})}
})
结构文件 - .wxml
WXML(WeiXin Markup Language) 是框架设计的一套标签语言,用于渲染界面。
小程序框架通过 WXML,在不同平台被渲染为不同端的渲染文件。
如上图,WXML 语言最终会转译为宿主环境对应的语言,所以 WXML 中使用的标签一定要使用小程序定义的标签,不能使用自定义标签,以保证页面结构能被正确的转译。
使用微信开发者工具开发时,在 WXML 中编写 HTML 标签或自定义标签,也可以正常渲染。这是因为微信开发者工具内核是浏览器内核,而且微信开发者工具并没有对 WXML 和 WXSS 的内容进行强验证。但是无法保证在真机上可以正常渲染。因此,微信开发者工具的效果仅用于方便开发调试,而真正的效果一定要以真机效果为准。
WXML 可以实现 数据绑定、列表渲染、条件渲染、模板、事件等能力。
数据绑定
WXML 文件可以绑定对应 Page 中定义的 data 数据,以在页面中直接使用 data 中的属性。
数据绑定使用 Mustache 语法(双大括号)将变量或简单运算包裹起来。主要有以下几种用法:
简单绑定
简单绑定就是使用 Mustache 语法 将变量包裹起来。
代码示例:
<!--index.wxml-->
<view><!-- 作为内容绑定 --><view>{{message}}</view><!-- 作为属性绑定 --><view id='item-{{id}}' style="border: {{border}}">我是属性绑定</view><!-- 作为控制属性绑定 --><view wx:if="{{show}}">我是控制属性绑定</view><!-- 关键字绑定 --><checkbox checked="{{false}}">关键字绑定</checkbox>
</view>
index.js
Page({data: {message: 'hello world',id: '0',border: '2rpx solid black',show: true}
})
效果如下:

注意:
若关键字为布尔值时,如
checkbox的checked属性,不能直接设置为checked="false",这样会将checked的值解析为一个 ‘false’ 字符串,转成布尔值时为 true。这种情况,需要将false用{{}}包裹起来。
运算
可以在 {{}} 内进行简单的运算,支持以下运算:
- 三元运算
- 算数运算
- 逻辑判断
- 字符串运算
- 数据路径运算
代码示例:
<!--index.wxml-->
<view><!--三元运算--><checkbox checked="{{checked === 'Y'? true : false}}">三元运算</checkbox><!-- 算数运算 --><view>{{ a + b}} + {{c}} + d</view><!-- 逻辑判断 --><view wx:if="{{length > 5}}"> </view><!-- 字符串运算 --><view>{{"hello" + name}}</view><!-- 数据路径运算 --><view>{{object.key}} {{array[0]}}</view>
</view>
// pages/index/index.js
Page({data: {checked: 'Y',a: 1,b: 2,c: 3,length: 1,name: 'world',object: {key: 'hello'},array: ['小程序从入门到入坑']}
})
效果如下:

组合
data 中的数据可以在 {{}} 中再次组合,构成新的数组或对象。
代码示例:
// index.wxml
<text wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </text><button data-obj="{{ { ...obj1, c: 3 } }}" bind:tap="onButton1Tap">按钮1</button><button data-obj="{{ { ...obj1, ...obj2 } }}" bind:tap="onButton2Tap">按钮2</button><button data-obj="{{ {field1, field2} }}" bind:tap="onButton3Tap">按钮3</button>
// index.js
Page({data: {zero: 0,obj1: {a: 1,b: 2},obj2: {c: 3,d: 4},field1: 'abc',field2: 'def'},onButton1Tap(e) {console.log('按钮1', e.currentTarget.dataset.obj)},onButton2Tap(e) {console.log('按钮2', e.currentTarget.dataset.obj)},onButton3Tap(e) {console.log('按钮3', e.currentTarget.dataset.obj)}
})
效果及控制台打印如下: 
列表渲染
wx:for
在组建上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item。
代码示例:
<view wx:for="{{myArray}}">{{index}}-{{item}}
</view>
Page({data: {myArray: ['hello', 'world']}
})
以上代码遍历 myArray,重复渲染了两个 view。
效果如下:

wx:for-index wx:for-item
wx:for-item 可以指定数组当前元素的变量名(默认 item)。
wx:for-index 可以指定数组当前下标的变量名(默认 index)。
代码示例:
<view wx:for="{{myArray}}" wx:for-index="myIndex" wx:for-item="myItem">{{myIndex}}-{{myItem}}
</view>
Page({data: {myArray: ['hello', 'world']}
})
效果与 wx:for 示例一致。
单列表渲染时一般不需要手动设置 wx:for-index 和 wx:for-item,当wx:for嵌套使用时,就有必要设置,以避免命名冲突。
嵌套列表代码示例:
<view wx:for="{{nestedArray}}" wx:for-index="myIndex" wx:for-item="myItem"><view wx:for="{{myItem}}">{{index}}-{{item}}</view>
</view>
Page({data: {nestedArray: [['hello', 'world'],['hello', '小程序']]}
})
结果如下:

wx:key
若列表中项目存在位置动态改变或者新增的情况,且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),则需要使用 wx:key 来指定列表中项目的唯一的标识符。
熟悉 vue 的同学,应该比较了解 v-for 的 key 属性。小程序的 wx:key 与 v-for 的 key 作用差不多,目的在于提升列表渲染性能。
wx:key 的值可设为以下两种: 1. 字符串,应为 wx:for 循环的数组项目的某个属性,该属性的值需要是数组中唯一的 字符串 或 数字,且不能动态改变。 2. 保留关键字 *this 代表在 wx:for 循环的数组项目本身,需要数组项目本身是一个唯一的 字符串 或者 数字。
当数据改变触发渲染层重新渲染的时候,会校正带有 wx:key 的组件,框架会确保他们被重新排序,而不是重新创建,以使组件保持自身的状态,并且提高列表渲染时的效率。
注:
如不提供
wx:key,会报一个warning,如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略
代码示例:
<!-- item 属性 -->
<switch wx:for="{{objectArray}}" wx:key="unique" style="display: block;"> {{item.id}}
</switch>
<button bindtap="switch">Switch</button>
<button bindtap="addToFront">添加</button>
<!-- *this -->
<switch wx:for="{{numberArray}}" wx:key="*this" style="display: block;"> {{item}}
</switch>
<button bindtap="addNumberToFront">添加</button>
Page({data: {objectArray: [{id: 5, unique: 'unique_5'},{id: 4, unique: 'unique_4'},{id: 3, unique: 'unique_3'},{id: 2, unique: 'unique_2'},{id: 1, unique: 'unique_1'},{id: 0, unique: 'unique_0'},],numberArray: [1, 2, 3, 4]},switch: function(e) {const length = this.data.objectArray.lengthfor (let i = 0; i < length; ++i) {const x = Math.floor(Math.random() * length)const y = Math.floor(Math.random() * length)const temp = this.data.objectArray[x]this.data.objectArray[x] = this.data.objectArray[y]this.data.objectArray[y] = temp}this.setData({objectArray: this.data.objectArray})},addToFront: function(e) {const length = this.data.objectArray.lengththis.data.objectArray = [{id: length, unique: 'unique_' + length}].concat(this.data.objectArray)this.setData({objectArray: this.data.objectArray})},addNumberToFront: function(e){this.data.numberArray = [ this.data.numberArray.length + 1 ].concat(this.data.numberArray)this.setData({numberArray: this.data.numberArray})}
})
体验以上代码后可以发现,无论是更新列表顺序,还是新增列表项目,绑定了 wx:key 的 switch 组件的状态都不会刷新,即没有重新创建 switch 组件,而仅仅调整组件的位置。
wx:for block
wx:for 可以应用于 <block> 标签上,用于渲染包含多个节点的结构块。
<block/>并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
代码示例:
<block wx:for="{{myArray}}"><view> {{index}}: </view><view> {{item}} </view>
</block>
Page({data: {myArray: ['hello', 'world']}
})
效果如下: 
注意事项
- 当
wx:for的值为字符串时,会将字符串解析成字符串数组
<view wx:for="array">{{item}}
</view>
等同于
<view wx:for="{{['a','r','r','a','y']}}">{{item}}
</view>
- 花括号和引号之间如果有空格,将最终被解析成为字符串
<view wx:for="{{[1,2,3]}} ">{{item}}
</view>
等同于
<view wx:for="{{[1,2,3] + ' '}}" >{{item}}
</view>
条件渲染
wx:if
在页面结构中,经常需要使用逻辑分支,这时候可以使用 wx:if="{{判断条件}}" 来进行条件渲染,当条件成立时渲染该代码块。
同时提供了 wx:elif 和 wx:else 来添加一个 else 块。
代码示例:
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
以上代码的渲染逻辑:当 length > 5 时,渲染 1,当 length > 2 是渲染 2,其余情况渲染 3。
wx:if block
与 wx:for 相同,wx:if 也可以用于 <block> 标签上,用于一次性判断多个标签,而不影响布局。
代码示例:
<block wx:if="{{true}}"><view> view1 </view><view> view2 </view>
</block>
与 hidden 对比
除 wx:if 外,组件还可以通过 hidden 属性控制显隐,那么他们有什么区别呢?
wx:if用于控制是是否渲染控制块内的模板。当条件切换时,会触发局部渲染,以确保条件块在切换时销毁或重新渲染;wx:if是惰性的,若初始渲染条件为false,框架什么也不做,在条件第一次变true时才开始局部渲染。hidden用于控制组件是否显示。组件始终会被渲染,只是简单控制显示与隐藏,并不会触发重新渲染和销毁。
一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,若需要频繁切换的情景下,用 hidden 更好,若在运行时条件基本不改变则 wx:if 更好。
事件绑定
WXML 中的事件通过 bind(或 catch)+事件名 属性进行事件绑定。当触发事件时,框架会调用逻辑层中对应的事件处理函数,并将当前状态通过参数传递给事件处理函数。
由于小程序中没有 DOM 的概念,因此事件只能通过 WXML 绑定,不能在逻辑层动态绑定。
代码示例:
<view data-params="123" bindtap="handleTap">点击</view>
Page({data: {},handleTap(e) {const params = e.currentTarget.dataset.paramsconsole.log(`参数:${params}`)}
})
点击按钮会触发 点击事件 tap, 在控制台打印 参数: 123。
效果如下: 
由于 事件系统 可以说的内容比较多,后续会整一篇专题,此处仅供小伙伴做初步了解。
模板
在实际项目开发中,经常会遇到不同页面使用相同的页面结构的情况。这是可以将相同的页面结构放入到一个模板中,然后在不同的页面调用,传入对应的绑定数据即可。以提升代码复用性,提升开发效率,避免重复开发。
定义模板
模板的代码片段在 <template> 标签内定义,通过 name 属性指定模板名称即可。
<template name="myTemplate"><view>内容</view><view>{{content}}</view>
</template>
使用模板
通过 is 属性指定需要渲染的模板。通过 data 属性传入模板所需的数据。
模板有自己的作用域,只能使用传入的 data 以及模板定义文件中定义的 <wxs /> 模块,不能直接使用 Page 中定义的 data。
<template name="myTemplate"><view>内容</view><view>{{content}}</view>
</template>
<template is="myTemplate" data="{{ content: 'hello 小程序' }}" />
模板也可以嵌套使用:
<template name="myTemplate"><view>myTemplate 内容:</view><view>{{content}}</view>
</template>
<template name="myTemplate1"><view>myTemplate1 内容:</view><view>{{content}}</view><template is="myTemplate" data="{{ content: '我是 myTemplate 的 内容' }}" />
</template>
<template is="myTemplate1" data="{{ content: '我是 myTemplate1 的 内容' }}" />
is 属性可以使用 Mustache 语法,来动态决定具体需要渲染哪个模板:
<template name="myTemplate"><view>myTemplate 内容:</view><view>{{content}}</view>
</template>
<template name="myTemplate1"><view>myTemplate1 内容:</view><view>{{content}}</view>
</template>
<block wx:for="{{[1,2]}}"><template is="{{item === 1 ? 'myTemplate' : 'myTemplate1'}}" data="{{content: item}}" />
</block>
引用
WXML 提供两种方式来引用其他 WXML 文件:import 和 include。
import
用于引入目标文件中定义的模板,忽略模板定义之外的所有内容。
<import /> 通过 src 属性指定被引入文件的相对地址。<import/> 引入会忽略引入文件中 <template/> 定义以外的内容。如下例中,仅引入了 tpl1.wxml 中定义的模板,模板外的 view 标签内容不会渲染到页面中。
例如在 pages/template/tpls 目录下新增一个 tpl1.wxml 文件,内容如下:
// pages/template/tpls/tpl1.wxml
<template name="tpl1-A"><view>我是 tpl1-A 模板</view>
</template>
<view>hello 小程序</view>
在 pages/template/template.wxml 中使用 import 引用 tpl1.wxml,即可使用在 tpl1.wxml 中定义的模板 tpl1-A。
// pages/template/template.wxml
<import src="./tpls/tpl1.wxml" />
<template is='tpl1-A' />
效果如下: 
import 存在作用域的概念,即只会引用目标文件中定义的模板,而不会引用在目标文件中引用的模板。
如 pages/template/tpls 目录下新增 tpl1.wxml、tpl2.wxml,存在如下引用关系:template.wxml 引用 tpl1.wxml,tpl1.wxml 引用 tpl2.wxml,则 template.wxml 文件中可以使用 tpl1.wxml 中定义的 tpl1-A 模板,而无法使用 tpl2.wxml 中定义的 tpl2-A 模板。
// pages/template/tpls/tpl1.wxml
<import src="./tpl2.wxml" />
<template name="tpl1-A"><view>我是 tpl1-A 模板</view><template is="tpl2-A" />
</template>
// pages/template/tpls/tpl2.wxml
<template name="tpl2-A"><view>我是 tpl2-A 模板</view>
</template>
// pages/template/template.wxml
<import src="./tpls/tpl1.wxml" />
<template is='tpl1-A' />
<!-- 不生效 -->
<template is='tpl2-A' />
inlcude
include 的作用域 import 恰恰相反,会将目标文件中除 template 和 <wxs /> 以外的代码全部引入,相当于将目标文件代码拷贝到 <include> 的位置。
我们对上面的例子做一下调整:
// pages/template/tpls/tpl1.wxml
<import src="./tpl2.wxml" />
<template name="tpl1-A"><view>我是 tpl1-A 模板</view><template is="tpl2-A" />
</template>
<view>我是 tpl1 组件内容</view>
// pages/template/template.wxml
<include src="./tpls/tpl1.wxml" />
<view>我是 template 内容</view>
<!-- 引用 tpl1-A 模板不生效 -->
<template is='tpl1-A' />
效果如下: 
通过以上应用可以发现:
import 更适合引用模板定义文件,而 include 更适合引用组件文件。
样式文件 - .wxss
WXSS (WeiXin Style Sheets) 是一套基于 CSS 拓展的样式语言,用于描述 WXML 的组件样式。其具有 CSS 的大部分特性,同时为了更适合小程序开发,对 CSS 进行了扩充和修改。
扩展的特性包括:
- 尺寸单位
- 样式导入
注:
熟悉
CSS对于WXSS的使用有很大的帮助,还不了解CSS的小伙伴,建议先补习一下。可查阅 MDN 做个整体的了解。
尺寸单位
小程序新提供一个尺寸单位:rpx,以实现页面布局根据屏幕宽度进行自适应,在渲染过程中 rpx 会按比例转化为 px。
rpx 转换规则:
WXSS 规定屏幕宽度为 750 rpx,若屏幕宽度为 375 px(如 iphone6),共有 750 个物理像素,则 750rpx = 375px = 750 物理像素,得出 1rpx = 0.5px = 1 物理像素。
常用设备屏幕转换如下:
| 设备 | rpx 转 px(公式:屏幕宽度/750) | px 转 rpx(公式:750/屏幕宽度) |
|---|---|---|
| iPhone5 | 1rpx = 0.42px | 1px = 2.34rpx |
| iPhone6 | 1rpx = 0.5px | 1px = 2rpx |
| iPhone6 Plus | 1rpx = 0.552px | 1px = 1.81rpx |
从上表可知,iphone6 设备的转换结果最为标准,即 1px = 2rpx,因此建议小程序的设计师可以以 iphone6 最为视觉标准进行页面设计。
样式导入
WXSS 中可以使用 @import 导入外联样式表,@import 后跟要导入的外联样式表的相对路径,结尾用 ; 表示语句结束。
代码示例:
/** common.wxss **/
.small-p {padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {padding:15px;
}
内联样式
框架组件上支持使用 style、class 属性来控制组件的样式。
style:静态的样式统一写到class中。style接收动态的样式,在运行时会进行解析,尽量避免将静态的样式写进style中,以免影响渲染速度。
<view style="color:{{color}};" />
class:用于指定样式类,样式类名之间用空格分隔。
<view class="custom_view normal_view" />
选择器
目前小程序支持的选择器如下:
| 选择器 | 样例 | 样例描述 |
|---|---|---|
| .class | .intro | 选择所有拥有 class=“intro” 的组件 |
| #id | #firstname | 选择拥有 id=“firstname” 的组件 |
| element | view | 选择所有 view 组件 |
| element, element | view, checkbox | 选择所有文档的 view 组件和所有的 checkbox 组件 |
| ::after | view::after | 在 view 组件后边插入内容 |
| ::before | view::before | 在 view 组件前边插入内容 |
样式文件分为全局样式(app.wxss)和局部样式(页面级的 .wxss),局部样式只作用于对应页面,且会覆盖全局样式中相同的选择器。
脚本文件 - .wxs
WXS(WeiXin Script) 是小程序独有的一套脚本语言,结合 WXML,可以构建出页面的结构。
WXML 无法调用页面的 .js 中定义的函数,但是可以调用定义在 .wxs 中的函数,鉴于此,WXS 最典型的应用场景就是 筛选器。
WXS 语法上有与 JavaScript 相近的地方,但他们属于完全不同的两种语言,主要区别如下:
WXS有自己的数据类型。WXS不支持类似于es6以上的语法。WXS模块遵循CommonJs规范。
定义 WXS
WXS 代码可以编写在 wxml 文件中的 <wxs> 标签内,或以 .wxs 为后缀名的文件内。
在 pages/wxs/a.wxs 中编写 wxs 代码:
// pages/wxs/a.wxs
const foo = 'hello 小程序'
const bar = function() {console.log('触发 a.wxs bar 函数')
}
module.exports = {foo,bar
}
在 pages/wxs/wxs.wxml 中引用 a.wxs 导出的内容:
// pages/wxs/wxs.wxml
<wxs src="./a.wxs" module="a" />
<view> {{a.foo}} </view>
<view> {{a.bar()}} </view>
<wxs> 标签
该标签用于包裹 wxs 脚本段或引入指定脚本文件。
包含以下两个属性:
module: 当前<wxs>标签的模块名。必填字段。src: 引用.wxs文件的相对路径。仅当本标签为 单闭合标签 或 标签的内容为空 时有效。
module 属性
在单个 wxml 文件内,建议其值唯一。若有重复模块名则按照先后顺序覆盖(后者覆盖前者)。不同 wxml 文件之间的 wxs 模块名互补影响。
module 属性值的命名规则:
- 首字符必须是:字母(a-zA-Z),下划线(_)。
- 剩余字符可以是:字母(a-zA-Z),下划线(_), 数字(0-9)。
src 属性
使用 src 引用其他 wxs 模块是,需注意:
- 只能引用
.wxs文件模块,且必须使用 相对路径。 wxs模块均为单例,wxs模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个wxs模块对象。- 如果一个
wxs模块在定义之后,一直没有被引用,则该模块不会被解析与运行。
模块
每一个 .wxs 文件和 <wxs> 标签都是一个单独的模块。
每个模块都有自己独立的作用域。即在一个模块里面定义的变量与函数,默认为私有的,对其他模块不可见。
一个模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现。
在 pages/wxs/a.wxs 中导出 foo 和bar:
// pages/wxs/a.wxs
const foo = 'hello 小程序'
const bar = function() {console.log('触发 a.wxs bar 函数')
}
module.exports = {foo,bar
}
若需要在.wxs模块中引用其他 wxs 文件模块,可以使用 require 函数。
在 pages/wxs/b.wxs 中引用 a.wxs:
// pages/wxs/b.wxs
var a = require('./a.wxs')console.log(a.foo)
console.log(a.bar())
使用 require 函数引用 wxs 模块时与使用 <wxs> src 属性引用类似,同样需要注意以下几点:
- 只能引用
.wxs文件模块,且必须使用相对路径。 wxs模块均为单例,wxs模块在第一次被引用时,会自动初始化为单例对象。多个页面,多个地方,多次引用,使用的都是同一个wxs模块对象。- 如果一个
wxs模块在定义之后,一直没有被引用,则该模块不会被解析与运行。
注意事项
<wxs>模块只能在定义该模块的WXML文件中被访问到。使用<include>或<import>引用时,<wxs>模块不会被引入到对应的WXML文件中。<template>标签中,只能使用定义该<template>的WXML文件中定义的<wxs>模块。
数据类型
WXS 目前支持以下数据类型:
number: 数值string:字符串boolean:布尔值object:对象function:函数array: 数组date:日期regexp:正则
与 es5 差异
WXS数据类型额外新增一个constructor属性
| 数据类型 | contructor |
|---|---|
| number | Number |
| string | String |
| boolean | Boolean |
| object | Object |
| function | Function |
| array | Array |
| date | Date |
| regexp | RegExp |
- 对象生成方式
- 生成 date 对象需要使用
getDate函数, 返回一个当前时间的对象。 - 生成 regexp 对象需要使用
getRegExp函数。 - 其余数据类型均支持使用字面量方式定义数据对象。
- 数据类型判断
constructor属性
由于每个数据类型都包含指定的 contructor 属性,因此可以直接通过该属性进行判断。
var number = 10;
console.log( "Number" === number.constructor );var string = "str";
console.log( "String" === string.constructor );var boolean = true;
console.log( "Boolean" === boolean.constructor );var object = {};
console.log( "Object" === object.constructor );var func = function(){};
console.log( "Function" === func.constructor );var array = [];
console.log( "Array" === array.constructor );var date = getDate();
console.log( "Date" === date.constructor );var regexp = getRegExp();
console.log( "RegExp" === regexp.constructor );
tyoeof
此处 typeof 作用与 JavaScript 相同,其中 object、array、date、regexp、null 类型均返回 object。
var number = 10;
var boolean = true;
var object = {};
var func = function(){};
var array = [];
var date = getDate();
var regexp = getRegExp();console.log( 'number' === typeof number );
console.log( 'boolean' === typeof boolean );
console.log( 'object' === typeof object );
console.log( 'function' === typeof func );
console.log( 'object' === typeof array );
console.log( 'object' === typeof date );
console.log( 'object' === typeof regexp );console.log( 'undefined' === typeof undefined );
console.log( 'object' === typeof null );
更多数据类型详细内容可以查阅小程序文档。
其他
小程序还支持其他如变量定义、注释、运算符、条件\循环语句以及内置的基础类库等,其使用规则与 es5 大同小异,此处就不多占篇幅了,有疑问的小伙伴可以私聊或评论,确实有必要补充的话后续可更新上来。
结语
今天的「小程序入门系列-简介及工程创建」就到这里啦,读到这里的小伙伴应该对小程序主体文件处理,小程序页面开发等有了大致的印象,爱动手的小伙伴们快去动起来吧😁。
若本文内容有错误或遗漏的地方,欢迎评论指出。感谢阅读,愿你我共同进步,谢谢!!!