微信小程式元件Components——父向子傳遞和子向父傳遞資料的過程
前言:元件是微信小程式在開發過程中一個非常重要的知識,可以化簡我們的程式碼複用及編寫,但是元件也是相對來說比較難以理解的一個概念,用法也比較糾結,本篇博文將具體介紹元件的基本使用方法
一、簡單瞭解
元件的建立其實和頁面很像,其實就是把多個標籤通過一定的邏輯整合到了一起形成元件
這是元件的所需檔案,可以看出和頁面很像,當然也有些不同
比如在json配置檔案中多了 “component”: true的內容
{
"component": true,
"usingComponents": {}
}
在js檔案中多了properties和method屬性等
properties: {
tabs:{
type:Array,
value:[]
}
},
methods: {
}
在使用外掛的是時候,父級頁面需要進行宣告,在json配置頁面中如何設定
{
"usingComponents": {
//相對路徑應用元件
"Tabs":"../../components/Tabs/Tabs"
},
"navigationBarTitleText": "梨花燒"
}
二、元件的使用
例如,想做一個標籤頁面
子元件wxml頁面
<view calss="tab">
<view class="tabs_title">
<view class="title_item {{item.isActive?'active':''}}"
wx:for="{{tabs}}"
wx:key="id"
bindtap="handleItemTap"
data-index="{{index}}"
>{{item.name}}</view>
</view>
<view class="tabs_content">
<slot></slot>
</view>
</view>
子元件js頁面如下
// components/Tabs/Tabs.js
Component({
/**
* 元件的屬性列表
*/
properties: {
tabs:{
type:Array,
value:[]
}
},
/**
* 元件的初始資料
*/
data: {
},
/**
* 元件的方法列表
*/
methods: {
handleItemTap(e){
const {index} = e.currentTarget.dataset;
this.triggerEvent("itemChange",{index});
}
}
})
父頁面wxml
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange">
<block wx:if="{{tabs[0].isActive}}">0</block>
<block wx:elif="{{tabs[1].isActive}}">1</block>
<block wx:elif="{{tabs[2].isActive}}">2</block>
<block wx:else>3</block>
</Tabs>
父頁面js
Page({
/**
* 頁面的初始資料
*/
data: {
tabs:[
{
id:0,
name:"首頁",
isActive:true
},
{
id:1,
name:"原創",
isActive:false
},
{
id:2,
name:"分類",
isActive:false
},
{
id:3,
name:"關於",
isActive:false
}
]
},
handleItemChange(e){
console.log(e);
const {index} = e.detail;
let {tabs} = this.data;
tabs.forEach(function(v,i){
if(i===index){
v.isActive=true;
}else{
v.isActive=false;
}
});
let num=2;
this.setData({
tabs,
num
});
}
})
需要注意下子元件js中properties屬性就是父向子傳遞資料的入口,(注:在子元件中使用let {tabs} = this.data;仍然可以獲得tabs,雖然data中沒有tabs資料,但是可以在properties中獲取,但是如果再將資料進行setData操作的話,就會儲存再data中,而不是properties),需要設定type型別和value初始值,父頁面可以採用下面的方式設定
<Tabs tabs="{{tabs}}">
這樣的話,就可以將父頁面的資料傳送到子元件中了。
但是子元件中有時候會有一些操作又需要將資料反饋到父頁面中,比如需要向第幾個頁面的資訊通知給父頁面,可以子元件wxml中加入單擊事件,然後通過this.triggerEvent(“itemChange”,{index});繫結並呼叫父頁面繫結事件binditemChange,使用如下程式碼實現
handleItemTap(e){
const {index} = e.currentTarget.dataset;
this.triggerEvent("itemChange",{index});
}
然後在父頁面中來設定觸發方法
<Tabs binditemChange="handelItemChange">
這樣就可以如法父頁面js中的handelItemChange方法了,
handelItemChange(e){
console.log(e);
}
通過列印e得到如下資料,可以從e.detail.index中獲取子元件傳回的資料了
{type: "itemChange", timeStamp: 955073, target: {…}, currentTarget: {…}, detail: {…}, …}
changedTouches: undefined
currentTarget: {id: "", dataset: {…}}
detail: {index: 2}
target: {id: "", dataset: {…}}
timeStamp: 955073
touches: undefined
type: "itemChange"
_requireActive: undefined
__proto__: Object
簡單回顧以下這個的流程:
1.父頁面呼叫子元件,單擊等事件操作的響應其實在子元件的;
2.子頁面呼叫單擊事件相應,並繫結父頁面的ItemChange方法;
3.父頁面通過bindItemChange屬性來繫結handleItemChange(e)方法,通過e引數將子資料返回給父頁面
所以實際上父頁面的bindItemChange屬性並不是父頁面直接單擊生效的,我想button按鈕的bindtop單擊出發事件也是通過類似的繫結
可能有人會問這樣傳來傳去的意義是什麼呢,因為元件建立後,可能被多個頁面多次呼叫,所以很多程式碼都是動態設定的,不能直接寫死,很多元件的資料需要父頁面的資料來決定,而且元件的資料如果發生變動的話,不能再子元件中更新資料,這樣的資料會儲存子元件的data中,父頁面的資料無法更新,所以一般再元件中不進行復雜的邏輯操作,直接將簡單的資料資訊傳送給父頁面,讓父頁面處理資料,保證父頁面資料的實時更新。
最後在說一下插槽標籤的作用
可以將<Tabs>內容</Tabs>中的“內容”替換到掉<slot></slot>