微信小程序:自定義組件的數據傳遞

1、前言

若是小程序中有可複用的UI且具備必定的功能性,就可使用自定義組件將其封裝起來。(若是僅僅只須要複用UI可以使用template)vue

下面介紹父子組件的數據傳遞方法,以及一個簡單的組件和一個複雜的組件示例。json

【因爲剛開始寫這篇文章的時候我還算是一個小程序的新手,本身看着官方文檔研究並整理概括的,有不少不足以及錯誤的地方。在通過一年的沉澱之後(雖然這一年我主要在寫vue而不是小程序),我決定從新整理這篇瀏覽量比較大的文章,以避免新手因個人文章走了彎路。】小程序

2、父子組件傳遞數據的方法

1.父組件向子組件傳遞數據

parent.wxmlide

<my-component name="{{name}}" age="{{age}}"></my-component>

parent.js組件化

data: {
  name: 'Peggy',
  age: 25
}

child.jsthis

properties: {
  name: {
    type: String,
    value: '小明'
  },
  age: Number
}

父組件向子組件傳值以屬性的形式,子組件以properties接收,並可指定數據類型type以及默認值value。
在wxml裏可直接以{{name}}的形式使用,而在js中以this.properties.name獲取。spa

2.子組件向父組件傳值

child.js3d

methods: {
  changeName() {
    this.triggerEvent('changeName', {
      name: '李四'
    })
  }
}

parent.wxmlcode

<my-component name="{{name}}" age="{{age}}" bindchangeName="changeName"></my-component>

parent.jscomponent

changeName(event) {
  console.log(event.detail)

  // { name: '李四' }
}

子組件向父組件傳遞數據使用this.triggerEvent方法,這個方法接受3個參數:
this.triggerEvent('myevent', myEventDetail, myEventOption);

myevent爲方法名,
myEventDetail是傳到組件外的數據,
myEventOption爲是否冒泡的選項,有三個參數能夠設置:

bubbles    默認false 事件是否冒泡
composed 默認false 事件是否能夠穿越組件邊界
capturePhase 默認false 事件是否擁有捕獲階段

在父組件監聽事件bindchangeName="changeName",在changeName方法裏有一個event參數,能夠從event.detail裏拿到組件內部傳出來的值。

3、簡單的組件(計數器)

圖片描述

1. 組件功能介紹

這個組件常見於外賣軟件中,用於記錄想要購買的商品的數量。初始化的時候只有一個加號,點擊加號之後出現數字和減號,並最後將數字傳到組件外供外部使用。

2. 建立組件

首先在根目錄建立components文件夾(推薦),而後建立num-controller文件夾(我取的組件名字),在這個文件夾上點擊右鍵新建一個component,名字爲index。

圖片描述

/components/num-controller/index.wxml

<view class="num-controller">
  <image src="images/minus.png" class="{{num <= min ?'hide': ''}}" bindtap="sub"></image>
  <text class="num">{{num}}</text>
  <image src="images/plus.png" bindtap="add"></image>
</view>

這段代碼就是加減兩個按鈕和一個數字。

/components/num-controller/index.json

{
  "component": true,
  "usingComponents": {}
}

這個文件在建立component的時候會自動寫入這段代碼。

/components/num-controller/index.js

Component({
  /**
   * 組件的屬性列表
   */
  properties: {
    nameId: {
      type: String
    },
    num: {
      type: Number,
      value: 0
    },
    int: {
      type: Number,
      value: 1
    },
    min: {
      type: Number,
      value: 0
    }
  },

  /**
   * 組件的初始數據
   */
  data: {

  },

  /**
   * 組件的方法列表
   */
  methods: {
    numChange() {
      this.triggerEvent('numChange', {
        num: this.properties.num,
        nameId: this.properties.nameId
      })
    },
    add() {
      this.setData({
        num: this.properties.num + this.properties.int
      })
      this.numChange()
    },
    sub() {
      this.setData({
        num: this.properties.num - this.properties.int
      })
      this.numChange()
    }
  }
})

在組件內部我定義了4個屬性,properties是父組件傳給子組件的屬性。
nameId用來標識子組件的惟一性,若是在父組件內有多個計數器,子組件想把改變的數據傳給父組件時能夠用到;
num表明計數器中的數字,默認爲0;
int表明加減一次改變多少,默認爲1;
min表明計數器的最小值,等於這個值時減號會消失,默認爲0。

同時在子組件內定義了兩個方法:
add點擊加號觸發,首先改變子組件內部的數字,同時觸發numChange方法將改變的數字傳到組件外部
sub點擊減號觸發,首先改變子組件內部的數字,同時觸發numChange方法將改變的數字傳到組件外部

3. 引入組件

假如我要在index.wxml裏引入組件:

<num-controller nameId="num1" num="{{num1}}" bindnumChange="numChange"></num-controller>
<num-controller nameId="num2" num="{{num2}}" int="{{5}}" min="{{5}}" bindnumChange="numChange"></num-controller>
<num-controller nameId="num3" num="{{num3}}" int="{{100}}" bindnumChange="numChange"></num-controller>

index.json

{
  "usingComponents": {
    "num-controller": "/components/num-controller/num-controller"
  }
}

想在頁面中使用組件必須在json文件裏註冊組件。

index.js

Page({
  data: {
    num1: 0,
    num2: 10,
    num3: 100
  },
  numChange(event) {
    const {num, nameId} = event.detail
    this.setData({
      [nameId]: num
    })
  }
})

data裏的num1, num2, num3是從組件外傳入的num,在numChange方法裏用event.detail能夠拿到組件內部經過this.triggerEvent傳出來的數據,而後根據業務需求作邏輯修改。

4、複雜的組件(篩選面板)

圖片描述

這是一個二級菜單,點擊左邊(一級)會改變右邊(二級)的展現。

1. 建立組件並引入

組件內部:
/components/filter-panel/index.wxml

<view class="filter-panel">
  <view class="panel-container">
    <view class="panel-left">
      ...
    </view>

    <view class="panel-right">
      ...
    </view>
  </view>
</view>

/components/filter-panel/index.json

{
  "component": true,
  "usingComponents": {}
}

組件外部:
假如我要在index.wxml裏引入組件:

<filter-panel></filter-panel>

index.json

{
  "usingComponents": {
    "filter-panel": "/components/filter-panel/index"
  }
}

這樣就成功引入組件啦~(說真的組件化作好了很是舒服,後期會省不少力氣)

2.組件與外部的數據傳遞

(1) 固定數據渲染

組件外部:

index.wxml

<filter-panel list="{{list}}" active="{{active}}"></filter-panel>

index.js

data: {
  list: [
    ['附近', '地鐵站'],
    [['不限', '1km', '2km', '3km'], ['江漢路', '積玉橋', '洪山廣場', '楚河漢街', '光谷廣場']]
  ],
  active: [0, 0]
},

組件內部:

/components/filter-panel/index.js

Component({
  /**
   * 組件的屬性列表
   */
  properties: {
    list: Array,
    active: Array
  },
  /**
   * 組件的方法列表
   */
  methods: {
    ...
  }
})

若是想從組件外向組件內傳遞數據,直接在外部引用時以屬性的方式傳入。
這裏我傳入了2個屬性:
list是二級選擇面板渲染的數據。
active是用戶選擇的選項數據。

到這裏組件已經能夠正常展現了,可是點擊顯示選中項還未實現。

(2) 可變數據渲染

控制組件active項的是外部的數據active: [0, 0],經過組件以屬性的形式傳到了內部。

/components/filter-panel/index.wxml

<view class="filter-panel">
  <view class="panel-container">
    <view class="panel-left">
      <ul>
        <li 
          class="{{active[0] == index? 'active': ''}}" 
          wx:for="{{list[0]}}" 
          wx:key="{{index}}" 
          wx:index="index" 
          data-index="{{index}}"
          bindtap="changeLevel1"
        >
          {{item}}
        </li>
      </ul>
    </view>

    <view class="panel-right">
      <ul>
        <li 
          class="{{active[1] == index? 'active': ''}}" 
          wx:for="{{list[1][active[0]]}}" 
          wx:key="{{index}}" 
          wx:index="index" 
          data-index="{{index}}"
          bindtap="changeLevel2"
        >
          {{item}}
        </li>
      </ul>
    </view>
  </view>
</view>

/components/filter-panel/index.js

Component({
  /**
   * 組件的屬性列表
   */
  properties: {
    list: Array,
    active: Array
  },
  /**
   * 組件的方法列表
   */
  methods: {
    changeLevel() {
      this.triggerEvent('changeLevel', {
        level1: this.properties.active[0],
        level2: this.properties.active[1]
      })
    },
    changeLevel1(event) {
      const index = event.target.dataset.index
      this.setData({
        active: [index, 0]
      })
      this.changeLevel()
    },
    changeLevel2(event) {
      const level2 = 'active[1]'
      const index = event.target.dataset.index
      this.setData({
        [level2]: index
      })
      this.changeLevel()
    }
  }
})

(3) 組件內數據傳到外部

在這個組件內我定義了changeLevel這個方法,每次點擊一級菜單或二級菜單的時候我就用過this.triggerEvent方法把active的值傳到組件外部以供使用。

/components/filter-panel/index.js

methods: {
  changeLevel() {
    this.triggerEvent('changeLevel', {
      level1: this.properties.active[0],
      level2: this.properties.active[1]
    })
  },
  changeLevel1(event) {
    const index = event.target.dataset.index
    this.setData({
      active: [index, 0]
    })
    this.changeLevel()
  },
  changeLevel2(event) {
    const level2 = 'active[1]'
    const index = event.target.dataset.index
    this.setData({
      [level2]: index
    })
    this.changeLevel()
  }
}

5、總結

這個項目裏卻是沒用用到組件間的數據傳遞,因此只是組件和外部的傳遞,還算是比較簡單,可是必定要思考清楚數據的變化狀態。

相關文章
相關標籤/搜索