前言
哈喽大家好,我是 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
大同小异,此处就不多占篇幅了,有疑问的小伙伴可以私聊或评论,确实有必要补充的话后续可更新上来。
结语
今天的「小程序入门系列-简介及工程创建」就到这里啦,读到这里的小伙伴应该对小程序主体文件处理,小程序页面开发等有了大致的印象,爱动手的小伙伴们快去动起来吧😁。
若本文内容有错误或遗漏的地方,欢迎评论指出。感谢阅读,愿你我共同进步,谢谢!!!