《小程序从入门到入坑》框架语法

前言

哈喽大家好,我是 SuperYing,我们继续小程序入门系列,本文将对小程序框架语法进行比较全面的介绍。在《小程序从入门到入坑》简介及工程创建中,我们提到小程序项目结构,主要包括 app.jsonapp.jsapp.wxss 以及页面(组件)级的 .wxml.wxss.js.json。接下来我将逐步介绍以上重点组成部分。

读完本文您将收获:

  • 了解小程序项目主体文件,明确 app.jsonapp.jsapp.wxss 等全局文件的作用及使用方式。
  • 了解小程序页面结构 WXML 语法,完成诸如 数据绑定列表渲染条件渲染 等常用开发方式。
  • 了解小程序样式 WXSS 的使用以及基于 css 语法的扩展方面。
  • 了解小程序脚本 WXS 的使用及典型应用场景。
  • 了解小程序常用开发技巧,基本可以独立完成小程序页面开发。

主体文件介绍

主体文件包括 app.jsonapp.jsapp.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 配置对应的小程序页面部分,小伙伴们可参考以验证配置是否正确。

image.png

注意

关于颜色的配置,应使用 十六进制 形式,如 #ffffff。

tabBar 配置

什么是 tabBar

tabBar 是移动端应用比较常见的页面效果,用于实现页面的快速切换。

在小程序中 tabBar 主要分为:

  • 顶部 tabBar
  • 底部 tabBar
配置项

如果小程序是一个多 tab 应用,即客户端窗口的底部或顶部有 tab 栏可以切换页面,可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。

tabBar 常用配置项如下:

  1. list 配置 tab 列表,限制最少 2 个,最多 5 个 tabtab 每个项目可配置以下内容:
    • pagePath: 必填,页面路径,必须在 pages 配置中先定义。
    • text: 必填,tab 上按钮文字。
    • iconPath: tab 默认图标路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。positiontop 时,不显示 icon
    • selectedIconPath: tab 选中时的图标路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。positiontop 时,不显示 icon
  2. colorselectedColor 分别设置 tab 上的默认文字颜色及选中时的文字颜色。
  3. backgroundColor 设置 tab 的背景色。
  4. borderStyle 设置 tab 的边框的颜色, 仅支持 black / white
  5. 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 部分标注:

image.png

注意:

  1. tabBar 的数量应控制在 2 ~ 5 个之间。

  2. 当渲染顶部 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 后打印信息:

image.png

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 编写,但在小程序中无法使用浏览器对象,如 documentwindow 等。同样的,基于浏览器特有对象的框架也无法使用,如 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() 被调用时,会将数据从逻辑层发送到视图层触发视图层重绘,同时会修改 Pagedata 值。

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,在不同平台被渲染为不同端的渲染文件。

image.png 如上图,WXML 语言最终会转译为宿主环境对应的语言,所以 WXML 中使用的标签一定要使用小程序定义的标签,不能使用自定义标签,以保证页面结构能被正确的转译。

使用微信开发者工具开发时,在 WXML 中编写 HTML 标签或自定义标签,也可以正常渲染。这是因为微信开发者工具内核是浏览器内核,而且微信开发者工具并没有对 WXMLWXSS 的内容进行强验证。但是无法保证在真机上可以正常渲染。因此,微信开发者工具的效果仅用于方便开发调试,而真正的效果一定要以真机效果为准。

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}
})

效果如下:

image.png

注意:

若关键字为布尔值时,如 checkboxchecked 属性,不能直接设置为 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: ['小程序从入门到入坑']}
})

效果如下:

image.png

组合

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)}
})

效果及控制台打印如下: image.png

列表渲染

wx:for

在组建上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。

默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item

代码示例:

<view wx:for="{{myArray}}">{{index}}-{{item}}
</view>
Page({data: {myArray: ['hello', 'world']}
})

以上代码遍历 myArray,重复渲染了两个 view

效果如下:

image.png

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-indexwx: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', '小程序']]}
})

结果如下:

image.png

wx:key

若列表中项目存在位置动态改变或者新增的情况,且希望列表中的项目保持自己的特征和状态(如 input 中的输入内容,switch 的选中状态),则需要使用 wx:key 来指定列表中项目的唯一的标识符。

熟悉 vue 的同学,应该比较了解 v-forkey 属性。小程序的 wx:keyv-forkey 作用差不多,目的在于提升列表渲染性能

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:keyswitch 组件的状态都不会刷新,即没有重新创建 switch 组件,而仅仅调整组件的位置。

wx:for block

wx:for 可以应用于 <block> 标签上,用于渲染包含多个节点的结构块。

<block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。

代码示例:

<block wx:for="{{myArray}}"><view> {{index}}: </view><view> {{item}} </view>
</block>
Page({data: {myArray: ['hello', 'world']}
})

效果如下: image.png

注意事项
  1. wx:for 的值为字符串时,会将字符串解析成字符串数组
<view wx:for="array">{{item}}
</view>

等同于

<view wx:for="{{['a','r','r','a','y']}}">{{item}}
</view>
  1. 花括号和引号之间如果有空格,将最终被解析成为字符串
<view wx:for="{{[1,2,3]}} ">{{item}}
</view>

等同于

<view wx:for="{{[1,2,3] + ' '}}" >{{item}}
</view>

条件渲染

wx:if

在页面结构中,经常需要使用逻辑分支,这时候可以使用 wx:if="{{判断条件}}" 来进行条件渲染,当条件成立时渲染该代码块。

同时提供了 wx:elifwx: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

效果如下: image.png

由于 事件系统 可以说的内容比较多,后续会整一篇专题,此处仅供小伙伴做初步了解。

模板

在实际项目开发中,经常会遇到不同页面使用相同的页面结构的情况。这是可以将相同的页面结构放入到一个模板中,然后在不同的页面调用,传入对应的绑定数据即可。以提升代码复用性,提升开发效率,避免重复开发。

定义模板

模板的代码片段在 <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 文件:importinclude

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' />

效果如下: image.png

import 存在作用域的概念,即只会引用目标文件中定义的模板,而不会引用在目标文件中引用的模板。

pages/template/tpls 目录下新增 tpl1.wxmltpl2.wxml,存在如下引用关系:template.wxml 引用 tpl1.wxmltpl1.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' />

效果如下: image.png

通过以上应用可以发现:

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/屏幕宽度)
iPhone51rpx = 0.42px1px = 2.34rpx
iPhone61rpx = 0.5px1px = 2rpx
iPhone6 Plus1rpx = 0.552px1px = 1.81rpx

从上表可知,iphone6 设备的转换结果最为标准,即 1px = 2rpx,因此建议小程序的设计师可以以 iphone6 最为视觉标准进行页面设计。

样式导入

WXSS 中可以使用 @import 导入外联样式表,@import 后跟要导入的外联样式表的相对路径,结尾用 ; 表示语句结束。

代码示例:

/** common.wxss **/
.small-p {padding:5px;
}
/** app.wxss **/
@import "common.wxss";
.middle-p {padding:15px;
}

内联样式

框架组件上支持使用 styleclass 属性来控制组件的样式。

  • style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,尽量避免将静态的样式写进 style 中,以免影响渲染速度。
<view style="color:{{color}};" />
  • class:用于指定样式类,样式类名之间用空格分隔。
<view class="custom_view normal_view" />

选择器

目前小程序支持的选择器如下:

选择器样例样例描述
.class.intro选择所有拥有 class=“intro” 的组件
#id#firstname选择拥有 id=“firstname” 的组件
elementview选择所有 view 组件
element, elementview, checkbox选择所有文档的 view 组件和所有的 checkbox 组件
::afterview::after在 view 组件后边插入内容
::beforeview::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 中导出 foobar

// 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 差异
  1. WXS 数据类型额外新增一个 constructor 属性
数据类型contructor
numberNumber
stringString
booleanBoolean
objectObject
functionFunction
arrayArray
dateDate
regexpRegExp
  1. 对象生成方式
  • 生成 date 对象需要使用 getDate函数, 返回一个当前时间的对象。
  • 生成 regexp 对象需要使用 getRegExp函数。
  • 其余数据类型均支持使用字面量方式定义数据对象。
  1. 数据类型判断
  • 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 相同,其中 objectarraydateregexpnull 类型均返回 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 大同小异,此处就不多占篇幅了,有疑问的小伙伴可以私聊或评论,确实有必要补充的话后续可更新上来。

结语

今天的「小程序入门系列-简介及工程创建」就到这里啦,读到这里的小伙伴应该对小程序主体文件处理小程序页面开发等有了大致的印象,爱动手的小伙伴们快去动起来吧😁。

若本文内容有错误或遗漏的地方,欢迎评论指出。感谢阅读,愿你我共同进步,谢谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/745249.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32初识1

什么是单片机&#xff1f; 单片机&#xff08; Single-Chip Microcomputer &#xff09;是一种集成电路芯片&#xff0c;把具有数据处理能力的中央处 理器 CPU 、随机存储器 RAM 、只读存储器 ROM 、多种 I/O 口和中断系统、定时器 / 计数器等功 能&#xff08;可能还包括显示…

部署快捷、使用简单、推理高效!大模型部署和推理框架 Xinference 来了!

今天为大家介绍一款大语言模型&#xff08;LLM&#xff09;部署和推理工具——Xinference[1]&#xff0c;其特点是部署快捷、使用简单、推理高效&#xff0c;并且支持多种形式的开源模型&#xff0c;还提供了 WebGUI 界面和 API 接口&#xff0c;方便用户进行模型部署和推理。 …

【iOS】ARC学习

文章目录 前言一、autorelease实现二、苹果的实现三、内存管理的思考方式__strong修饰符取得非自己生成并持有的对象__strong 修饰符的变量之间可以相互赋值类的成员变量也可以使用strong修饰 __weak修饰符循环引用 __unsafe_unretained修饰符什么时候使用__unsafe_unretained …

蓝桥杯--冶炼金属

目录 一、题目 二、解决代码 &#xff08;1&#xff09;版本一&#xff08;报错&#xff1a;超时&#xff09; 代码分析 &#xff08;2&#xff09;版本二&#xff08;不会超时&#xff09; 代码分析 &#xff08;3&#xff09;版本三&#xff08;最终精简版&#xff09;…

Python自学☞序列和索引的相关操作

一、基本概念 1、概念 序列是一个用于存储多个值的连续空间&#xff0c;每个值都对应一个整数的编号&#xff0c;称为索引 2、切片的语法结构 注&#xff1a;切片可以访问序列一定范围内的元素 序列[start&#xff1a;end&#xff1a;step] start-->切片的开始索…

Python数据分析-5

1.时间序列 2.pandas重采样 重采样&#xff1a;指的是将时间序列从一个频率转化为另一个频率进行处理的过程&#xff0c;将高频率数据转化为低频率数据为降采样&#xff0c;低频率转 化为高频率为升采样。 统计出911数据中不同月份电话次数的变化情况&#xff1a…

vue3中的文字滚动播报

vue3中的文字滚动播报 之前UI框架一直使用的elementPlus&#xff0c;有个需求&#xff0c;需要在页面上写个滚动播放新闻的功能&#xff0c;发现UI框架居然没有这个组件。花了一下午&#xff0c;在ChatGPT的帮助下&#xff0c;总算写成功了&#xff0c;先看最终展示效果 web页…

GPT-5:人工智能的下一个前沿即将到来

当我们站在人工智能新时代的门槛上时&#xff0c;GPT-5即将到来的呼声愈发高涨且迫切。作为革命性的GPT-3的继任者&#xff0c;GPT-5承诺将在人工智能领域迈出量子跃迁式的进步&#xff0c;其能力可能重新定义我们与技术的互动方式。 通往GPT-5之路 通往GPT-5的旅程已经标记着…

Unreal发布Android在刘海屏手机上不能全屏显示问题

Unreal 4.27发布Android在刘海屏手机上不能全屏显示问题 Android设置全屏刘海屏全屏设置4.27设置刘海屏在部分手机不能显示问题 Android设置全屏 AndroidManifest.xml文件配置 ...<activity android:name"com.epicgames.ue4.GameActivity" android:label"st…

给电脑加硬件的办法 先找电脑支持的接口,再买相同接口的

需求&#xff1a;我硬盘太小&#xff0c;换或加一个大硬盘 结论&#xff1a;接口是NVMe PCIe 3.0 x4 1.找到硬盘型号 主硬盘 三星 MZALQ512HALU-000L2 (512 GB / 固态硬盘) 2.上官网查 或用bing查 非官方渠道信息&#xff0c;不确定。

CompletableFuture原理与实践-外卖商家端API的异步化

背景 随着订单量的持续上升&#xff0c;美团外卖各系统服务面临的压力也越来越大。作为外卖链路的核心环节&#xff0c;商家端提供了商家接单、配送等一系列核心功能&#xff0c;业务对系统吞吐量的要求也越来越高。而商家端API服务是流量入口&#xff0c;所有商家端流量都会由…

【深度学习笔记】9_5 多尺度目标检测

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 9.5 多尺度目标检测 在9.4节&#xff08;锚框&#xff09;中&#xff0c;我们在实验中以输入图像的每个像素为中心生成多个锚框。这些…

springboot+vue学生选课系统 java+ssm+idea+_mysql

系统包含三种角色&#xff1a;管理员、老师、学生&#xff0c;系统分为前台和后台两大模块&#xff0c;主要功能如下。 ide工具&#xff1a;IDEA 或者eclipse 编程语言: java 学生网上选课系统可以实现教室管理&#xff0c;老师管理&#xff0c;课程管理&#xff0c;教学计划管…

微服务分布式springcloud研究生志愿填报辅助系统

本文讲述了研究生志愿填报辅助系统。结合电子管理系统的特点&#xff0c;分析了研究生志愿填报辅助系统的背景&#xff0c;给出了研究生志愿填报辅助系统实现的设计方案。 本论文主要完成不同用户的权限划分&#xff0c;不同用户具有不同权限的操作功能&#xff0c;在用户模块&…

AJAX 03 XMLHttpRequest、Promise、封装简易版 axios

AJAX 学习 AJAX 3 原理01 XMLHttpRequest① XHR 定义② XHR & axios 关系③ 使用 XHR④ XHR查询参数案例&#xff1a;地区查询&#xff08;URLSearchParams&#xff09;⑤ XHR数据提交 POST 02 PromisePromise 使用Promise - 三种状态案例&#xff1a;使用Promise XHR 获取…

电商场景下 ES 搜索引擎的稳定性治理实践

继上文在完成了第一阶段 ES 搜索引擎的搭建后&#xff0c;已经能够实现对千万级别的商品索引的读写请求的支持。目前&#xff0c;单机房读流量在 500&#xff5e;1000 QPS 之间&#xff0c;写流量在 500 QPS 左右。 但随着业务的发展&#xff0c;问题也逐渐开始暴露&#xff0…

Wmware安装Linux(centerOS、Ubuntu版本)

目录 1、安装wmware 2、center版本 3、ubuntu版本 1、安装wmware 此处不做展开。 2、center版本 需要提前下载的文件&#xff1a; 无图形化界面https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso 有图形化界面https://mirrors.a…

增删卜易——八宫六十四卦

之前看倪海厦的《天纪》笔记里面提到了六十四卦世应,觉得不知道这个世应是啥意思。很长时间就没看了,偶然间看到了张文江教授写的一本书《潘雨廷先生谈话录》提到了《卜筮正宗》,“卜筮最后的判断是非理性转义,其他一切都只是形式”,“明人的著作,从京氏易出,如今天几日…

STM32 学习12 输入捕获与触摸按键

STM32 学习12 输入捕获与触摸按键 一、输入捕获介绍1. 概念2. STM32F1 资源3. 捕获原理 二、输入捕获配置步骤1. 使能时钟、设置端口模式2. 初始化定时器3. 设置捕获参数4. 开启捕获和定时器中断&#xff08;溢出中断|更新中断&#xff09;6. 编写定时器中断服务函数7. 使能定时…

针对教育行业的网络安全方案有哪些

智慧校园”是教育信息化进入高级阶段的表现形式&#xff0c;比“数字校园”更先进。集体知识共融、共生、业务应用融合创新、移动互联网物联网高速泛在是其重要特征。特别是在互联网教育的大环境下&#xff0c;为了更好的发挥智慧化教学服务和智慧化教学管理功能&#xff0c;需…