本文为微信小程序开发的学习总结
2.1 JSON 配置
JSON 是一种数据格式,在小程序中起静态配置的作用。JSON 在小程序运行之前就决定了小程序一些表现,需要注意的是小程序是无法在运行过程中去动态更新JSON 配置文件从而发生对应的变化的。
2.1.1 JSON 语法
JSON文件都是被包裹在一个大括号中 {},通过key-value的方式来表达数据。JSON的Key必须包裹在一个双引号中且无法使用注释。
2.2 WXML 模板
2.2.1 介绍
打开 pages/wxml/index.wxml 文件:
<!--pages/wxml/index.wxml-->
<text>pages/wxml/index.wxml</text>
不带有任何逻辑功能的 WXML 基本语法如下:
<!-- 在此处写注释 -->
<标签名 属性名1="属性值1" 属性名2="属性值2" ...> ...</标签名>
一个完整的 WXML语句由一段开始标签和一段结束标签组成,在标签中可以是内容,也可以是其他的 WXML 语句。WXML 要求标签必须是严格闭合的。
标签可以拥有属性,属性提供了有关的 WXML元素更多信息。属性总是定义在开始标签中,除了一些特殊的属性外,其余属性的格式都是key=“value” 的方式成对出现。WXML中的属性是大小写敏感的。
带有属性的图片标签
<image class="userinfo-avatar" src="./image/a.png" ></image>
2.2.2 数据绑定
可以动态的改变渲染界面
数据绑定示例:
<!--pages/wxml/index.wxml-->
<text>当前时间:{{time}}</text>
打开 pages/wxml/index.js 文件,在 data 的大括号中加入:time: (new Date()).toString()
示例:
// pages/wxml/index.js
Page({
/**
* 页面的初始数据
*/
data: {
time: (new Date()).toString()
},
})
模拟器刷新后正确的展示了当前时间,并且每次编译时间都会被更新。
WXML 通过 {{变量名}} 来绑定 WXML 文件和对应的 JavaScript 文件中的 data 对象属性。
为了保持简单,通过以下格式来展示上述的代码逻辑,使用第一段注释来表明 WXML 对应的脚本文件中的 data 结构。
展示格式:
<!--
{
time: (new Date()).toString()
}
-->
<text>当前时间:{{time}}</text>
属性值也可以动态的去改变,有所不同的是,属性值必须被包裹在双引号中,如下:
<text data-test="{{test}}"> hello world</text>
2.2.3 逻辑语法
可以在 {{ }} 内进行简单的逻辑运算
三元运算:
<!-- 根据 a 的值是否等于 10 在页面输出不同的内容 -->
<text>{{ a === 10? "变量 a 等于10": "变量 a 不等于10"}}</text>
算术运算:
<!--
{ a: 1, b: 2, c: 3 }
-->
<view> {{a + b}} + {{c}} + d </view>
<!-- 输出 3 + 3 + d -->
支持字符串的拼接:
<!--
{ name: 'world' }
-->
<view>{{"hello " + name}}</view>
<!-- 输出 hello world -->
{{ }}中还可以直接放置数字、字符串或者是数组(常量):
<text>{{[1,2,3]}}</text>
<!-- 输出 1,2,3 -->
<text>{{"hello world"}}</text>
<!-- 输出 hello world -->
2.2.4 条件逻辑
使用 wx:if="{{condition}}" 来判断是否需要渲染该代码块:
<view wx:if="{{condition}}"> True </view>
使用 wx:elif 和 wx:else 来添加一个 else 块:
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>
因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。
<block wx:if="{{true}}">
<view> view1 </view>
<view> view2 </view>
</block>
2.2.5 列表渲染
在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item
<!-- array 是一个数组 -->
<view wx:for="{{array}}">
{{index}}: {{item.message}}
</view>
<!-- 对应的脚本文件
Page({
data: {
array: [{
message: 'foo',
}, {
message: 'bar'
}]
}
})
-->
若不用默认设置,则应使用 wx:for-item 指定数组当前元素的变量名,使用 wx:for-index 指定数组当前下标的变量名:
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.message}}
</view>
类似 block wx:if
,也可以将 wx:for
用在 <block/>
标签上,以渲染一个包含多节点的结构块。例如:
<block wx:for="{{[1, 2, 3]}}">
<view> {{index}}: </view>
<view> {{item}} </view>
</block>
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input/>
中的输入内容, <switch/>
的选中状态),需要使用 wx:key
来指定列表中项目的唯一的标识符。
wx:key
的值以两种形式提供:
- 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
- 保留关键字 this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
当数据改变触发渲染层重新渲染的时候,框架会使带有 key 的组件被重新排序,而不是重新创建,以保持组件自身的状态,提高列表渲染效率。
使用 wx:key 示例(WXML)
<switch wx:for="{{objectArray}}" wx:key="unique" > {{item.id}} </switch>
<button bindtap="switch"> Switch </button>
<button bindtap="addToFront"> Add to the front </button>
<switch wx:for="{{numberArray}}" wx:key="*this" > {{item}} </switch>
<button bindtap="addNumberToFront"> Add Number to the front </button>
使用 wx:key 示例(JavaScript)switch函数进行数据交换
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.length
for (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.length
this.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
})
}
})
2.2.6 模板——类似于C中的函数
WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。使用 name 属性,作为模板的名字。然后在 <template/>
内定义代码片段,如:
定义模板:
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入
模板使用示例(将注释中的item放在Page中):
<!--
item: {
index: 0,
msg: 'this is a template',
time: '2016-06-18'
}
-->
<template name="msgItem">
<view>
<text> {{index}}: {{msg}} </text>
<text> Time: {{time}} </text>
</view>
</template>
<template is="msgItem" data="{{...item}}"/>
<!-- 输出
0: this is a template Time: 2016-06-18
-->
is可以动态决定具体需要渲染哪个模板。
动态使用模板:
<template name="odd">
<view> odd </view>
</template>
<template name="even">
<view> even </view>
</template>
<block wx:for="{{[1, 2, 3, 4, 5]}}">
<template is="{{item % 2 == 0 ? 'even' : 'odd'}}"/>
</block>
<!-- 输出
odd
even
odd
even
odd
-->
2.2.7 引用
WXML 提供两种文件引用方式import和include。
import 可以在该文件中使用目标文件定义的 template,如:
在 item.wxml 中定义了一个叫 item的 template :
<!-- item.wxml -->
<template name="item">
<text>{{text}}</text>
</template>
在 index.wxml 中引用了 item.wxml,就可以使用 item模板:
<import src="item.wxml"/>
<template is="item" data="{{text: 'forbar'}}"/>
2.3 WXSS样式
用于描述WXML的组件样式,也就是视觉上的效果。
2.3.1 文件组成
页面样式:与app.json注册过的页面同名且位置同级的WXSS文件。比如上图app.json注册了pages/rpx/index页面,那pages/rpx/index.wxss为页面pages/rpx/index.wxml的样式。
其它样式:其它样式可以被项目公共样式和页面样式引用
2.3.2 尺寸单位
为了适配不同宽度的屏幕,我们引入了rpx(responsive pixel)尺寸单位。小程序编译后,rpx会做一次px换算。
2.3.3 WXSS引用
样式引用:
@import './test_0.wxss'
由于WXSS最终会被编译打包到目标文件中,用户只需下载一次,在使用过程中不会因为样式引用产生多余的文件请求。
2.3.4 内联样式
WXSS内联样式:
<!--index.wxml-->
<!--内联样式-->
<view style="color: red; font-size: 48rpx"></view>
小程序支持动态更新内联样式:
<!--index.wxml-->
<!--可动态变化的内联样式-->
<!--
{
eleColor: 'red',
eleFontsize: '48rpx'
}
-->
<view style="color: {{eleColor}}; font-size: {{eleFontsize}}"></view>
2.3.5 选择器
WXSS优先级:
WXSS 选择器优先级权重:
view{ // 权重为 1
color: blue
}
.ele{ // 权重为 10
color: red
}
#ele{ // 权重为 100
color: pink
}
view#ele{ // 权重为 1 + 100 = 101,优先级最高,元素颜色为orange
color: orange
}
view.ele{ // 权重为 1 + 10 = 11
color: green
}
2.3.6 官方样式库
WeUI.wxss基础样式库:
2.4 JavaScript 脚本
小程序的主要开发语言是 JavaScript,用来开发业务逻辑以及调用小程序的 API
2.4.1 ECMAScript
JavaScript 是 ECMAScript 的一种实现。小程序中的 JavaScript同浏览器中的 JavaScript 以及 NodeJS 中的 JavaScript 是不相同的。
2.4.2 小程序的执行环境
不同的平台的小程序的脚本执行环境有所区别。
小程序目前可以运行在三大平台:
- iOS平台,包括iOS9、iOS10、iOS11
- Android平台
- 小程序IDE
区别体现在三大平台实现的 ECMAScript 的标准有所不同。
在项目设置中,勾选 ES6 转 ES5,将 ECMAScript 6代码转为 ECMAScript 5代码,从而在所有的环境都能得到很好的执行。
2.4.3 模块化
小程序中可以将任何一个JavaScript 文件作为一个模块,通过module.exports 或者 exports 对外暴露接口。
B.js 引用模块A,并使用A暴露的multiplyBy2方法完成一个变量乘以 2 的操作。
模块示例:
// moduleA.js
module.exports = function( value ){
return value * 2;
}
引用模块A:
// B.js
// 在B.js中引用模块A
var multiplyBy2 = require('./moduleA')
var result = multiplyBy2(4)
在需要使用这些模块的文件中,使用 require(path) 将公共代码引入——extern 函数:
var common = require('common.js')
Page({
helloMINA: function() {
common.sayHello('MINA')
},
goodbyeMINA: function() {
common.sayGoodbye('MINA')
}
})
2.4.4 脚本的执行顺序
小程序的执行的入口文件是 app.js 。并且会根据其中 require 的模块顺序决定文件的运行顺序。
app.js
/* a.js
console.log('a.js')
*/
var a = require('./a.js')
console.log('app.js')
/* b.js
console.log('b.js')
*/
var b = require('./b.js')
当 app.js 执行结束后,小程序会按照 app.json 中定义的 pages 的顺序逐一执行。
2.4.5 作用域
在文件中声明的变量和函数只在该文件中有效,不同的文件中可以声明相同名字的变量和函数,不会互相影响
当需要使用全局变量的时,通过使用全局函数 getApp() 获取全局的实例,并设置相关属性值
在脚本 a.js 中设置全局变量:
// a.js
// 获取全局变量
var global = getApp()
global.globalValue = 'globalValue'
在脚本 b.js 中访问 a.js 定义的全局变量:
// b.js
// 访问全局变量
var global = getApp()
console.log(global.globalValue) // 输出 globalValue
上述示例只有在 a.js 比 b.js 先执行才有效,当需要保证全局的数据可以在任何文件中安全的被使用到,那么可以在 App() 中进行设置
定义全局变量
// app.js
App({
globalData: 1
})
获取以及修改 global 变量的方法
// a.js
// 局部变量
var localValue = 'a'
// 获取 global 变量
var app = getApp()
// 修改 global 变量
app.globalData++ // 执行后 globalData 数值为 2