微信小程序组件化的解决思路和方法
本文主要和大家分享微信小程序组件化的解决思路和方法,从小程序基础库版本 1.6.3 开始,小程序支持简洁的组件化编程。查看自己使用的小程序基础库版本,可以通过在开发者工具右侧点击详情查看:最基本的组件。
小程序的组件,其实就是一个目录,该目录需要包含4个文件:
xxx.json
xxx.wxml
xxx.wxss
xxx.js
声明一个组件
首先需要在 json 文件中进行自定义组件声明(将 component 字段设为 true 可这一组文件设为自定义组件)
{ "component": true }
其次,在要引入组件的页面的json文件内,进行引用声明
{ "usingComponents": { //自定义的组件名称 : 组件路径,注意是相对路径,不能是绝对路径 "component-tag-name": "path/to/the/custom/component" } }
这样,在主页面就可以使用了。
相比于vue的组件引入,小程序的方案更简洁。vue组件引入是需要 import 之后,同时在 components 里面注册,而小程序的组件只需要在 .json 里面注册,就可以在 wxml 里面使用。
使用slot
和vue 相同,小程序也有slot概念。
单一slot
在组件模板中可以提供一个
// 主页面内,<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中声明启用:
Component({ options: { multipleSlots: true // 在组件定义时的选项中启用多slot支持 }, properties: { /* ... */ }, methods: { /* ... */ } })
使用:
// 主页面 <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 里面应该写什么呢?
微信官方提供的案例中:
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,是传入外部数据的入口。
// 主页面使用组件 <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。
// 子组件触发自定义事件 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 属性产生关联,他们两个之间就可以捕获到对方,并且可以相互访问,修改对方的属性,如同修改自己的属性一样。
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){} } }, })
比如说,有两个组件如代码所示:
// 组件a slot 包含了组件b<a><b></b></a>
他们之间的关系如下图所示:
两个组件捕获到对方组件的实例,是通过 this.getRelationNodes('./path_to_a')方法。既然获取到了对方组件的实例,那么就可以访问到对方组件上的data, 也可以设置对方组件上的data, 但是不能调用对方组件上的方法。
// 在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 里面设置一个新名字 { "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
现在我们已经可以做到了两个组件之间的数据传递,那么如何在多个组件间传递数据呢?
如上图所示,同级的组件b 和同级的组件c , b 和 c 之间不可以直接获取,b可以获取到a, c 也可以获取到a,而a可以直接获取到 b 和 c。所以,如果想获取到兄弟元素,需要先获取到祖先节点,然后再通过祖先节点获取兄弟节点
我在组件b 里面,我需要先找到祖先组件a的实例,然后用祖先组件a的实例的getRelationNodes方法获取到组件c的实例。
看见没?恐怕我们又要写一大堆重复性的代码了。
幸好,微信小程序还提供了behavior 属性, 这个属性相当于 mixin,很容易理解的,是提高代码复用性的一种方法。
思路:
假设目前有三个组件,组件a, 组件b, 组件c, 其中组件b和组件c是兄弟组件,组建a是b和c的兄弟组件。为了减少代码的重复性,我们把获取父组件的方法,和获取兄弟组件的方法封装一下,封装在 behavior 的 methods 中。只要是引入该behavior的组件,都可以便捷的调用方法。
实现:
新建一个behavior文件,命名无所谓,比如说relation_behavior.js
// 在 get_relation.js 文件里面 module.exports = Behavior({ methods:{ // 获取父组件实例的快捷方法 _parent () { // 如果根据该路径获取到acestor组件为null,则说明this为ancesor var parentNode = this.getRelationNodes('../record_item/record_item') if (parentNode&&parentNode.length !== 0) { return parentNode[0] } else { return this } }, // 获取兄弟组件实例的快捷方法 _sibling(name) { var node = this._parent().getRelationNodes(`../${name}/${name}`) if (node &&node.length > 0) { return node[0] } } } })
然后在组件b, 和 组件c 上引入该behavior,并且调用方法,获取父组件和兄弟组件的实例
// 组件b中 var relation_behavior = require('./path_to_relation_behavior') Component({ behaviors:[relation_behavior], methods:{ test () { // 获得父组件的实例 let parent = this._parent() // 访问父组件的数据d console.log(parent.data.name) // 修改父组件的数据 parent.setData({ name: 'test1' }) // 获得兄弟组件的实例 let sibling = this._sibling('c') // 访问兄弟组件的数据 console.log(sibling.data.name) // 修改兄弟组件的数据 sibling.setData({ name:"test" }) } } }) // 组件c中 var relation_behavior = require('./path_to_relation_behavior') Component({ behaviors:[relation_behavior], methods:{ test () { // 获得父组件的实例 let parent = this._parent() // 访问父组件的数据d console.log(parent.data.name) // 修改父组件的数据 parent.setData({ name: 'test1' }) // 获得兄弟组件的实例 let sibling = this._sibling('b') // 访问兄弟组件的数据 console.log(sibling.data.name) // 修改兄弟组件的数据 sibling.setData({ name:"test" }) } } })
同时需要注意,c和b两个组件,从relations属性的角度来说,是a的后代组件。
但是组件b和组件c 所处的作用域, 都是主页面的作用域,传入的property都是主页面的property,这样就保证了组件数据的灵活性。relations 像一个隐形的链子一样把一堆组件关联起来,关联起来的组件可以相互访问,修改对方的数据,但是每一个组件都可以从外界独立的获取数据。
看了这么多理论的东西,还是需要一个具体的场景来应用。
比如说,我们有个一个分享记录图片心情的页面,当用户点击【点赞】的按钮时候,该心情的记录 点赞按钮会变红,下面的一栏位置会多出点赞人的名字。
如果不通过组件化,很可能的做法是 修改一个点赞按钮,然后遍历数据更新数据,最后所有记录列表的状态都会被重新渲染一遍。
如果是通过组件化拆分:把点赞的按钮封装为 组件b, 下面点赞人的框封装为组件c, 每一个心情记录都是一个组件a
下面是代码实现
// 在主页面内 <view wx:for='{{feed_item}}'> <a item='{{item}}'> <b></b> <c></c> </a> <view> // 在组件a内 var behavior_relation = require('../../relation_behavior.js) //这里引入上文说的Behavior Component({ behaviors:[behavior_relation], relations:{ '../b/b':{ type: 'descendant' } } }) // 在组件b内 var behavior_relation = require('../../relation_behavior.js) //这里引入上文说的Behavior Component({ behaviors:[behavior_relation] relations:{ '../a/a':{ type: 'ancestor' } }, data: { is_like: false //控制点赞图标的状态 }, methods:{ // 当用户点赞的时候 onClick () { // 修改本组件的状态 this.setData({ is_like: true }) // 修改 c 组件的数据 this._sibling('c').setData({ likeStr: this._sibling('c').data.likeStr + '我' }) } } }) // 在组件c内 var behavior_relation = require('../../relation_behavior.js) //这里引入上文说的Behavior Component({ behaviors:[behavior_relation], relations:{ '../a/a':{ type: 'ancestor' } }, data:{ likeStr:'晓红,小明' } })
这样,组件b 可以修改组件c中的数据。同时,组件b 和 组件c 又可以通过 properties 和 事件系统,和主页面保持独立的数据通信。
相关推荐:
以上是微信小程序组件化的解决思路和方法的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

微信是主流的聊天工具之一,我们可以通过微信认识新的朋友,联系老的朋友,维系朋友之间的情谊。正如天下没有不散的宴席,人与人之间的相处难免会发生意见不合的时候。当一个人极其影响你的情绪,或者在相处的时候发现三观不合,没办法再继续沟通,那么我们可能需要删除微信好友的方法。怎么删除微信好友?删除微信好友的方法第一步:在微信主界面轻触【通讯录】;第二步:点击对应要删除的好友,进入【详细资料】;第三步:点击右上角【...】;第四步:点击下方【删除】即可;第五步:了解后页面提示后,点击【删除联系人】即可;温馨

番茄小说是一款非常热门的小说阅读软件,我们在番茄小说中经常会有新的小说和漫画可以去阅读,每一本小说和漫画都很有意思,很多小伙伴也想着要去写小说来赚取赚取零花钱,在把自己想要写的小说内容编辑成文字,那么我们要怎么样在这里面去写小说呢?小伙伴们都不知道,那就让我们一起到本站本站中花点时间来看写小说的方法介绍吧。分享番茄小说写小说方法教程 1、首先在手机上打开番茄免费小说app,点击个人中心——作家中心 2、跳转到番茄作家助手页面——点击创建新书在小说的结

七彩虹主板在中国国内市场享有较高的知名度和市场占有率,但是有些七彩虹主板的用户还不清楚怎么进入bios进行设置呢?针对这一情况,小编专门为大家带来了两种进入七彩虹主板bios的方法,快来试试吧! 方法一:使用u盘启动快捷键直接进入u盘装系统 七彩虹主板一键启动u盘的快捷键是ESC或F11,首先使用黑鲨装机大师制作一个黑鲨U盘启动盘,然后开启电脑,当看到开机画面的时候,连续按下键盘上的ESC或F11键以后将会进入到一个启动项顺序选择的窗口,将光标移动到显示“USB”的地方,然

而后悔莫及、人们常常会因为一些原因不小心将某些联系人删除、微信作为一款广泛使用的社交软件。帮助用户解决这一问题,本文将介绍如何通过简单的方法找回被删除的联系人。1.了解微信联系人删除机制这为我们找回被删除的联系人提供了可能性、微信中的联系人删除机制是将其从通讯录中移除,但并未完全删除。2.使用微信内置“通讯录恢复”功能微信提供了“通讯录恢复”节省时间和精力,用户可以通过该功能快速找回之前被删除的联系人,功能。3.进入微信设置页面点击右下角,打开微信应用“我”再点击右上角设置图标、进入设置页面,,

Win11管理员权限获取方法汇总在Windows11操作系统中,管理员权限是非常重要的权限之一,可以让用户对系统进行各种操作。有时候,我们可能需要获取管理员权限来完成一些操作,比如安装软件、修改系统设置等。下面就为大家总结了一些获取Win11管理员权限的方法,希望能帮助到大家。1.使用快捷键在Windows11系统中,可以通过快捷键的方式快速打开命令提

字体大小的设置成为了一项重要的个性化需求,随着手机成为人们日常生活的重要工具。以满足不同用户的需求、本文将介绍如何通过简单的操作,提升手机使用体验,调整手机字体大小。为什么需要调整手机字体大小-调整字体大小可以使文字更清晰易读-适合不同年龄段用户的阅读需求-方便视力不佳的用户使用手机系统自带字体大小设置功能-如何进入系统设置界面-在设置界面中找到并进入"显示"选项-找到"字体大小"选项并进行调整第三方应用调整字体大小-下载并安装支持字体大小调整的应用程序-打开应用程序并进入相关设置界面-根据个人

手机游戏成为了人们生活中不可或缺的一部分,随着科技的发展。它以其可爱的龙蛋形象和有趣的孵化过程吸引了众多玩家的关注,而其中一款备受瞩目的游戏就是手机版龙蛋。帮助玩家们在游戏中更好地培养和成长自己的小龙,本文将向大家介绍手机版龙蛋的孵化方法。1.选择合适的龙蛋种类玩家需要仔细选择自己喜欢并且适合自己的龙蛋种类,根据游戏中提供的不同种类的龙蛋属性和能力。2.提升孵化机的等级玩家需要通过完成任务和收集道具来提升孵化机的等级,孵化机的等级决定了孵化速度和孵化成功率。3.收集孵化所需的资源玩家需要在游戏中

Oracle版本查询方法详解Oracle是目前世界上最流行的关系型数据库管理系统之一,它提供了丰富的功能和强大的性能,广泛应用于企业中。在进行数据库管理和开发过程中,了解Oracle数据库的版本是非常重要的。本文将详细介绍如何查询Oracle数据库的版本信息,并给出具体的代码示例。查询数据库版本的SQL语句在Oracle数据库中,可以通过执行简单的SQL语句
