设置外观和代理
外观
代理
项目结构
主要目录
pages:存放所有小程序的页面utils:存放工具性质的模块(例如:格式化时间的自定义模块)app.js:小程序项目的入口文件app.json:小程序项目的全局配置文件app.wxss:小程序项目的全局样式文件(在此文件内写入的样式会被全局生效)project.config.json:项目配置文件sitemap.json:配置小程序及其页面是否允许被微信索引pages目录
小程序官方建议将所有小程序的页面,都存放在pages目录中,以单独的文件夹存在
其中,每个页面由4个基本文件组成:.js文件(页面的脚本文件,存放页面的数据、事件处理函数等).json文件(当前页面的配置文件,配置窗口的外观、表现等).wxml文件(页面的模板结构文件)-
JSON配置文件
通过不同的
.json配置文件,可以对小程序项目进行不同级别的配置 根目录中的
app.json配置文件- 根目录中的
project.config.json配置文件 - 根目录中的
sitemap.json配置文件 - 每个页面文件夹中的
.json配置文件app.json
小程序的全局配置,包括小程序的所有页面路径、窗口外观、界面表现、底部tab等
"pages":小程序所有页面的路径"window":全局定义小程序所有页面的背景色、文字颜色等"tabBar":全局定义小程序底部的 tab 栏"style":全局定义小程序组件所使用的样式版本"sitemapLocation":用来指明 sitemap.json 的位置{"pages":["pages/index/index","pages/logs/logs"],"window":{"backgroundTextStyle":"light","navigationBarBackgroundColor": "#fff","navigationBarTitleText": "Weixin","navigationBarTextStyle":"black"},"tabBar": {"list": [{"pagePath": "pages/index/index","text": "首页"}]},"style": "v2","sitemapLocation": "sitemap.json"}
project.config.json
项目配置文件,用来记录我们对小程序开发工具所做的个性化配置
setting:编译相关的配置projectname:项目名称-
sitemap.json
配置小程序页面是否允许微信索引
page:所有页面都能被索引action:是否允许被索引(allow为允许,disallow为不允许)

注:sitemap的索引提示是默认开启的,如需关闭sitemap的索引提示,在小程序项目配置文件project.config.json的setting中配置字段checkSiteMap为false
页面的.json配置文件
小程序中每个页面都可以使用`.json`文件来对本页面的窗口外观进行配置,页面中的配置项会覆盖`app.json`的`window`中相同的配置项<br />
新建小程序页面
只需在app.json中的pages节点中新增页面的存放路径,小程序开发者工具会帮我们自动创建对应的页面文件
WXML模板
什么是 WXML
WXML是小程序框架设计的一套标签语言,用来构建小程序页面的结构,作用类似于网页开发中的 HTML
WXML 和 HTML 的区别
- 标签名称不同
- HTML(div,span,img,a)
- WXML(view,text,image,navigator)
- 属性节点不同
<a href="#">超链接</a><navigator url="/pages/home/home">超链接</navigator>
提供了类似于 Vue 中的模板语法
新增了
rpx尺寸单位- CSS 中需要手动进行像素单位换算,例如 rem
- WXSS 在底层支持新的尺寸单位
rpx,在不同大小的屏幕上小程序会自动进行换算
- 提供了全局的样式和局部样式
- 项目根目录中的
app.wxss会作用域所有小程序页面 - 局部页面的
.wxss样式仅对当前页面生效
- 项目根目录中的
WXSS 仅支持部分 CSS 选择器
app.js
- 整个小程序项目的入口文件,通过调用
App()函数来启动整个小程序
- 整个小程序项目的入口文件,通过调用
- 页面的 .js 文件
- 页面的入口文件,通过调用
Page()函数来创建并运行页面
- 页面的入口文件,通过调用
普通的 .js 文件
主体:渲染层和逻辑层
- WXML 模板和 WXSS 样式工作在渲染层
- JS 脚本工作在逻辑层

- 通信
- 渲染层和逻辑层之间的通信
- 由微信客户端进行转发
- 逻辑层和第三方服务器之间的通信
- 由微信客户端进行转发
- 渲染层和逻辑层之间的通信
运行机制
- 启动过程
- 把小程序的代码包下载到本地
- 解析
app.json全局配置文件 - 执行
app.js小程序入口文件,调用App()创建小程序实例 - 渲染小程序首页
- 小程序启动完成
渲染过程
view- 普通视图区域
- 类似于 HTML 中的 div,是一个块级元素
scroll-view- 可滚动的视图区域
- 常用来实现滚动列表效果
swiper和swiper-itemtext:文本组件- 类似于 HTML 中的 span 标签,是个行内元素
rich-text:富文本组件- 支持把 HTML 字符串渲染为 WXML 结构
button:按钮组件- 功能比 HTML 中的 button 按钮丰富
- 通过
open-type属性可以调用微信提供的各种功能(客服、转发、获取用户授权、获取用户信息等)
image:图片组件
- 特点:以
on开头,用来监听某些事件的触发 举例:
wx.onWindowResize(function callback)监听窗口尺寸变化的事件同步 API
特点1:以
Sync结尾的 API 都是同步 API- 特点2:同步 API 的执行结果,可以通过函数返回值直接获取,如果执行出错会抛出异常
举例:
wx.setStorageSync('key','value')向本地存储中写入内容异步 API
特点:类似于 Jquery 中的
$.ajax(options)函数,需要通过 success、fail、complete 接收调用的结果举例:
wx.request()发起网络数据请求,通过 success 回调函数接收数据组件
view
view组件基本使用
实现 flex 横向布局效果:
- 更多属性请查阅相关文档:view文档链接
```html
// about.wxml
A B C
// about.wxss
- 效果图如下所示:<a name="b1MLd"></a>## scroll-view<a name="hO0nL"></a>### scroll-view 组件基本使用- 实现纵向滚动效果:- 更多属性请查阅相关文档:[scroll-view文档链接](https://developers.weixin.qq.com/miniprogram/dev/component/scroll-view.html)```html// scroll.wxml<scroll-view class="container1" scroll-y><view>A</view><view>B</view><view>C</view></scroll-view>// scroll.wxss<style> // 使用时要将 style 标签去掉.container1 view {width: 100px;height: 100px;text-align: center;line-height: 100px;}.container1 view:nth-child(1) {background-color: lightgreen;}.container1 view:nth-child(2) {background-color: lightskyblue;}.container1 view:nth-child(3) {background-color: lightcoral;}.container1 {border: 1px solid #000;height: 120px;width: 100px;}</style>
- 效果图如下所示:
swiper 和 swiper-item
swiper 和 swiper-item 组件的基本使用
- 实现轮播图效果:
- 更多属性请查阅相关文档:swiper文档链接、swiper-item文档链接
```html
// swiper.wxml
A B C
// swiper.wxss
- 效果图如下所示:- `swiper`组件的常用属性<a name="mOMJd"></a>## text<a name="AP6Tx"></a>### text 组件基本使用- `selectable`:实现长按文本选中文本内容的效果- `user-select`:实现长按文本选中,该属性会将文本显示为`inline-block`效果- 更多属性请查阅相关文档:[text文档链接](https://developers.weixin.qq.com/miniprogram/dev/component/text.html)```html<view>手机号支持长按选中效果<text selectable>18888888888</text><text user-select>我会在手机号后面显示</text></view>
rich-text
rich-text 组件基本使用
nodes:将该属性节点内的内容渲染为 HTML 元素- 更多属性请查阅相关文档:rich-text文档链接
```html
// richText.wxml
// richText.wxss .aqua { color: aqua; }
- 最终效果如下所示:<a name="qkTMt"></a>## button- `type`:设置按钮类型样式- `size`:设置按钮大小样式- `plain`:设置按钮背景色是否透明(默认不透明)- `disabled`:是否禁用按钮- `loading`:是否在按钮名称前带上 loading 图标- 更多属性请查阅相关文档:[button文档链接](https://developers.weixin.qq.com/miniprogram/dev/component/button.html)```html// button.wxml<!-- type属性使用 --><button>默认按钮</button><button type="primary">绿色按钮</button><button type="default">白色按钮</button><button type="warn">红色按钮</button><!-- size属性使用 --><button type="primary" size="mini">绿色按钮</button><button type="default" size="mini">白色按钮</button><button type="warn" size="mini">红色按钮</button><!-- plain属性使用 --><button plain type="primary">绿色按钮</button><button plain type="default">白色按钮</button><button plain type="warn">红色按钮</button><!-- disabled属性使用 --><button type="primary" disabled>绿色按钮</button><!-- loading属性使用 --><button type="primary" loading></button>
image
注意:
image元素默认宽高为width: 320px; height: 240px;标签中即使没有src路径或src路径下没有内容,宽高依旧不改变
src:图片路径,/默认表示项目根目录mode:指定图片的剪裁模式和缩放模式- 缩放模式:
scaleToFill(默认值):不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素aspectFit:保持纵横比缩放图片,完全展示图片的长边,会完整地将图片显示出来aspectFill:保持纵横比缩放图片,完全展示图片的短边,会使图片有一定的裁剪widthFix:宽度不变,高度自动变化,保持原图宽高比不变heightFix:高度不变,宽度自动变化,保持原图宽高比不变
- 剪裁模式:不缩放图片
top:只显示图片的顶部区域bottom:只显示图片的底部区域center:只显示图片的中间区域left:只显示图片的左边区域right:只显示图片的右边区域top left:只显示图片的左上区域top right:只显示图片的右上区域bottom left:只显示图片的左下区域bottom right:只显示图片的右下区域
- 缩放模式:
lazy-load:图片懒加载,在即将进入一定范围(上下三屏)时才开始加载show-menu-by-longpress:长按图片显示发送给朋友、收藏、保存图片、搜一搜、打开名片/前往群聊/打开小程序(若图片中包含对应二维码或小程序码)的菜单- 更多属性请查阅相关文档:image文档链接
```html
效果如下图所示:<br />html
效果如下图所示:<br />html

<a name="WPvfq"></a>
# WXML模板
<a name="rgrIN"></a>
## 数据绑定
<a name="FRk2T"></a>
### 基本原则
1. 在 data 中定义数据javascript
Page({
data: {
// 字符串类型
info: ‘init data’,
imgSrc: “https://s.cn.bing.net/th?id=OIP-C.nRlAFygdctTCHmIWN7GxRwHaEK&w=333&h=187&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2“,
randomNum1: Math.random() * 10,
randomNum2: Math.random().toFixed(2)
}
})
2. 在 WXML 中使用数据html
最终效果如下所示:<br />
<a name="i1Kkm"></a>
## 事件绑定
- 定义:在`.js`文件中的`Page()`函数中
- 绑定:在`element`中绑定事件
<a name="cjOBM"></a>
### 常用事件
| 类型 | 绑定方式 | 事件描述 |
| --- | --- | --- |
| `tap` | bindtap 或 bind:tap | 手指触摸后马上离开,类似于 HTML 的 click 事件 |
| `input` | bindinput 或 bind:input | 文本框的输入事件 |
| `change` | bindchange 或 bind:change | 状态改变时触发 |
<a name="dp80f"></a>
#### bindtap 语法格式
1. 通过`bindtap`可以为组件绑定`tap`触摸事件,语法如下:html
2. 在页面的`.js`文件中定义对应的事件处理函数,事件参数通过形参`event(简写:e)`来接收:javascript
btnTapHandler(e) { // 按钮的 tap 事件处理函数
console.log(e) // 事件参数对象 e
}
结果如下所示:<br />
<a name="nNj1z"></a>
#### bindinput 语法格式
1. 通过`bindinput`为文本框绑定**输入**事件:html
2. 在页面的`.js`中定义事件处理函数:javascript
inputHandler(e) {
console.log(e.detail.value)
},
> `e.detail.value`获取 input 框的最新值
结果如下所示:<br />
<a name="TykVI"></a>
#### bindinput 实现 v-model 效果html
```javascript
Page({
data: {
msg: 'Hello World!'
},
inputModel(e) {
this.setData({
msg: e.detail.value
})
},
})

### 事件对象属性
| 属性 | 类型 | 说明 |
| —- | —- | —- |
| type | String | 事件类型 |
| timeStamp | Integer | 页面打开到触发事件所经过的毫秒数 |
| target | Object | 触发事件的组件的一些属性值集合 |
| currentTarget | Object | 当前组件的一些属性值合集 |
| detail | Object | 额外的信息 |
| touches | Array | 触摸事件,当前停留在屏幕中的触摸点信息的数组 |
| changedTouches | Array | 触摸事件,当前变化的触摸点信息的数组 |
#### target和currentTarget的区别
- e.target指向的是触发事件的源头组件,因此,e.target是内部的按钮组件
- e.currentTarget指向的是当前正在触发事件的组件,因此,e.currentTarget是当前源头组件最外部的组件
### 数据赋值 this.setData()
- 使用this.setData()方法,给 Data 中的数据重新赋值
html
<view>count值:{{count}}</view>
<button type="primary" bindtap="changeCount">Count++</button>
javascript
changeCount() {
this.setData({
count: this.data.count + 1
})
}
> 用this.data拿到 Page()中的 data对象
### 事件传参
- 传递参数:使用`data-=”{{value}}”给事件传参,表示参数名,value表示参数值
- **获取参数值**:使用e.target.dataset,获取事件传递过来的参数值,一般来说是个对象,使用e.target.dataset.info获取指定的参数值
```html
<button type="primary" bindtap="btnTapHandler1" data-info="{{3}}">事件传参</button>
```
```javascript
btnTapHandler1(e) {
// 获取的是参数对象
console.log(e.target.dataset);
// 获取的是具体的参数值,info 为传来的参数名
console.log(e.target.dataset.info);
},
```
<a name="t7eZO"></a>
## 条件渲染
<a name="t87fu"></a>
### wx:if、wx:elif、wx:else(属性)
```html
<view wx:if="{{num >= 95}}">学霸</view>
<view wx:elif="{{num >= 90}}">优等生</view>
<view wx:elif="{{num >= 60}}">普通生</view>
<view wx:else>学渣</view>
```
```javascript
data: {
num: 99
},
```
<a name="AOu3Z"></a>
### block 标签(组件)
- 作用:类似 Vue 中的template标签,只用来包裹
```html
<block wx:if="{{true}}">
<view>为 true 显示我</view>
<view>为 true 显示我</view>
</block>
```

> 真实渲染时,block标签并不会渲染到页面中
<a name="wYnoo"></a>
### hidden(属性)
- 作用:使用display: none;来控制元素的 **显示** 和 **隐藏**,true为**显示**,false`为*隐藏
html
<view hidden="{{ false }}">为 true 隐藏我,为 false 显示我</view>

## 列表渲染
### wx:for、wx:for-index、wx:for-item
- wx:for-index:指定 index索引的名字
- wx:for-item:指定item值的名字
```html
// cycle.js Page({ data: { arr: [‘iPhone’, ‘HUAWEI’, ‘vivo’] } })
<a name="ucub6"></a># WXSS<a name="Um8lZ"></a>## 特性:1. `rpx`尺寸单位1. `@import`样式导入<a name="fn8YN"></a>## rpx尺寸单位<a name="GzG0C"></a>### 了解- `rpx`是小程序独有的,用来**解决屏幕适配的尺寸单位**<a name="FGlMZ"></a>### 实现原理- 鉴于不同设备屏幕的大小不同,为了实现屏幕的自动适配,**rpx** 把所有设备的屏幕在宽度上**等分为 750 份**(即:当前屏幕的总宽度为 **750rpx**)- 小设备上,1rpx 代表的宽度就小- 大设备上,1rpx 代表的宽度就大- 小程序在不同的设备中运行时,会自动将 rpx 单位换算为 px 单位进行渲染,从而实现屏幕适配<a name="TTTdR"></a>## @import (样式导入)- `@import` 后跟需要导入的外联样式表的相对路径,用 `;` 表示语句结束```html// Pages/index/index.wxml<view wx:for="{{userList}}" wx:key="id" class="username">id:{{item.id}} --- value:{{item.name}}</view>// common/common.wxss.username {color: aqua;}// Pages/index.index.wxss@import "../../common/common.wxss"
全局样式(app.wxss)
- 作用于所有页面
view {padding: 10rpx;margin: 10rpx;background-color: #888;}

当全局样式和局部样式冲突时,根据就近原则,局部样式会覆盖全局样式 当局部样式的权重大于或等于全局样式的权重时,才会覆盖全局的样式
全局配置
window
全局/页面常用配置项
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| navigationBarTitleText | String | 字符串 | 导航栏标题文字内容 |
| navigationBarBackgroundColor | HexColor | #000 | 导航栏背景颜色 |
| navigationBarTextStyle | String | white | 导航栏标题颜色,black / white |
| backgroundColor | HexColor | #fff | 窗口的背景色 |
| backgroundTextStyle | String | light | 下拉 loading 的样式,drak / light |
| enablePullDownRefresh | Boolean | false | 是否全局开启下拉刷新 |
| onReachBottomDistance | Number | 50 | 页面上拉触底事件触发时距页面底部距离,单位为 px |
tabBar
- tabBar 中只能配置最少 2 个、最多 5 个 tab 页签
- 当渲染顶部 tabBar 时,不显示 icon,只显示文本
节点配置项
| 属性 | 类型 | 必填 | 默认值 | 描述 | | —- | —- | —- | —- | —- | | position | String | 否 | bottom | tabBar 的位置,bottom / top | | borderStyle | String | 否 | black | tabBar 上边框的颜色,black / white | | color | HexColor | 否 | | tab 上文字的默认(未选中)颜色 | | selectedColor | HexColor | 否 | | tab 上文字选中时的颜色 | | backgroundColor | HexColor | 否 | | tabBar 的背景色 | | list | Array | 是 | | tab 页签的列表,最少2个、最多5个 |
tab 项的配置项
| 属性 | 类型 | 必填 | 描述 |
|---|---|---|---|
| pagePath | String | 是 | 页面路径,页面必须在 pages 中预先定义 |
| text | String | 是 | tab 上显示的文字 |
| iconPath | String | 否 | 未选中时的图标路径; 当前 position 为 top 时,不显示 icon |
| selectedIconPath | String | 否 | 选中时的图标路径; 当 position 为 top 时,不显示 icon |
网络数据请求
限制
- 只能请求 HTTPS 类型的接口
-
配置 request 合法域名
配置步骤
登录微信小程序管理后台
- 开发
- 开发设置
- 服务器域名
- 修改 request 合法域名
注意事项:
- 域名只支持 https 协议
- 域名不能使用 IP 地址或 localhost
- 域名必须经过 ICP 备案
- 服务器域名一个月内最多可申请 50 次修改
发起 GET 请求
<!-- index.wxml --><button type="primary" bindtap="getInfo">发起GET请求</button><!-- index.js -->Page({// 发起 GET 请求getInfo() {wx.request({url: 'https://api.muxiaoguo.cn/api/tiangourj?api_key=c342043936758a92',method: 'GET',success: (res) => {console.log(res);}})}})
发起 POST 请求
<!-- index.wxml --><button type="primary" bindtap="postInfo">发起POST请求</button><!-- index.js -->Page({// 发起 POST 请求postInfo() {wx.request({url: 'https://api.muxiaoguo.cn/api/tianqi?api_key=29abdbf534ebdca5',methosd: "POST",data: {type: 1,city: "南昌"},success(res) {console.log(res);}})}})
页面刚加载时请求数据
Page({onLoad(options) {// 调用 get 请求事件this.getInfo()}})
跳过 request 合法域名校验
- 开启后可暂时跳过 https 校验域名,请求 http 接口
跳过 request 合法域名校验的选项,仅在开发和调试阶段使用
页面导航
声明式导航(属性实现跳转)
概述
- 在页面上声明一个
<navigator>导航组件 -
导航 tabBar 页面
使用
<navigator>组件跳转到指定的 tabBar 页面时,需要指定 url 属性和 open-type 属性,其中:使用
<navigator>组件跳转到指定的非 tabBar 页面时,需要指定 url 属性和 open-type 属性,其中:- url 表示要跳转的页面地址,必须以 / 开头
- open-type 表示跳转的方式,必须为 navigate
在跳转的页面非 tabBar 页面时,可以省略
open-type="navigate"属性不写
<!-- 导航跳转至分类页 --><navigator url="/pages/contents/contents" open-type="navigate">导航至contents页</navigator>
后退导航
- 后退上一页面或多级页面,需要指定 delta 属性和 open-type 属性,其中:
- open-type 的值必须是 navigateBack,表示要进行后退导航
- delta 的值必须是数字,表示要后退的层级(默认值为 1)
如果只是后退至上一页面,delta 属性则可以省略不写,因为默认值就为 1 在 tabBar 页面中使用不会生效,只能在非 tabBar 页面使用法
<!-- 后退导航 --><navigator open-type="navigateBack" delta="1">返回上一页</navigator>
导航传参
- 参数和路径之间使用
?分隔 - 参数键和参数值用
=连接 不同参数用
&分隔<navigator url="/pages/contents/contents?name=smallfish&age=18">跳转 contents 页</navigator>
编程式导航(js实现跳转)
概述
-
导航 tabBar 页面
调用 wx.switchTab(Object Object) 方法,跳转至 tabBar 页面;其中 Object 的参数对象的属性列表如下: | 属性 | 类型 | 是否必选 | 说明 | | —- | —- | —- | —- | | url | string | 是 | 需要跳转的 tabBar 页面路径,路径后不能带参数 | | success | function | 否 | 接口调用成功的回调函数 | | fail | function | 否 | 接口调用失败的回调函数 | | complete | function | 否 | 接口调用结束的回调(调用成功、失败都会执行) |
<!-- 导航到 users 页 --><button type="primary" bindtap="gotoUsers">跳转至users页</button>// 导航到 users 页gotoUsers() {wx.switchTab({url: '/pages/users/users',})},
导航非 tabBar 页面
- 调用 wx.navigateTo(Object Object) 方法,可以跳转至非 tabBar 页面;其中 Object 参数对象的属性列表如下: | 属性 | 类型 | 是否必选 | 说明 | | —- | —- | —- | —- | | url | string | 是 | 跳转至非 tabBar 页面的路径,路径后可带参数 | | success | function | 否 | 接口调用成功的回调 | | fail | function | 否 | 接口调用失败的回调 | | complete | function | 否 | 接口调用结束的回调(调用成功、失败都会执行) |
<!-- 导航至 contents 页 --><button type="primary" bindtap="gotoContents">跳转 contents 页</button>// 导航至非 tabBar 页gotoContents() {wx.navigateTo({url: '/pages/contents/contents',})},
后退导航
- 调用 wx.navigateBack(Object Object) 方法,可以返回上一页或多页;其中 Object 参数对象的属性列表如下: | 属性 | 类型 | 默认值 | 是否必选 | 说明 | | —- | —- | —- | —- | —- | | delta | number | 1 | 否 | 返回的页面数,delta 大于现有页面数,则返回首页 | | success | function | | 否 | 接口调用成功的回调 | | fail | function | | 否 | 接口调用失败的回调 | | complete | function | | 否 | 接口调用结束的回调(调用成功、失败都会执行) |
如果只是后退至上一页面,delta 属性则可以省略不写,因为默认值就为 1 在 tabBar 页面中使用不会生效,只能在非 tabBar 页面使用
<!-- 返回上一页 --><button type="primary" bindtap="gotoBack">返回上一页</button>// 返回上一页gotoBack() {wx.navigateBack()},
导航传参
- 调用 wx.navigateTo(Object Object) 方法,可携带参数,示例如下: ```html
// 导航至非 tabBar 页 gotoContents() { wx.navigateTo({ url: ‘/pages/contents/contents?name=smallfish&age=18’, }) },
<a name="qMUyB"></a>## onLoad 接收导航参数```javascriptonLoad(options) {// options 就是导航传递的参数对象console.log(options)}
页面事件
实现下拉刷新
<view>下拉刷新效果</view><view>count:{{ count }}</view><button bindtap="addCount">count++</button>
Page({data: {count: 0},onPullDownRefresh() {this.setData({count: 0})// 关闭下拉刷新效果wx.stopPullDownRefresh()}})
实现上拉触底
配置上拉触底距离
- 小程序启动,生命周期开始
- 小程序关闭,生命周期结束
- 中间小程序运行的过程,就是小程序的生命周期

自动按次序执行
应用生命周期
- 小程序:启动 -> 运行 -> 销毁
在
app.js中进行声明,代码如下:App({// 小程序初始化完成时,执行此函数,全局只触发一次,做初始化工作onLaunch(options) {},// 小程序启动,或从后台进入前台显示时触发onShow(options) {},// 小程序从前台进入后台时触发onHide() {}})
页面生命周期
小程序:页面加载 -> 渲染 -> 销毁
在页面对应的
.js中进行声明:代码如下:Page({onLoad(options) {}, // 监听加载,一个页面只调用一次onShow() {}, // 监听页面显示onReady() {}, // 监听页面初次渲染完成,一个页面只调用一次onHide() {}, // 监听页面隐藏onUnload() {} // 监听页面卸载,一个页面只调用一次})
WXS脚本
WXS 是小程序独有的一套脚本语言,结合 WXML,可以构建出页面的结构
- wxs 不支持:let 、const 、解构赋值、展开运算符、箭头函数、对象属性简写等
module:模块的名称- src:模块的路径(相对路径)
- wxs 中定义的函数不能作为组件的事件回调函数
- wxs 不能调用 js 文件中定义的函数
- wxs 不能调用小程序提供的 API
- 在 ios 设备上,wxs 比 js 快 2~20倍
- 在 Android 设备上,二者的运行效率无差异
内联WXS脚本
<!-- m1 wxs模块 --><view class="title">m1 模块</view><view>{{ m1.toUpper(name) }}</view><!-- m1 wxs模块 --><wxs module="m1">module.exports.toUpper = function(str) {return str.toUpperCase()}</wxs>
外链WXS脚本
// xxx.wxml<!-- m2 wxs模块 --><view class="title">m2 模块</view><view>{{ m2.toLower(country) }}</view><!-- m2 wxs模块 --><wxs src="../../utils/tools.wxs" module="m2"></wxs>// utils/tools.wxsfunction toLower(str) {return str.toLowerCase()}module.exports = {toLower: toLower}
自定义组件
组件创建
- 在项目根目录中,创建
components文件夹 - 在新建的
components文件夹中新建你想要的组件文件夹 - 鼠标右键,点击组件文件夹,点击“新建Component”
- 输入组件名称后回车,会生成组件对应的 4 个文件,分别是
.js、.json、.wxml、.wxss为了保证目录结构清晰,把不同组件存放到单独的目录中
组件引用
局部引用
- 在页面的
.json配置文件中引用组件,示例如下:// 页面的 .json 文件中,引入组件```json{"usingComponents": {"test1": "/components/test1/test1"}}
// 在页面的 .wxml 文件中,使用组件
<test1></test1>
<a name="xKQUO"></a>### 全局引用- 在项目根目录下的`app.json`文件中,和`window`节点平级,新增`usingComponents`节点,示例如下:```markdown// 在 app.json 文件中,引入组件```json{"usingComponents": {"test1": "/components/test1/test1"}}
// xxx.wxml 文件中,使用组件
<test1></test1>
<a name="ruUP9"></a>## 全局和局部的区别- 组件的`.json`需要声明“component”: true 属性- 组件的`.js`调用的是 Component() 函数- 组件的事件处理函数需要定义到 methods 节点中<a name="etHcG"></a>## 样式隔离:stylelsolation:::danger注意点:1. app.wxss 中的全局样式对组件无效1. 只有 class 选择器有样式隔离效果,id、属性、标签选择器不受样式隔离的影响1. 在组件和引用组件的页面中建议使用 class 选择器,不要使用 id、属性、标签选择器:::- 防止组件内外样式互相干扰;有时,希望外界可以控制组件内部样式```javascript// 方法 1Component({options: {styleIsolation: 'isolated'}})
// 方法 2{"styleIsolation": "isolated"}
| 可选值 | 默认值 | 描述 |
|---|---|---|
| isolated | 是 | 启用样式隔离,在自定义组件内外,使用class 指定的样式将不会互相影响 |
| apply-shared | 否 | 页面 WXSS 样式将影响自定义组件,但自定义组件 WXSS 中的样式不会影响页面 |
| shared | 否 | 页面 WXSS 样式将影响自定义组件,自定义组件 WXSS 样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件 |
事件处理函数和自定义方法:methods
<view>count值是:{{ count }}</view><button type="primary" bindtap="addCount">count++</button>
Component({data: {count: 0},methods: {addCount() { // 事件处理函数this.setData({count: this.data.count + 1})this._showCount()},_showCount() { // 自定义方法,以 _ 开头wx.showToast({ // 弹窗方法title: 'count值为:' + this.data.count,icon: 'none'})}}
properties 和 data
- 类似于 Vue 中的 props
- 用于接收外界传递到组件中的数据
- properties 中的数据是可读写的
- properties 和 data 指向的是同一个对象
- data:存储组件私有数据
- properties:存储外界传递到组件中的数据
<test max="15"><test1>
Component({properties: {max: Number, // 简单定义类型max: { // 复杂定义类型type: Number,value: 10 // 默认值}},})
数据监听器:observers
<view>{{n1}} + {{n2}} = {{sum}}</view><button bindtap="addN1">n1 + 1</button><button bindtap="addN2">n2 + 1</button>
Component({data: {n1: 0,n2: 0,sum: 0},methods: {addN1() {this.setData({n1: this.data.n1 + 1})},addN2() {this.setData({n2: this.data.n2 + 1})},},observers: {'n1, n2': function(n1, n2) {this.setData({sum: n1 + n2})}}})
:::danger
observers中,如果键为对象,需要监听对象中的所有属性,可以使用
obj.**方法即可 :::纯数据字段
概念:不用于界面渲染的 data 字段
好处:有助于提升页面更新的性能
Component({options: {pureDataPattern: /^_/},data: {a: 0,_b: 10}})
组件的生命周期函数
Component({lifetimes: {created() {}, // 组件实例刚被创建时执行attached() {}, // 组件实例进入页面节点树时执行ready() {}, // 组件再视图层布局完成后执行moved() {}, // 组件实例被移动到节点树的另一个位置时执行detached() {}, // 组件实例被页面节点树移除时执行error(Object Error) {} // 组件方法抛出错误时执行}})
:::danger
created 执行时并不能使用 this.setData
attached 执行时可以使用 this.setData :::
组件所在页面的生命周期函数
Component({pageLifetimes: {show() {}, // 组件所在页面被展示时执行hide() {}, // 组件所在页面被隐藏时执行resize(size) {} // 组件所在页面尺寸变化时执行}})
插槽
<view><view>这是slots组件内部</view><slot></slot></view>
<slots><view>这是要插入到slots组件中的内容</view></slots>
使用多个插槽
Component({options: {multipleSlots: true // 在组件定义时的选项中启用了多 slot 支持}})
父子组件通信
属性绑定
父组件向子组件的指定属性设置数据,仅能设置JSON兼容的数据 ```html // pages/home/home.wxml
父组件中,count值为:{{ count }} —————————————
// components/attr/attr.wxml
```javascript// pages/home/home.jsPage({data: {count: 0},addCount() {this.setData({count: this.data.count + 1})}})// components/attr/attr.jsComponent({properties: {count: Number}})
事件绑定
- 子组件向父组件传递数据,可传递任何数据
在父组件的
js中,定义一个函数,这个函数将通过自定义事件的形式,传递给子组件Page({data: {count: 0},syncCount(e) {console.log(e.detail.value);}})
在父组件的
wxml中,通过自定义事件的形式,将步骤 1 中定义的函数引用,传递给子组件<emit count="{{count}}" bind:sync="syncCount"></emit>
在子组件的
js中,通过调用this.triggerEvent('自定义事件名称', {/*参数对象*/}),将数据发送到父组件<view>子组件的count值为:{{count}}</view><button type="primary" bindtap="addCount">count+1</button>
Component({properties: {count: Number},methods: {addCount() {this.setData({count: this.properties.count + 1})this.triggerEvent('sync', {value: this.properties.count})}}})
在父组件的
js中,通过e.detail获取到子组件传递过来的数据Page({syncCount(e) {this.setData({count: e.detail.value})},})
获取组件实例
- 父组件可通过 this.selectComponent(只能传class或id选择器) 获取子组件实例对象
这样可以直接访问子组件的任意数据和方法
<view>父组件的count值为:{{count}}</view><view>----------------------------</view><get-instance-obj bind:sync="syncCount" count="{{count}}" class="customA" id="cA"></get-instance-obj><button bindtap="getChild">获取子组件实例对象</button>
Page({data: {count: 0},syncCount(e) {this.setData({count: e.detail.value})},getChild() {const child = this.selectComponent('.customA')child.addCount()},})
<view>子组件的count值为:{{count}}</view><button bindtap="addCount">count++</button>
Component({properties: {count: Number},methods: {addCount() {this.setData({count: this.properties.count + 1})this.triggerEvent('sync', {value: this.properties.count})}}})
behaviors
在项目根目录下创建 behaviors 目录,并创建自己想要的 js 文件
- 在 js 文件中定义数据、属性、方法、生命周期等节点
- 在组件中使用 require 导入,在与 data 节点平级,创建 behaviors 节点,为一个数组,数组中的元素便是引入的变量名
module.exports = Behavior({behaviors: [], // 用来保存引入的其他 behaviorsproperties: { // 同组件属性myBehaviorProperty: {type: String}},data: { // 同组件数据myBehaviorData: {}},attached: function(){}, // 生命周期函数methods: { // 同自定义组件的方法myBehaviorMethod: function(){}}})
var myBehavior = require('my-behavior')Component({behaviors: [myBehavior] // 使用})
使用npm包
- 通过 miniprogram-api-promise 第三方包,实现 API Promise 化:
```javascript import { promisifyAll } from ‘miniprogram-api-promise’npm install --save miniprogram-api-promise@1.0.4
const wxp = wx.p = {} promisifyAll(wx, wxp)
- 通过额外的配置,将官方提供的、基于回调函数的异步 API,升级改造为基于 Promise 的异步 API,从而提高代码的可读性、维护性、避免回调地狱的问题- 调用 Promise 化之后的异步 API```html<van-button type="danger" bindtap="getInfo">vant按钮</van-button><script>async getInfo() {const { data: res } = await wx.p.request({method: 'GET',url: 'https://www.escook.cn/api/get',data: {name: 'zs',age: 18}})console.log(res)}</script>
安装使用 Vant Weapp
npm i @vant/weapp -S --productionnpm i @vant/weapp@1.3.3 -S --production
在项目根目录下右键打开 cmd 命令行窗口,运行如下命令:
# 创建一个 package.json 配置文件npm init -y# 在 app.json 中删除 style 节点
{..."setting": {..."packNpmManually": true,"packNpmRelationList": [{"packageJsonPath": "./package.json","miniprogramNpmDistDir": "./miniprogram/"}]}}
// 注册使用 vant 组件"usingComponents": {"van-button": "@vant/weapp/button/index"}
在开发者工具左上角的 工具 选项中,选择 构建 npm,打开右上角 详情,打开 本地设置,勾选 使用 npm 模块
自定义全局主题(app.wxss)
更多主题样式,请参考:主题配置文件
page{--button-danger-background-color: #c00000;--button-danger-border-color: #D60000;}
:::danger 以上变量皆是 Vant 组件库已经定义好的,作用域组件的样式 :::
全局数据共享 Mobx
- mobx-miniprogram:创建 Store 实例对象
- mobx-miniprogram-bindings:把 Store 中的共享数据或方法,绑定到组件或页面中使用
安装
npm install --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1
创建 Store 实例
```javascript // store/store.js
import { action, observable } from ‘mobx-miniprogram’
export const store = observable({ // 数据字段 numA: 1, numB: 2, // 计算属性 get sum() { return this.numA + this.numB }, // action 方法,用来修改 store 中的数据 updateNum1: action(function (step) { this.numA += step }), updateNum2: action(function (step) { this.numB += step }) })
<a name="uHOPl"></a>## 绑定实例到页面```html// 页面的 .wxml 文件<view>{{numA}} + {{numB}} = {{sum}}</view><van-button type="primary" bindtap="btnHandler1" data-step="{{1}}">numA + 1</van-button><van-button type="danger" bindtap="btnHandler1" data-step="{{-1}}">numA + 1</van-button>// 页面的 .js 文件<script>import { createStoreBindings } from 'mobx-miniprogram-bindings'import { store } from '../../store/store'Page({btnHandler1(e) {this.updateNum1(e.target.dataset.step)},onLoad() {this.storeBindings = createStoreBindings(this, {store, // 数据源fields: ['numA', 'numB', 'sum'], // 数据字段actions: ['updateNum1'] // 方法})},onUnload() {this.storeBindings.destroyStoreBindings()}})</script>
绑定到组件
// numbers.wxml 组件<view>{{numA}} + {{numB}} = {{sum}}</view><van-button type="primary" bindtap="btnHandler2" data-step="{{1}}">numB + 1</van-button><van-button type="danger" bindtap="btnHandler2" data-step="{{-1}}">numB + 1</van-button>// numbers.js 组件<script>import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'import { store } from '../../store/store'Component({behaviors: [storeBindingsBehavior],storeBindings: {store,fields: {numA: 'numA',numB: 'numB',sum: 'sum'},actions: {updateNum2: 'updateNum2'}},methods: {btnHandler2(e) {this.updateNum2(e.target.dataset.step)</script>
分包
概念:
把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载
好处:
- 主包:包含 启动页面 或 tabBar 页面,以及所有分包都需要用到的公共资源
- 分包:只包含当前分包有关的页面和私有资源
加载规则
- 小程序启动时,默认会下载主包并启动主包内页面
- tabBar 页面需要放到主包中
当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后在进行展示
主包无法引用独立分包内的私有资源
- 独立分包之间,不能相互引用私有资源
- 独立分包和普通分包之间,不能相互引用私有资源
- 独立分包中不能引用主包内的公共资源
:::
分包预下载
- 进入小程序的某个页面时,由框架自动预下载可能需要的分包,从而提升进入后续分包页面时的启动速度
{"preloadRule": { // 分包预下载的规则"pages/classify/classify": { // 触发分包预下载的页面路径// 指定的网络模式下进行预下载// 默认值为:wifi// all 为不限网络"network": "all",// 进入页面后,预下载哪些分包// 可通过 root 或 name 指定预下载的分包"packages": ["pkgA"]}},}

