微信小程序推荐以简洁的开发方式打造轻量级应用。然而,小程序的需求越来越多,业务需求往往难以做到精简,这就对开发方式有了进一步的要求。组件化开发是协同合作、提升开发效率的关键。
小程序本身的组件能力,从一开始只有官方提供的、定制化程度不高的基础组件,到1.6.3开始支持自定义组件,再到插件功能开放,可以说是日渐完善了。本文将探讨一些小程序自定义组件的方案。让我们从一个很简单的提示弹层组件说起,效果图是这样的:
在小程序 1.6.3 版本之前,只能将组件的 *.wxml
、 *.js
和 *.wxss
文件抽取出来,自行封装,再在页面里通过 import 或 include 两种方法引入组件:
使用import引入template模板
template即模板,小程序文档定义:
WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。
我们把toast组件放在components目录下,结构如下:
components/ └─toast/ ├─toast.js ├─toast.wxml └─toast.wxss
组件不需要配置文件 *.json
,其他部分和小程序页面一样,由 *.wxml
、 *.js
和 *.wxss
文件构成。
在 toast.wxml
文件中用 <template>
定义组件的模版,name属性作为模板的名字:
<template name="toast"> <view> <view class="{{iconType}}"></view> <view>{{toastMsg}}</view> </view> </template>
样式文件和普通页面写法相同。组件的方法、事件和构造函数都需要在 toast.js
中定义并导出。
组件的使用
使用组件时,首先在页面里通过 <import/>
引入组件,再使用 <template>
指定 is
属性为模板的 name
,再将页面数据通过 data
属性传入模板(注意要用扩展运算符 ...
展开对象)。
<import src="toast.wxml" /><template is="toast" data="{{...toastData}}"></template>
组件样式通过 @import"toast.wxss"
在页面的样式文件内引入,如果使用组件的方法,需要在js中引入组件并初始化。
include方式
include 和 import 的区别,小程序文档描述:
import可以在该文件中使用目标文件定义的template。include 可以将目标文件除了
外的整个代码引入,相当于是拷贝到 include 位置。模板拥有自己的作用域,只能使用 data 传入的数据。
include模式非常简单,就是简单的代码替换,没有作用域,也不能像import模板使用data属性传递数据,只能通过将当前页面的data对象传给组件,从而绑定数据、渲染页面。
组件还是由 *.wxml
、 *.js
和 *.wxss
文件构成。 *.wxml
和 *.wxss
的写法与普通页面相同,组件js也需要封装组件方法、事件,并导出构造函数。使用组件时,在页面里只要添加 <includesrc="toast.wxml"/>
就把组件模板copy过来了。
无论用template还是include方式构造组件,最大的难点就是如何封装组件的构造函数,并将属性和方法暴露出去。曾经采用过的方法是调用 getCurrentPages()
方法获取当前页面对象,然后用 Object.assign()
把组件的事件和方法“合并”到页面对象上,但这样并不能很好地解决组件事件传递、作用域隔离等一系列问题。所以,在小程序自定义组件能力开放之前,组件化可以说是比较尴尬的,对于复杂的组件,写起来真的是非常痛苦!!终于,从基础库版本 1.6.3 开始,小程序支持简洁的组件化编程。
官方自定义组件
自定义组件官方文档非常全面,规范化了小程序组件开发,其中描述道:
开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用;也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。自定义组件在使用时与基础组件非常相似。
有了自定义组件,写起组件来就方便多了。还是以前面的toast组件为例,目录结构:
components/ └─toast/ ├─toast.js ├─toast.wxml ├─toast.wxss └─toast.json
组件目录比前面的方法多了一个 toast.json
,我们需要在这个 json 配置文件中将 component
字段声明为 true
,代表自定义组件:
{ "component": true}
组件模板和样式的写法都和常规页面类似。那么,前面所说的之前最痛苦的组件封装,在自定义组件里是怎么实现的呢? toast.js
作为组件构造器,是使用 Component 构造器来注册组件的,并提供组件的属性定义、内部数据和自定义方法,例如:
// toast.js Component({ properties: { toastMsg: { // 属性名 type: String, // 类型(必填) value: '', // 属性初始值(可选),可以在组件使用时指定 } }, data: { // 组件内部数据 isToastShow: false }, methods: { // 组件的自定义方法 toastShow: function () { this.setData({ isToastShow: true }); } } })
properties 对象声明组件属性,与 Vue.js 的 props 类似。在组件被调用时,就可以通过指定属性来渲染组件模板了。
data 对象即组件的内部数据,和 properties 一同用于模版渲染。
method 里定义组件的方法。
Component 构造器里的支持的内容如表格所示:
自定义组件使用
使用组件非常简单,首先在页面的 json文件内,进行引用声明:
"usingComponents": { "toast": "/components/toast/toast" }
现在,页面里就可以直接用组件名称的标签引入它,并将属性值传递给组件,再也不用import来、include去了。
<toast id="toast" icon-type="okay" toast-msg="okay成功啦"></toast>
在页面的生命周期函数 onLoad()
中获取组件实例,就可以愉快地使用组件的方法了。
onLoad: function () { // 获得toast组件 this.toast = this.selectComponent("#toast"); this.toast.toastShow() }
在事件方面,监听自定义组件事件的方法与监听基础组件事件的方法完全一致。
<!-- 当自定义组件触发“myevent”事件时,调用“onMyEvent”方法 --> <component-tag-name bindmyevent="onMyEvent" /> <!-- 或者可以写成 --> <component-tag-name bind:myevent="onMyEvent" />
在实际应用中发现,第二种方法 bind:myevent
的兼容性更好一些。
自定义组件触发事件时,需要使用 triggerEvent
方法,指定事件名、detail对象和事件选项:
<!-- 在自定义组件中 --> <button bindtap="onTap">点击这个按钮将触发“myevent”事件</button> Component({ properties: {} methods: { onMyEvent: function(e){ e.detail // 自定义组件触发事件时提供的detail对象 }, onTap: function () { var myEventDetail = {} // detail对象,提供给事件监听函数 var myEventOption = {} // 触发事件的选项 this.triggerEvent('myevent', myEventDetail, myEventOption) } } })
自定义组件还有很多丰富的功能,比如像Vue.js一样有 slot 的概念,用于承载组件引用时提供的子节点;使用小程序提供的 relations 进行组件之间数据通信等等。总的来说,自定义组件推出后,组件化编程方便且规范了许多。在探索小程序组件化的道路上,第三方组件化框架也层出不穷。
第三方组件化框架
在这里推荐两个优秀的框架,它们都将小程序开发模式转为了MVVM方式:
WePY
WePY 是一款让小程序支持组件化开发的框架,预编译的手段让开发者可以选择自己喜欢的开发风格去开发小程序。采用类Vue开发风格,单文件模式,支持多种编译器如Less/Sass/Stylus、Babel/Typescript,能够很好地提升开发效率。
mpvue
WePY 采用的是类似 Vue.js 的开发风格,而 mpvue 则是一个使用 Vue.js 开发小程序的前端框架,直接将Vue应用转成小程序,可以说是完整的 Vue.js 开发体验了。并且支持 Vuex 数据管理方案和 webpack 构建机制。令人兴奋的是,mpvue还具备 H5 代码转换编译成小程序目标代码的能力。
小结
以上几种小程序组件化方案,开发时该如何选择呢?从组件功能而言,WePY和mpvue已经堪称完美,如果从整体来权衡,使用它们需要先熟悉Vue.js,开发中也是实时编译之后才能调试,框架更适合使用在大型项目中。
对于中小型项目,当只需使用展示型组件,且没有动态变化的数据时,可以使用include直接拷贝;需要根据数据渲染组件时,可以选择template,通过data属性传递数据。当组件再复杂一些,涉及事件和方法调用,就可以使用自定义组件了。
另外,小程序基础库版本 1.9.6 开始支持插件功能,开发者可以像开发小程序一样编写一个插件并上传代码,在插件发布之后,其他小程序方可调用。如何用组件化提升开发效率和用户体验值得我们不断思考,期待小程序的组件化能力越来越强大。
扩展阅读
https://mp.weixin.qq.com/debug/wxadoc/dev/framework/view/wxml/import.html
https://mp.weixin.qq.com/debug/wxadoc/dev/framework/custom-component/
https://github.com/Tencent/wepy
https://github.com/aben1188/awesome-wepy
https://github.com/Meituan-Dianping/mpvue
https://mp.weixin.qq.com/debug/wxadoc/dev/framework/plugin/?version=6206021b&ascene=1&lang=zh_CN&devicetype=Windows+7&winzoom=1
作者:全栈探索