前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微信小程序组件化编程和实践(上)

微信小程序组件化编程和实践(上)

原创
作者头像
疯狂的小程序
发布2018-01-25 17:03:17
1.8K0
发布2018-01-25 17:03:17
举报
文章被收录于专栏:疯狂的小程序疯狂的小程序

从小程序基础库版本 1.6.3 开始,小程序支持简洁的组件化编程。查看自己使用的小程序基础库版本,可以通过在开发者工具右侧点击详情查看:

最基本的组件

小程序的组件,其实就是一个目录,该目录需要包含4个文件:

  1. xxx.json
  2. xxx.wxml
  3. xxx.wxss
  4. xxx.js

声明一个组件

首先需要在?json?文件中进行自定义组件声明(将?component?字段设为?true?可这一组文件设为自定义组件)

代码语言:javascript
复制
{
??"component":?true
}

其次,在要引入组件的页面的json文件内,进行引用声明

代码语言:javascript
复制
{
??"usingComponents":?{
????//自定义的组件名称?????:?组件路径,注意是相对路径,不能是绝对路径??
????"component-tag-name":?"path/to/the/custom/component"
??}
}

这样,在主页面就可以使用了。

相比于vue的组件引入,小程序的方案更简洁。vue组件引入是需要 import 之后,同时在 components 里面注册,而小程序的组件只需要在 .json 里面注册,就可以在 wxml 里面使用。

使用slot

和vue 相同,小程序也有slot概念。

单一slot

在组件模板中可以提供一个?<slot>?节点,用于承载组件引用时提供的子节点。

代码语言:javascript
复制
//?主页面内,<addlike>是组件
<addlike?item="item"?my_properties="sssss">
????<text>我是被slot插入的文本</text>
</addlike>
?
//?addlike?组件
<view?class="container">
????<view>hello,?这里是组件</view>
????<view>hello,?{{my_properties}}</view>
????<slot></slot>
</view>
?
//?渲染后
<view?class="container">
????<view>hello,?这里是组件</view>
????<view>hello,?{{my_properties}}</view>
????<text>我是被slot插入的文本</text>
</view>

多个slot

如果需要在组件内使用多个slot, 需要在组件js中声明启用:

代码语言:javascript
复制
Component({
??options:?{
????multipleSlots:?true?//?在组件定义时的选项中启用多slot支持
??},
??properties:?{?/*?...?*/?},
??methods:?{?/*?...?*/?}
})

使用:

代码语言:javascript
复制
//?主页面
<addlike?item="item"?my_properties="sssss">
????//?在普通的元素上加入?slot?属性,指定slotname,?就可以变成子元素的slot了
????<text?slot="slot1">我是被slot1插入的文本</text>
????<text?slot="slot2">我是被slot2插入的文本</text>
</addlike>
?
//?子页面
<view?class="container">
????<view>hello,?这里是组件</view>
????<view>hello,?{{my_properties}}</view>
????<slot?name="slot1"></slot>
????<slot?name="slot2"></slot>
</view>

Component构造器

?刚才我们说了,一个组件内应该包括js, ?wxml, wxss, json 四个文件。wxml 相当于是 HTML,wxss 相当于是 css, 那么js 里面应该写什么呢?

微信官方提供的案例中:

代码语言:javascript
复制
Component({
?
??behaviors:?[],
?
??properties:?{
???
??},
??data:?{},?//?私有数据,可用于模版渲染
?
??//?生命周期函数,可以为函数,或一个在methods段中定义的方法名
??attached:?function(){},
??moved:?function(){},
??detached:?function(){},
?
??methods:?{
????onMyButtonTap:?function(){
?????
????},
????_myPrivateMethod:?function(){
?????
????},
????_propertyChange:?function(newVal,?oldVal)?{
?
????}
??}
})

里面调用了一个Component构造器。Component构造器可用于定义组件,调用Component构造器时可以指定组件的属性、数据、方法等。具体 Component里面可以放什么东西,如下所示:

组件与数据通信

组件化必然要涉及到数据的通信,为了解决数据在组件间的维护问题,vue, react,angular 有不同的解决方案。而小程序的解决方案则简洁很多。

主页面传入数据到组件

properties相当于vue的props,是传入外部数据的入口。

代码语言:javascript
复制
//?主页面使用组件
<a?add_like="{{add_like}}">
</a>
?
//?组件a.js?内
Component({
????properties:{
????????add_like:{
????????????type:Array,
????????????value:[],
????????????observer:function(){
????????????????
????????????}
????????}
????}
})

注意: 传入的数据,不管是简单数据类型,还是引用类型,都如同值复制一样(和红宝书里面描述js函数参数传入是值复制还不一样,红宝书里面的意思是:简单数据类型直接复制数值,引用类型复制引用,也就是说在函数内修改参数对象的属性,会影响到函数外对象的属性)。

如果是Vue的props, 则可以通过 .sync 来同步,而在小程序子组件里面,调用this.setData()修改父组件内的数据,不会影响到父组件里面的数据, 也就是说,子组件property的修改,仿佛和父组件没有任何关系。那么,如果是在子组件内修改父组件的数据,甚至是修改兄弟组件内的数据,有没有简单的方法呢?下面会有讲到

组件传出数据到主页面

和vue类似,组件间交互的主要形式是自定义事件。

组件通过?this.triggerEvent()?触发自定义事件,主页面在组件上?bind:component_method="main_page_mehod"?来接收自定义事件。

其中,this.triggerEvent()?方法接收自定义事件名称外,还接收两个对象,eventDetail?和?eventOptions

代码语言:javascript
复制
//?子组件触发自定义事件
ontap?()?{
????//?所有要带到主页面的数据,都装在eventDetail里面
	var?eventDetail?=?{
		name:'sssssssss',
		test:[1,2,3]
	}
	//?触发事件的选项?bubbles是否冒泡,composed是否可穿越组件边界,capturePhase?是否有捕获阶段
	var?eventOption?=?{
		composed:?true
	}
	this.triggerEvent('click_btn',?eventDetail,?eventOption)
}
?
//?主页面里面
main_page_ontap?(eventDetail)?{
????console.log(eventDetail)
????//?eventDetail
????//?changedTouches
????//?currentTarget
????//?target
????//?type
????//?……
????//?detail???哈哈,所有的子组件的数据,都通过该参数的detail属性暴露出来
}

组件之间数据通信

和vue提出的vuex的解决方案不同,小程序的组件间的通讯简单小巧。你可以和主页面与组件通讯一样,使用自定义事件来进行通讯,当然更简单方便的方法,是使用小程序提供的relations.

relations 是Component 构造函数中的一个属性,只要两个组件的relations 属性产生关联,他们两个之间就可以捕获到对方,并且可以相互访问,修改对方的属性,如同修改自己的属性一样。

代码语言:javascript
复制
Component({
???relations:{
????'./path_to_b':?{?????????????????//?'./path_to_b'是对方组件的相对路径
????????type:?'child',???????????????//??type可选择两组:parent和child、ancestor和descendant
????????linked:function(target){??}??//?钩子函数,在组件linked时候被调用?target是组件的实例,
????????linkChanged:?function(target){}
????????unlinked:?function(target){}
????????}
????},
})

比如说,有两个组件如代码所示:

代码语言:javascript
复制
//?组件a?slot?包含了组件b
<a>
????<b></b>
</a>

他们之间的关系如下图所示:

两个组件捕获到对方组件的实例,是通过 this.getRelationNodes('./path_to_a')方法。既然获取到了对方组件的实例,那么就可以访问到对方组件上的data, 也可以设置对方组件上的data, 但是不能调用对方组件上的方法。

代码语言:javascript
复制
//?在a?组件中
Component({
????relations:{
????????'./path_to_b':?{
????????????type:?'child',
????????????linked:function(target){??}??//?target是组件b的实例,
????????????linkChanged:?function(target){}
????????????unlinked:?function(target){}
????????}
????},
????methods:{
????????test?()?{
????????????var?nodes?=?this.getRelationNodes('./path_to_b')
????????????var?component_b?=?nodes[0];
????????????
????????????//?获取到b组件的数据
????????????console.log(component_b.data.name)
????????????
????????????//?设置父组件的数据
????????????//?这样的设置是无效的
????????????this.setData({
????????????????component_b.data.name:'ss'
????????????})
????????????//?需要调用对方组件的setData()方法来设置
????????????component_b.setData({
????????????????name:'ss'
????????????})
????????}
????}
})
?
//?在b?组件里面
Component({
????relations:{
????????'./path_to_a':?{??????????????????????//注意!必须双方组件都声明relations属性
????????????type:'parent'
????????}
????},
????data:?{
????????name:?'dudu'
????}
})

注意:1. 主页面使用组件的时候,不能有数字,比如说 <component_sub1> 或 <component_sub_1>,可以在主页面的json 里面设置一个新名字

代码语言:javascript
复制
{
????"usingComponents":{
????????"test_component_subb":?"../../../components/test_component_sub2/test_component_sub2"
????}
}

2. relations 里面的路径,比如说这里:

是对方组件真实的相对路径,而不是组件间的逻辑路径。

3. 如果relations 没有关联,那么 this.getRelationNodes 是获取不到对方组件的

4. 本组件无法获取本组件的实例,使用this.getRelatonsNodes('./ path_to_self ') 会返回一个null

4. type 可以选择的?parent?、?child?、?ancestor?、?descendant?

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 最基本的组件
    • 声明一个组件
      • 使用slot
        • 单一slot
        • 多个slot
      • Component构造器
      • 组件与数据通信
        • 主页面传入数据到组件
          • 组件传出数据到主页面
            • 组件之间数据通信
            相关产品与服务
            云开发 CloudBase
            云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
            http://www.vxiaotou.com