小程序自定义组件开发实战
作者: dkvirus 发表于: 2018-06-25 15:41:00 最近更新: 2018-08-01 22:12:22

2017.11月初期待已久的原生小程序自定义组件功能已经发布,此次发布版本为 1.6.3,尽管此前有模板

一、写在前面的话

微信官网虽然提供了许多组件,但实际应用时仍感觉稍显疲软,如消息提示框只提供了成功与加载两种状态,那么如果失败了如何提示?还有模态框只有简单的 title 和 content 属性,内部并不支持自定义 wxml,等等,作者将工作中用到的微信组件文档中没有的 UI 自定义封装了一些,有需要的可以看下:wx-ui (持续补充中)

二、开发前准备

  1. 目前自定义组件相关特性处于公测阶段。如果需要使用相关特性,请确认在项目选项中已勾选“预览/上传时使用新特性”;
  2. 小程序基础库从 1.6.3才开始支持组件化编程,在此之前先升级开发工具,选择高于1.6.3版本的基础库来体验组件化编程。
  3. 微信小程序官方组件文档。 建议先看一遍,在跑一遍下方的示例代码。

image.png

三、概述

3.1 目标组件

常见的价格加减组件,当设置值小于最小值时,减号 - 不可点击,当设置值大于最大值时,加好不可点击,效果如下:

price组件.gif

3.2 组件化开发需要注意两点

  • 页面如何往组件传值?
  • 组件如何将自身值反馈给页面?

tips: 第一遍看可能有点绕,建议将代码 copy 到开发工具跑一遍,在对照着下方的解释去理解会事半功倍。

四、价格组件实例

写一个组件,在页面中使用它。

4.1 书写价格组件 price

  • 组件不需要在 app.json 中的 pages 属性中进行配置,因为它不是一个页面;
  • 组件和普通页面一样,有 .wxml、.wxss、js 和 .json 四个文件;
  • 组件必须要在 *.json 文件中进行申明这是一个组件,具体代码见 price.json 文件;
  • 组件的 wxml 和 .wxss 和页面的书写没有任何区别,这里不多说;
  • 组件的 .js 文件使用了新的构造函数 Component 代替了页面构造函数 Page,用来管理属性和事件。官方文档:Component 构造器.js 文件是组件中最重要的文件,在页面中使用组件时再介绍它。

4.1.1 组件页面 price.wxml

price 组件的页面显示。

1
2
3
4
5
6
7
<view class="quantityViewStyle">
<view class="minusStyle" bindtap="minus" style="color:{{num==min?'#DADADA':white}}">-</view>
<view class="inputViewStyle">
<input class="inputStyle" value="{{num}}" type="number" bindblur="onInputBlur"/>
</view>
<view class="plusStyle" bindtap="plus" style="color:{{num==max?'#DADADA':white}}">+</view>
</view>

4.1.2 组件样式 price.wxss

price 组件的样式文件。

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
.quantityViewStyle {
display:flex;
border:0rpx solid #DADADA;
border-radius:6rpx;
width: 220rpx;
}
.minusStyle {
height:58rpx;
width:60rpx;
border-right:0rpx solid #DADADA;
display:flex;
justify-content:center;
align-items:center;
}
.plusStyle {
height:58rpx;
width:60rpx;
display:flex;
justify-content:center;
align-items:center;
}
.inputViewStyle {
height:58rpx;
width:100rpx;
border-right:0rpx solid #DADADA;
}
.inputStyle {
width:80rpx;
height:54rpx;
text-align:center;
font-size:26rpx;
background:white;
}

4.1.3 组件逻辑 price.js

  • Component 是个新的构造器,主要关注其中 properties 和 methods 两个属性;
  • 在 properties 中,如设置 num 字段,用 type 和 value 修饰,type 表示 num 是个数值,而 value 表示 num 的默认值,如果页面调用组件时没有传值,那么 num 就是 5;
  • methods 属性里写组件的相关方法,主要注意 this.triggerEvent('custom', { value: num }) 这行代码,这是子组件往页面传值的唯一方式。
    • 组件往页面传值,通常的写法是在页面调用组件时添加一个事件监听,这样只要组件中值改变时,通过这个事件就可以监听到改变的值;
    • 第一个参数为页面定义的监听事件的事件类型,名称自定义。
      • 事件类型:在 index.wxml 中调用组件 price 时添加了事件监听函数bindcustom="onPageInputChange",其中 bind 是微信小程序绑定事件的一个前缀,后面的 custom 才是具体的事件类型;
      • 要注意第一个参数的值要与事件监听函数事件类型相同;
    • 第二个参数是个对象,表示往使用该组件的页面中传的值,在 index.js 中onPageInputChange: function (e) { // .... } 中的参数 e 就是这地方传递过去的。
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
47
48
49
50
51
52
53
54
55
56
Component({
properties: {
// 这里定义了innerText属性,属性值可以在组件使用时指定
num: {
type: Number,
value: 5,
},
min: {
type: Number,
value: 0,
},
max: {
type: Number,
value: 10
}
},
methods: {
// 加法
plus: function () {
// 加值小于最大值,才允许加法运算
var num = this.data.num + 1;
if (num <= this.data.max) {
this.setData({
num: num
})
this.triggerEvent('custom', { value: num })
}
},
// 减法
minus: function () {
// 减值大于最小值,才允许减法运算
var num = this.data.num - 1;
if (num >= this.data.min) {
this.setData({
num: num
})
this.triggerEvent('custom', { value: num })
}
},
// 文本框失去焦点事件,判断输入值是否为数字
onInputBlur: function (e) {
var value = e.detail.value;
if (isNaN(value)) {
// 不是数字,直接置为最小值
this.setData({num: this.data.min})
} else {
// 是数字,输入值大于最大值,置为最大值,同理最小值
if (value > this.data.max) {
this.setData({ num: this.data.max })
} else if (value < this.data.min) {
this.setData({ num: this.data.min })
}
}
}
}
})

4.1.4 组件配置 price.json

声明 price 是个组件。

1
2
3
{
"component": true
}

4.2 在页面中使用组件

  • 在页面中使用组件,需要先在 *.json 文件中进行配置,格式如下;

    • component-tag-name 为组件在页面(*.wxml)中使用的名称,这里可以自定义,可以叫 price,也可以叫 my-price,但不可有数字,否则会报错;
    • path/to/the/custom/component 为组件的路径,这里写相对路径,也就是 ../ 开头的路径,不要有后缀,具体见下方 index.json 文件。
      1
      2
      3
      4
      5
      {
      "usingComponents": {
      "component-tag-name": "path/to/the/custom/component"
      }
      }
  • 页面需要在 app.json 中配置,别忘记了。

4.2.1 页面 index.wxml

1
2
3
4
5
6
<view style="display: flex;flex-direction: row;justify-content: space-between;padding: 0 20rpx;">
<view>¥26.3</view>
<!-- 以下是对一个自定义组件的引用 price -->
<price num="{{price}}" bindcustom="onPageInputChange"/>
<view>{{price}}</view>
</view>
  • 这里调用组件的代码为 <price num="" bindcustom="onPageInputChange"/>
  • num 字段为设置价格组件的默认值,在 price.js 中可以在 properties 属性中找到它;
  • bindcustom="onPageInputChange" 为自定义事件监听函数,用法为监听价格组件文本框中数值变化。在下方的 index.js 中可以看到事件处理函数 onPageInputChange 有个参数 e,这个参数需要在组件中进行传递。通过 e.detail.value 可以获取文本框中的值。

4.2.2 页面逻辑 index.js

1
2
3
4
5
6
7
8
9
Page({
data: {
price: 5
},

onPageInputChange: function (e) {
this.setData({ price: e.detail.value})
}
})

4.2.3 配置文件 index.json

声明使用组件 price。

1
2
3
4
5
{
"usingComponents": {
"price": "../price/price"
}
}

4.2.4 app.json

配置 index 页面。

1
2
3
4
5
6
7
8
9
10
11
{
"pages":[
"pages/index/index"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle":"black"
}
}
首页
友链
归档
dkvirus
动态
RSS