小程序开发之组件化方案
2018-03-24 09:56 阅读(333)

微信小程序推荐以简洁的开发方式打造轻量级应用。然而,小程序的需求越来越多,业务需求往往难以做到精简,这就对开发方式有了进一步的要求。组件化开发是协同合作、提升开发效率的关键。

小程序本身的组件能力,从一开始只有官方提供的、定制化程度不高的基础组件,到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      
             });
         }  
     }
 })

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



作者:全栈探索