概述

项目结构

小程序的项目结构

  • 目录pages:存放所有小程序的页面
  • 目录utils:用来存放工具性质的模块(如格式化时间的自定义模块)
  • app.js :小程序项目的入口文件
  • app.json:小程序项目的全局配置文件
  • app.wxss:全局样式文件
  • project.config.json:配置文件
  • sitemap.json:配置小程序页面是否允许被微信索引。

存放在pages目录下的每个页面,都由四个基本文件组成:

  • .js文件 —— 存放页面的数据,事件处理函数等
  • .json文件 —— 配置文件,配置窗口外观等
  • .wxml文件 —— 结构文件
  • .wxss文件 —— 样式表文件

app.json

app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、窗口外观、界面表现、底部 tab 等。

  • pages:用来记录当前小程序所有页面的路径,首页为排第一位的页面。
  • window:全局定义小程序所有页面的背景色、文字颜色等
  • style:全局定义小程序组件所使用的样式版本
  • sitemapLocation:用来指明 sitemap.json 的位置
  • tabbar:定义底部tab,设置页面路径,名字,选中与未选中样式图表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
"pages": [
"pages/personal/personal",
"pages/index/index",
"pages/video/video"
],
"style": "v2",
"sitemapLocation": "sitemap.json",
"window": {
"navigationBarBackgroundColor": "#d43c33",
"navigationBarTextStyle": "white",
"navigationBarTitleText": "云音乐"
},
"tabBar": {
"color": "#333",
"selectedColor": "#d43c33",
"backgroundColor": "#fff",
"list": [
{
"pagePath": "pages/index/index",
"text": "主页",
"iconPath": "static/images/tabs/tab-home.png",
"selectedIconPath": "static/images/tabs/tab-home-current.png"
},
{
"pagePath": "pages/video/video",
"text": "视频",
"iconPath": "static/images/tabs/select.png",
"selectedIconPath": "static/images/tabs/selected.png"
},
{
"pagePath": "pages/personal/personal",
"text": "个人中心",
"iconPath": "static/images/tabs/tab-my.png",
"selectedIconPath": "static/images/tabs/tab-my-current.png"
}
]
}
}

project.config.json

project.config.json 是项目配置文件,用来记录我们对小程序开发工具所做的个性化配置,例如:

  • setting 中保存了编译相关的配置
  • projectname 中保存的是项目名称
  • appid 中保存的是小程序的账号 ID

sitemap.json

sitemap.json 文件用来配置小程序页面是否允许 微信索引。

当开发者允许微信索引时,微信会通过爬虫的形式,为小程序的页面内容建立索引。当用户的搜索关键字和页 面的索引匹配成功的时候,小程序的页面将可能展示在搜索结果中。

1
2
3
4
5
6
7
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}

注意:sitemap 的索引提示是默认开启的,如需要关闭 sitemap 的索引提示,可在小程序项目配置文件 project.config.json 的 setting 中配置字段 checkSiteMap 为 false

WXML模板

WXML(WeiXin Markup Language)是小程序框架设计的一套标签语言,类似于HTML。

区别:

  • 标签名称不同
    • HTML (div, span, img, a)
    • WXML(view, text, image, navigator)
  • 属性节点不同
    • <a href=”#”>超链接</a>
    • <navigator url=”#”></navigator>
  • 提供了类似于 Vue 中的模板语法
    • 数据绑定
    • 列表渲染
    • 条件渲染

WXSS样式

是一套样式语言,与CSS的区别:

  • 新增rpx尺寸单位: rpx能在不同大小屏幕上的小程序自动进行换算。
  • 提供全局的样式和局部样式
    • 项目根目录的app.wxss会作用于所有小程序页面。
    • 局部页面的 .wxss样式仅对当前页面生效。
  • WXSS仅支持部分CSS选择器
    • .class 和 #id
    • element
    • 并集选择器 选择器1,选择器2{css} 、后代选择器 选择器1 选择器2 {css}
    • ::after 和 ::before 等伪类选择器

宿主环境

宿主环境指的是程序运行所必须的依赖环境。微信是小程序的宿主程序,借助微信,小程序可以:微信扫码、微信支付、微信登录、地理定位、etc…

小程序宿主环境包含:通信模型,运行机制,组件,API

通信模型

小程序通信的主体是渲染层和逻辑层。

  • WXML模板和WXSS样式工作在渲染层;
  • JS脚本工作在逻辑层

渲染层与逻辑层之间,逻辑层与第三方服务器间的通信,都是由微信帮忙转发的。

运行机制

小程序启动过程:

  1. 把小程序的代码包下载到本地
  2. 解析 app.json 全局配置文件
  3. 执行 app.js 小程序入口文件,调用 App() 创建小程序实例
  4. 渲染小程序首页
  5. 小程序启动完成

页面渲染过程:

  1. 加载解析页面的 .json 配置文件
  2. 加载页面的 .wxml 模板和 .wxss 样式
  3. 执行页面的 .js 文件,调用 Page() 创建页面实例
  4. 页面渲染完成

组件

小程序组件由宿主环境提供,有9大类:

  • 视图容器
  • 基础内容
  • 表单组件
  • 导航组件
  • 媒体组件
  • map地图组件
  • canvas画布组件
  • 开放能力
  • 无障碍访问

视图容器

view

  • 普通视图区域,类似HTML的div,是块级元素。

scroll-view

  • 可滚动的视图区域,可实现滚动列表

  • ```html

    A B C
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    ```css
    .view3 {
    border: 1px solid red;
    height: 100px;
    width: 220px;
    white-space: nowrap; /* scroll-x生效需要的样式,-y不用 */
    }
    .view3 view{
    display: inline-block;/* scroll-x生效需要的样式,-y不用 */
    }

swiper和swiper-item

  • 轮播图组件,和其中的 item组件

  • 常用属性:

    属性 类型 默认值 说明
    indicator-dots boolean false 是否显示面板指示点
    indicator-color color rgba(0,0,0,3) 指示点颜色
    indecator-active-color color #000000 当前选中的指示点颜色
    autoplay boolean false 是否自动切换
    interval number 5000 自动切换时间间隔
    circular boolean false 是否采用衔接滑动
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <swiper class="swiper1" indicator-dots>
    <swiper-item>
    <view>A</view>
    </swiper-item>
    <swiper-item>
    <view>B</view>
    </swiper-item>
    <swiper-item>
    <view>B</view>
    </swiper-item>
    </swiper>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    .swiper1 {
    height: 150px;
    }
    .swiper1 view{
    height: 100%;
    line-height: 150px;
    text-align: center;
    }
    swiper-item:nth-child(1) {
    background-color: lightgreen;
    }
    swiper-item:nth-child(2) {
    background-color: lightskyblue;
    }
    swiper-item:nth-child(3) {
    background-color: lightcoral
    }

基础内容

text

  • 文本组件,类似HTML的span标签,是行内元素。

  • 加上selectable元素,可以让文本能被长按选中。

    1
    <text selectable>长按选中</text>

rich-text

  • 富文本组件,通过nodes属性,能把HTML字符串渲染为WXML结构。

    1
    <rich-text nodes="<h1>标题</h1>"></rich-text></rich-text>

其他常用组件

button

  • 按钮组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <!-- 通过type指定类型 -->
    <button>默认按钮</button>
    <button type="primary">主色调按钮</button>
    <button type="warn">警告按钮</button>
    <!-- size="mini" 小尺寸按钮 -->
    <button size="mini">默认小尺寸</button>
    <button type="primary" size="mini">主色调小尺寸</button>
    <button type="warn" size="mini">警告小尺寸</button>
    <!-- plain 镂空按钮 -->
    <button size="mini" plain>默认镂空按钮</button>
    <button type="primary" size="mini" plain>主色调镂空按钮</button>
    <button type="warn" size="mini" plain>警告镂空按钮</button>

image

  • 图片组件,默认宽300px,高240px

    1
    <image src="/images/1.png"></image>

    image组件的mode属性可以指定图片的裁剪和缩放模式:

    mode值 说明
    scaleToFill (默认值)缩放模式,不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素
    aspectFit 缩放模式,保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。
    aspectFill 缩放模式,保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方 向是完整的,另一个方向将会发生截取。
    widthFix 缩放模式,宽度不变,高度自动变化,保持原图宽高比不变
    heightFix 缩放模式,高度不变,宽度自动变化,保持原图宽高比不变

navigator

  • 页面导航组件,相当于HTML的a链接

API

分为3类:

  • 事件监听api

    特点:以on开头,用来监听某些事件的触发。

  • 同步api:以Sync结尾的api,可以通过函数返回值直接获取,如果执行出错会抛出异常。

  • 异步api:类似 JQuery 中的 $.ajax(options) 函数,需要通过success,fail,complete接收调用

模板与配置

WXML模板语法

事件绑定

  • 数据绑定的基本原则:

    1. 在data中定义数据;

      1
      2
      3
      4
      5
      6
      7
      Page({
      // 页面的初始数据
      data: {
      info: 'init data',
      msgList: [{msg: 'hello'}, {msg: 'world'}]
      }
      })
    2. 在WXML中使用数据;

      1
      <view>{{ 要绑定的数据名称 }}</view>

    关于Mustache语法,即 { { } }:

    • 绑定内容

      1
      2
      3
      4
      5
      Page({
      data: {
      info: 'init data'
      }
      })
      1
      <view>{{ info }}</view>
    • 绑定属性

      1
      2
      3
      4
      5
      Page({
      data: {
      imgSrc: 'www.baidu.com/images/logo.png'
      }
      })
      1
      <image src="{{imgSrc}}"></image>
    • 运算

      1
      2
      3
      4
      5
      Page({
      data: {
      randomNum: Math.random * 10
      }
      })
      1
      <view>{{ randomNum > 5 ? '大于5' : '小于5' }}</view>
  • 事件绑定

    常用的事件:

    类型 绑定方式 事件描述
    tap bindtap 或 bind:tap 手指触摸后离开,类似于HTML的click
    input bindinput 或 bind:input 文本框的输入事件
    change bindchange 或 bind:change 状态改变时触发

    事件对象的属性列表:

    属性 类型 说明
    type String 事件类型
    timeStamp Integer 页面打开到触发所要经过的毫秒数
    target Object 触发事件的组件的一些属性值集合
    currentTarget Object 当前组件的一些属性值集合
    detail Object 额外的信息
    touches Array 触摸事件,当前停留在屏幕中的触摸点信息的数组
    changedTouches Array 触摸事件,当前变化的触摸点信息的数组

    target 和 currentTarget:

    • target是触发该事件的源头组件,currentTarget则是当前事件所绑定的组件。
    • 当点击内部的按钮时,事件会以冒泡的方式向外扩散, e.target是内部被点击的按钮组件, e.currentTarget 外部正在触发事件的那个组件。
    • bindtap

      点击事件

      1
      <button bindtap="btnTapHandler">按钮</button>

      在js中对应的事件处理函数:

      1
      2
      3
      4
      5
      Page({
      btnTapHandler(e){
      console.log(e)
      }
      })
    • 事件处理中为data中的数据赋值:

      要调用this.setData()

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      Page({
      data: {
      count: 0
      }
      changeCount(){
      this.setData({
      count: this.data.count + 1
      })
      }
      })
    • *事件传参 data-:

      小程序中,不能在绑定事件的同时为函数传参。 要使用 data-* 自定义属性来传参,其中 * 号是参数的名字。

      1
      <button bindtap="btnTapHandler" data-count="{{2}}">按钮</button>

      count会被解析为参数的名字,数值2为参数的值。

      函数接收:通过 event.target.dataset.参数名 即可获取具体参数的值。

      1
      2
      3
      4
      5
      btnTapHandler(e){
      //event.target.dataset 是一个对象,包含了所有 data-* 传递的参数项
      console.log(event.target.dataset)
      console.log(event.target.dataset.count)
      }
    • bindinput

      文本框输入事件

      1
      <input bindinput="inputHandler"><input>
      1
      2
      3
      inputHandler(e){
      console.log(e.detail.value)
      }

      实现文本框和data之间的数据同步:

      1
      <input value="{{msg}}" bindinput="inputHandler"><input>
      1
      2
      3
      4
      5
      inputHandler(e){
      this.setData({
      mag: e.detail.value
      })
      }

条件渲染

  1. wx:if

使用 wx:if=”“ 来判断是否需要渲染该代码块。

1
2
3
<view wx:if="{{type === 1}}">男</view>
<view wx:elif="{{type === 2}}">女</view>
<view wx:else>保密</view>
  1. 结合 <block> 使用 wx:if

    如果要一次性控制多个组件的展示/隐藏,可以用 <block> 包起来。

    1
    2
    3
    4
    <block wx:if="{{true}}">
    <view>xx</view>
    <view>zz</view>
    </block>

    <block> 不是组件,只起包裹作用,不会被渲染。

  2. hidden

    使用 hidden=”“ 也能控制元素的显示与隐藏

    1
    <view hidden="{{条件}}">true隐藏,false显示</view>

    不同之处:

    • wx:if 以动态创建和移除元素的方式,控制元素的展示与隐藏 。
    • hidden 以切换样式的方式(display: none/block;)控制元素的显示与隐藏。

    建议:

    • 频繁切换时,建议使用 hidden
    • 控制条件复杂时,建议使用 wx:if 搭配 wx:elif、wx:else 进行展示与隐藏的切换
  3. wx:for

    指定数组,然后循环渲染重复的组件结构

    1
    <view wx:for="{{array}}"></view>

    默认情况下,当前的索引用index表示,当前循环项用item表示。

    也可以指定index和item:

    1
    <view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName"></view>

    wx:key —— 实现列表渲染时,建议为列表项指定唯一的key值,能提高渲染效率。

    1
    2
    3
    4
    5
    6
    7
    data: {
    userList: [
    {id: 1, name: 'tom'},
    {id: 2, name: 'army'},
    {id: 3, name: 'jack'},
    ]
    }
    1
    <view wx:for="{{userList}}" wx:key="id">{{item.name}}</view>

WXSS模板

与css的区别:

  • rpx尺寸单位

    —— 将所有设备屏幕从宽度上等分为750份,一份即为1rpx;

  • @import 样式导入

    1
    @import "外联样式表的路径";

全局配置

app.json 是小程序的全局配置文件,常见配置如下:

  • pages:用来记录当前小程序所有页面的路径,首页为排第一位的页面。
  • window:全局定义小程序所有页面的背景色、文字颜色等。
  • style:是否启用新版的组件样式。
  • sitemapLocation:用来指明 sitemap.json 的位置。
  • tabbar:定义顶部或底部的tabBar,用于多页面的快速切换,最少设置2个,最多5个,设置页面路径,名字,选中与未选中样式图表。

window节点常用配置项:

属性名 类型 默认值 说明
navigationBarTitleText String 字符串 导航栏标题文字内容
navigationBarBackgroundColor HexColor #000000 导航栏背景颜色
navigationBarTextStyle String white 导航栏标题颜色,仅可用blcak和white
backgroundColor HexColor #fffff 窗口的背景色
backgroundTextStyle String dark 下拉loading的样式,仅可用dark和light
enablePullDownRefresh Boolean false 是否全局开启下拉刷新
onReachBottomDistance Number 50 页面上拉触底事件触发时据页面底部距离,单位为px
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
"pages": [
"pages/personal/personal",
"pages/index/index",
"pages/video/video"
],
"style": "v2",
"sitemapLocation": "sitemap.json",
"window": {
"navigationBarBackgroundColor": "#d43c33",
"navigationBarTextStyle": "white",
"navigationBarTitleText": "云音乐"
},
"tabBar": {
"position": "bottom",
"color": "#333",
"selectedColor": "#d43c33",
"backgroundColor": "#fff",
"borderStyle": "black", //上边框颜色
"list": [
{
"pagePath": "pages/index/index",
"text": "主页",
"iconPath": "static/images/tabs/tab-home.png",
"selectedIconPath": "static/images/tabs/tab-home-current.png"
},
{
"pagePath": "pages/video/video",
"text": "视频",
"iconPath": "static/images/tabs/select.png",
"selectedIconPath": "static/images/tabs/selected.png"
},
{
"pagePath": "pages/personal/personal",
"text": "个人中心",
"iconPath": "static/images/tabs/tab-my.png",
"selectedIconPath": "static/images/tabs/tab-my-current.png"
}
]
}
}

网络数据请求

处于安全考虑,小程序对数据接口的请求有以下限制:

  1. 只能请求HTTPS类型的接口;

  2. 必须将接口域名添加到信任列表;

    需要登录到小程序后台管理界面, 在开发—开发设置—服务器域名—修改request合法域名(只支持https,不能用ip,需经过ICP备案)

GET请求 —— 调用 wx.request()

1
2
3
4
5
6
7
8
9
10
11
12
wx.request({
url: 'https://xxx',
method: 'GET',
data:{
name: 'Tom',
age: 22
},
//请求成功后的回调函数
success:(res) => {
console.log(res)
}
})

POST请求 —— 调用 wx.request()

1
2
3
4
5
6
7
8
9
10
11
12
wx.request({
url: 'https://xxx',
method: 'POST',
data:{
name: 'Tom',
age: 22
},
//请求成功后的回调函数
success:(res) => {
console.log(res)
}
})

在页面刚加载时就请求数据: onLoad事件

1
2
3
4
5
6
Page({
// 生命周期函数--监听页面加载
onLoad: function (options) {

}
}

视图逻辑

页面导航

页面导航: 页面间的相互跳转。小程序实现页面导航有两种方式:

  1. 声明式导航: 通过<navigator>导航组件实现跳转。
  2. 编程式导航:调用导航API。

声明式导航

  • 导航到 tabBar页面:

    <navigator>需要指定url和open-type属性。其中 url 以 / 开头, oprn-type 只能指定switchTab为跳转方式。

    1
    <navigator url="/pages/message/message" open-type="switchTab">导航到消息页面</navigator>
  • 导航到 非tabBar页面:

    <navigator>需要指定url和open-type属性。open-type 只能指定navigate为跳转方式。(open-type属性可省略)

    1
    <navigator url="/pages/info/info" open-type="navigate">导航到info页面</navigator>
  • 后退导航

    <navigator>需要指定open-type和delta属性。 其中open-type必须为 navigateBack,delta的值为后退的层级。(如果只退1级,delta可省略)

    1
    <navigator open-type="navigateBack" delta='1'>返回上一页</navigator>

编程式导航

  • 导航到 tabBar页面

    调用 wx.switchTab(Object o) 方法,可跳转到 tabBar页面。参数对象的属性如下:

    属性 类型 时候必选 说明
    url string 是 需要跳转的tabBar页面路径,路径不能带参数
    success function 否 接口调用成功的回调函数
    fail function 否 失败时的回调函数
    compiete function 否 结束时的回调函数(一定会执行)
    1
    2
    3
    <button bindtap="gotoMessage">
    跳转到消息页面
    </button>
    1
    2
    3
    4
    5
    gotoMessage(){
    wx.switchTab({
    url: '/pages/message/message'
    })
    }
  • 导航到非tabBar页面

    调用 wx.navigateTo(Object o) ,参数对象的属性与 wx.switchTab() 一样,不过url属性能携带参数。

    1
    2
    3
    <button bindtap="gotoInfo">
    跳转到info页面
    </button>
    1
    2
    3
    4
    5
    gotoInfo(){
    wx.navigateTo({
    url: '/pages/info/info'
    })
    }
  • 后退导航

    调用 wx.navigateBack(Object o)方法。

    1
    2
    3
    <button bindtap="goBack">
    后退
    </button>
    1
    2
    3
    4
    5
    goBack(){
    wx.navigateBack({
    delta: 1
    })
    }

导航传参

  • navigator组件的 url 的路径后可以携带参数。
1
<navigator url="/pages/info/info?name=Tom&age=20">跳到info页面</navigator>
  • 调用 wx.navigateTo(Object o) 时,url属性也能携带参数。

页面事件

  • 下拉刷新:

    • 全局开启:在app.json 的window节点中, 将enablePullDownRefresh 设置为 true。
    • 局部开启:页面的 .json文件中,同样将window节点中的 enablePullDownRefresh 设置为 true。

    还可以通过 backgroundColor 配置下拉刷新窗口颜色,和 backgroundTextStyle 配置下来刷新loadin的样式(dark和light)

    监听:通过 onPullDownRefresh() 可监听当前页面的下拉刷新事件。

    停止下拉属性效果: 刷新结束后,下拉的loading效果仍会一直闲置,需要调用 wx.stopPullDownRefresh() 来停止刷新效果。

    1
    2
    3
    4
     onPullDownRefresh: function () {
    ....
    wx.stopPullDownRefresh()
    },
  • 上拉触底

    通过上拉滑动,而加载更多数据。

    监听:通过 onReachBottom() 函数可监听页面的上拉触底事件。

    上拉触底距离: 在.json文件中,通过 onReachBottomDistance 属性来设置,默认为50px;

生命周期

应用生命周期函数,在app.js中声明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
App({
//当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
onLaunch: function () {

},

//当小程序启动,或从后台进入前台显示,会触发 onShow
onShow: function (options) {

},

//当小程序从前台进入后台,会触发 onHide
onHide: function () {

},

//当小程序发生脚本错误,或者 api 调用失败时,会触发 onError 并带上错误信息
onError: function (msg) {

}
})

页面声明周期函数,在页面的 .js文件中声明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Page({
// 页面的初始数据
data: {

},

//生命周期函数--监听页面加载
onLoad: function (options) {

},

//生命周期函数--监听页面初次渲染完成
onReady: function () {

},

//生命周期函数--监听页面显示
onShow: function () {

},

//生命周期函数--监听页面隐藏
onHide: function () {

},

//生命周期函数--监听页面卸载
onUnload: function () {

},

//页面相关事件处理函数--监听用户下拉动作
onPullDownRefresh: function () {

},

//页面上拉触底事件的处理函数
onReachBottom: function () {

},

//用户点击右上角分享
onShareAppMessage: function () {

}
})

WXS脚本

WXS(WeiXin Script)是小程序独有的一套脚本语言。

自定义组件

创建和引用

创建组件: 在根目录的components下,新建组件文件夹。

引用组件:局部引用 / 全局引用,都是在 .json 文件中进行引用:

1
2
3
4
5
{
"usingComponents": {
"my-test1": "/components/test1/test1"
}
}

在 .wxml 中使用

1
<my-test1></my-test1>

组件和页面的区别:

  • 组件的 .json文件 中需要声明 “component”: true
  • 组件的 .js文件中调用的是Component()函数
  • 组件的事件处理函数需要定义到methods节点中。

样式隔离

组件的样式隔离:

  • 默认情况下,不同组件间、组件与调用者间的样式不会相互影响;

  • app.wxss中的全局样式对组件无效;

  • 只有class选择器会有样式隔离效果, 而 id选择器、属性选择器、标签选择器不受样式隔离的影响。

    建议在组件和引用组件的页面中使用class选择器,不要用其他选择器,以避免干扰。

  • 修改组件的隔离性:在组件的 .js文件或 .jsonwen文件中通过 styleIsolation修改组件的样式隔离选项。

    1
    2
    3
    4
    5
    Component({
    options: {
    styleIsolation: 'isolated'
    }
    })
    1
    2
    3
    {
    "styleIsolation": "isolated"
    }

    styleIsolation的可选值:

    可选值 默认值 描述
    isolated 是 启动隔离样式,组件内外,使用class指定的样式不会相互影响
    apply-shared 否 页面的样式将影响自定义组件,而组件不会影响页面
    shared 否 会相互影响,也会影响其他设置了apply-shared或shared的组件

组成

  • data数据:组件的私有数据;

    1
    2
    3
    4
    5
    component({
    data: {
    count: 0
    }
    })
  • methods方法 :事件处理函数和自定义方法需要定义到methods节点中;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Component({
    methods:{
    addCount(){ //事件处理函数

    },
    _showCount(){ //自定义函数,建议以 _ 开头

    }
    }
    })
  • properties属性 :用来接收外界传递进来的数据;

    properties属性和data数据本质是一样的,只是用途不一样。 properties中的属性同样可用 setData 重新赋值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Component({
    properties: {
    //完整定义属性的方式(需要默认值时)
    max: {
    type: Number, //数据类型
    value: 10 //默认值
    },
    //简化定义(不需要默认值时)
    max: Number
    }
    })

数据监听器

数据监听器:监听和响应任何属性和数据的变化,并执行操作。

1
2
3
4
5
6
7
Component({
observers: {
'字段A, 字段B': function(接收A的新值, 接收B的新值){
....
}
}
})

用法例子:

1
2
3
<view>{{n1}}+{{n2}}-{{sum}}</view>
<button size="mini" bindtap="addN1">n1自增</button>
<button size="mini" bindtap="addN2">n2自增</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Component({
data: {
n1:0,
n2:0,
sum:0
},
methods: {
addN1(){
this.setData({
n1: this.data.n1 + 1
})
},
daaN2(){
this.setData({
n2: this.data.n2 + 1
})
}
},
observers: { //数据监听节点
'n1, n2': function(n1,n2){
this.setData({
sum: n1 + n2
})
}
}

})

数据监听器还支持监听对象中单个或多个属性的变化,语法如下:

1
2
3
4
5
6
7
8
Component({
observers:{
//使用setData为对象.属性A/B,或者为整个对象赋值时,都会触发此监听器
'对象.属性A, 对象.属性B': function(A新值, B新值){
...
}
}
})

纯数据字段

纯数据字段:指那些不用于界面渲染的data字段。(即不展现在界面上,也不传递给其他组件,仅仅在组件内部使用)

优势:纯数据字段有助于提升页面更新的性能。

使用规则:在 Component 构造器的 options 节点中,指定 pureDataPattern 为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段

1
2
3
4
5
6
7
8
9
10
Component({
options: {
//指定所有 _ 开头的数据字段为纯数据字段。
pureDataPattern: /^_/
},
data: {
a: true, //普通数据
_b: true, //纯数据字段
}
})

组件的生命周期

生命周期函数 参数 描述说明
created 无 在组件实例刚刚被创建时执行
attached 无 组件实例进入页面节点时执行
ready 无 组件在视图层布局完成后执行
moved 无 组件实例被移动到节点树另一个位置时执行
datached 无 在组件实例从页面节点数移除时执行
error Object Error 每当组件方法抛出错误时执行

重要的三个生命函数:

  • 组件实例刚被创建好的时候,created 生命周期函数会被触发

    • 此时还不能调用 setData

    • 通常在这个生命周期函数中,只应该用于给组件的 this 添加一些自定义的属性字段

  • 在组件完全初始化完毕、进入页面节点树后, attached 生命周期函数会被触发

    • 此时, this.data 已被初始化完毕
    • 这个生命周期很有用,绝大多数初始化的工作可以在这个时机进行(例如发请求获取初始数据)
  • 在组件离开页面节点树后, detached 生命周期函数会被触发

    • 退出一个页面时,会触发页面内每个自定义组件的 detached 生命周期函数
    • 此时适合做一些清理性质的工作

定义: 在 lifetimes 内定义生命周期函数(推荐,lifetimes优先级最高)

1
2
3
4
5
6
7
8
9
10
Component({
//推荐用法
lifetimes: {
attached(){},
detached(){},
},
//旧时的定义方法,不推荐
attached(){},
datached(){},
})

组件所在页面的生命周期

当自定义组件的行为依赖于页面状态的变化时,就需要用到组件所在页面的生命周期。

组件所在页面的生命周期有三种:

生命周期函数 参数 描述
show 无 组件所在页面 被展示时执行
hide 无 组件所在页面 被隐藏时执行
resize Object Size 组件所在页面 尺寸变化时执行

定义在 pageLifetimes 节点:

1
2
3
4
5
6
7
Component({
pageLifetimes: {
show: function(){},
hide: function(){},
resize: function(size){}
}
})

插槽

在组件的wxml结构中,可以提供一个 <slot>节点(即 插槽),用于承载组件使用者提供的wxml结构。

也就是,使用者可以将自定义的wxml结构插入组件的<slot>节点位置。

语法:

  • 单个插槽: 默认每个组件只能使用一个<slot>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <!-- 组件 -->
    <view class="wrapper">
    <view>组件内容</view>
    <!-- 对于不确定的内容,使用插槽占位,实际内容由使用者决定 -->
    <slot></slot>
    </view>

    <!-- 组件的使用者 -->
    <component-tag-name>
    <!-- 定义slot处的内容 -->
    <view>这里的内容是要插入到slot位置处的</view>
    </component-tag-name>
  • 多个插槽: 需在.js文件中启用配置。

    1
    2
    3
    4
    5
    6
    Component({
    options: {
    multipleSlots: true //启用多slot支持
    },
    ...
    })
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!-- 组件 -->
    <view class="wrapper">
    <!-- 使用name属性区分不同slot -->
    <slot name="slot1"></slot>
    <view>组件内容</view>
    <slot name="slot2"></slot>
    </view>

    <!-- 组件的使用者 -->
    <component-tag-name>
    <!-- 定义slot处的内容 -->
    <view slot="slot1">内容1</view>
    <view slot="slot2">内容2</view>
    </component-tag-name>

父子组件间的通信

父子组件之间通信的3种方式

  1. 属性绑定 —— 父向子传值,向子组件的指定属性设置数据。只能传递普通类型数据,无法传递方法。

    例子:父组件:

    1
    2
    3
    data: {
    count: 0
    }
    1
    2
    <my-test count="{{count}}"></my-test>
    <view>父组件中,count值为:{{count}}</view>

    子组件:

    1
    2
    3
    4
    // 子组件的properties节点
    properties: {
    count: Number
    }
    1
    <text>子组件中,count值为{{count}}</text>
  2. 事件绑定 —— 子向父传值,可以传递任何类型数据。

    • 父组件的js中,定义一个要传给子组件的函数;

      1
      2
      3
      syncCount(){

      }
    • 父组件的wxml中,通过自定义事件将函数传给子组件;

      1
      2
      3
      4
      <!-- bind: 后写自定义事件名称 -->
      <my-test bind:sync="syncCount"></my-test>
      <!-- 或在bind后直接写事件名称 -->
      <my-test bindsync="syncCount"></my-test>
    • 子组件的js中,通过 this.triggerEvent(‘事件名’, {参数对象}),将数据发给父组件;

      1
      2
      3
      4
      5
      6
      7
      8
      methods: {
      addCount(){
      this.setData({
      count: this.properties.count + 1
      })
      this.triggerEvent('sync',{value:this.properties.count})
      }
      }
    • 父组件的js中,在那个函数中通过e.detail获取数据;

      1
      2
      3
      4
      5
      syncCount(){
      this.setData({
      count: e.detail.value
      })
      }
  3. 获取组件实例

    在父组件里调用 this.selectComponent(“id/class选择器”),获取子组件的实例对象,从而直接访问子组件的任何数据和方法。 调用时需要传入一个选择器。

    1
    2
    3
    4
    <my-test class="customA" id="cA"></my-test>
    <button bindtap="getChild">
    获取子组件实例
    </button>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    getChild(){
    const child = this.selectComponent('.customA') //也可以传递id选择器 #cA
    //调用子组件的setData方法
    child.setData({
    count: child.properties.count + 1
    })
    //调用子组件的addCount方法
    child.addCount()
    }

behaviors

behaviors 用于实现组件间代码共享。

每个 behavior 可以包含一组属性、数据、生命周期函数和方法。组件引用它时,它的属性、数据和方法会被合并到组件中。

每个组件可以引用多个 behavior,behavior 也可以引用其它 behavior。

使用:

  • 创建behavior

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //调用Behavior()方法,创建实例对象
    //使用module.exports将对象共享出去
    module.exports = Behavior({
    //属性节点
    properties: {},
    //私有数据节点
    data: { username: 'zs'},
    //事件处理函数和自定义方法节点
    methods: {},
    //其他节点...
    })
  • 导入并使用behavior

    在组件中,使用require()方法导入需要的behavior,挂在后就可以访问了。

    1
    2
    3
    4
    5
    6
    const myBehavior = require("../../behaviors/my-behavior")

    Component({
    behaviors: [myBehavior],
    ....
    })

behaviors中所有可用的节点:

可用的节点 类型 描述
properties Object Map 属性
data Object 数据
methods Object 方法
behaviors String Array 引入其他的behavior
created Function 生命周期函数
attached Function 生命周期函数
ready Function 生命周期函数
moved Function 生命周期函数
detached Function 生命周期函数

同名字段的覆盖规则:

  • 使用者的字段 > 当前behavior > 调用的 behavior

npm包

能用,但大部分都不能用。因为小程序的限制:

  • 不支持依赖于 Node.js 内置库的包
  • 不支持依赖于浏览器内置对象的包
  • 不支持依赖于 C++ 插件的包

Vant Weapp

Vant Weapp是一套小程序UI组件库,使用的是MIT开源许可协议,对商业使用较友好。

官方文档地址: https://vant-contrib.gitee.io/vant-weapp/0.x/#/intro

安装Vant组件库:

  1. 通过npm安装:npm i @vant/weapp@1.3.3 -S –production

    需要先使用 npm init -y 初始化一个包管理配置文件package.json

  2. 构建npm包:点击工具-构建npm

使用:

在app.json的usingComponents节点中,引入需要的组件,即可在wxml中直接使用组件。

1
2
3
"usingComponents": {
"van-button": "@vant/weapp/button"
}
1
<van-button type="primary">按钮</van-button>

Vant Weapp 使用CSS变量来实现定制主体,在app.wxss中,写入CSS变量,对全局生效:

定义:

1
2
3
4
page {
--button-danger-background-color: #C00000;
--button-danger-border-color: #D60000;
}

使用:

1
2
3
.e1 {
background-color: var(--button-danger-background-color);
}

如果CSS变量写在其他选择器下,就只在那个选择器范围内生效。

API Promise化

问题:默认情况下,小程序提供的异步API都是基于回调函数实现的。缺点在于,冗余造成回调地狱,代码可读性,可维护性差。

API Promise化,指的是通过额外的配置,将官方提供的异步API,升级为基于Promise的异步API。

实现:

  1. 安装:npm install –save miniprogram-api-promise@1.0.4

  2. 使用:

    1
    2
    3
    4
    5
    //在小程序的入口文件(app.js)中,只需调用一次promisifyAll()方法,即可实现异步API的Promise化
    import { promisifyAll } from 'minigrogram-api-promise'

    const wxp = wx.p = {}
    promisifyAll(wx, wxp)

    调用Promise化后的异步API:

    1
    <van-button bindtap="getInfo"></van-button>
    1
    2
    3
    4
    5
    6
    7
    8
    async getInfo(){
    const {data: res} = await wx.p.request({
    method: 'GET',
    url: 'https://www.xxxx'
    data:{name:'Tom', age:20}
    })
    console.log(res)
    }

全局数据共享

全局数据共享,是为了解决组件间数据共享的问题。开发中常用的方案有:Vuex,Redux,Mobx等。

小程序中,可使用 mobx-miniprogram 配合 mobx-miniprogram-bindings 实现全局数据共享。

  • mobx-miniprogram 用于创建Store实例对象;
  • mobx-miniprogram-bindings 用于把Store中的共享数据或方法,绑定到组件或页面中使用;

分包

普通分包

分包指把一个完整的小程序项目,按需求划分为不同的子包,使用时按需加载。

好处:优化首次加载时间,多团队开发时更好解耦。

分包后的项目构成:1个主包 + 多个分包。

  • 主包:一般只包含启动页面和TabBar页面,以及所有分包都要的公共资源;
  • 分包:只包含和当前分包有关的页面和私有资源;

分包大小的限制: 主包+分包不超过16M, 单个包不超过2M

使用分包:在app.json中的 subpackages节点中声明分包的结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"pages":[],
"subpackages": [
{
"root":"第一个分包的根目录",
"pages":[
"pages/cat",
"pages/dog"
]
},{
"root":"第二个分包的根目录",
"name": "分包的别名"
"pages":[
"pages/apple",
"pages/banana"
]
}
]
}

引用原则:

  1. 主包无法引用分包内的私有资源 ;
  2. 分包之间不能相互引用私有资源 ;
  3. 分包可以引用主包内的公共资源 ;

独立分包

独立分包 能独立于主包和其他分包而单独运行。 可以在不下载主包的情况下,独立运行。

因此,独立分包不能引用其他包的资源,包括主包的公共资源。

使用场景:让小程序从某一分包页面启动时,不用先下载主包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"pages":[],
"subpackages": [
{
"root":"第一个分包的根目录",
"pages":[
"pages/cat",
"pages/dog"
]
},{
"root":"第二个分包的根目录",
"name": "分包的别名"
"pages":[
"pages/apple",
"pages/banana"
],
"independent":true //声明当前分包是“独立分包”
}
]
}

分包预下载

分包预下载:在进入某页面时,自动下载之后可能需要的分包,从而提升进入其他分包页面的启动速度。

使用:

预下载的行为会在进入指定页面时触发。在app.json中,使用preloadRule节点定义分包的规则。

1
2
3
4
5
6
7
8
9
10
{
"preloadRule":{
"pages/contact/contact": { //触发分包预下载的页面路径
//network表示在指定网络模式下进行预下载, 可选all和wifi, 默认wifi
"network":"all",
//package 表示进入页面后,预下载哪些分包, 通过root或name指定预下载哪些分包
"package":["pkgA"]
}
}
}

限制: 一个分包的预下载份额不超过2M,即预下载的分包加起来不能超过2M;