一個小程序組件由4個文件組成,分別是wxml
、wxss
、json
、js
,本規範只關注組件的js
,其它自行查看官方文檔。json
在自定義組件的 js
文件中,須要使用 Component()
來註冊組件,Component是一個構造器,可用於定義組件,調用Component構造器時能夠指定組件的屬性、數據、方法等。小程序
Component
的變量能夠分爲如下2種類型:app
properties
:組件外部經過組件屬性的方式傳入內部的數據。異步
不能作會修改數據的運算操做,若是必需要修改數據,能夠先把數據賦值給組件的data
,例如:this.data.a = this.properties.a
,再去作運算操做,有如下兩種狀況:xss
this.properties.a
的數據是基本數據類型,則直接賦值this.properties.a
的數據是引用數據類型,則須要深拷貝一個新的數據以後,再賦值data
:組件內部聲明的數據ide
Component
的函數能夠分爲如下幾種類型:函數
life-cycle-function
:組件生命週期函數event-function
:在組件的methods
下自定義的事件響應函數,與wxml的事件綁定一一對應commen-function
:在組件的methods
下自定義的公共函數,供life-cycle-function
與event-function
調用request-function
:在組件的methods
下自定義的異步請求數據的函數在實際的代碼中,咱們利用註釋把變量和函數分爲以上定義的幾種類型。動畫
下面以小程序的語音消息組件爲例:this
文件路徑:components/voice-messagespa
<view class="voice-message {{(type === 'comment') ? 'comment' : ''}}" catchtap="togglePlay"> <!-- 省略其它代碼 --> </view>
import { isCorrectVal } from '../../utils/index'; const app = getApp(); Component({ properties: { // work:做業的語音 comment:評論的語音 type: { type: String, value: 'work' }, // 語音的地址 voiceUrl: { type: String, value: '' }, // 音頻的長度 voiceLength: { type: Number, value: 0 } }, data: { unsubscribe: function() {}, model: { loading: false, render: false, id: 0, voiceLength: 0, innerAudioContext: null, playing: false, trumpetStatus: [false, false, true], btnLength: '0' } }, /** * life-cycle-function * @description 初始化組件 */ attached: function() { this.data.unsubscribe = app.soundScheduler.subscribe( 'beforePlay', () => { this.data.model.innerAudioContext.stop(); } ); if (!isCorrectVal(this.properties.voiceUrl)) { throw new Error('音頻地址錯誤'); } /* 計算音頻按鈕長度 */ let base = 40; // 10s內基礎長度 let step = 20; // 每10s增長的長度 let stepNum = 0; let length = 40; // 按鈕初始長度 if (this.properties.type === 'comment') { base = 30; step = 15; length = 30; } if (this.properties.voiceLength > 10) { stepNum = Math.ceil((this.properties.voiceLength - 10) / 10); } length = base + step * stepNum; this.setData({ 'model.btnLength': length, 'model.voiceLength': this.properties.voiceLength >= 2 ? this.properties.voiceLength : 2 }); this.data.model.innerAudioContext = wx.createInnerAudioContext(); this.data.model.innerAudioContext.obeyMuteSwitch = false; this.data.model.innerAudioContext.src = this.properties.voiceUrl; this.data.model.innerAudioContext.onPlay(() => { this.onPlay(); }); this.data.model.innerAudioContext.onStop(res => { this.onStop(); }); this.data.model.innerAudioContext.onEnded(res => { this.onStop(); }); this.data.model.innerAudioContext.onError(res => { this.onError(res); }); }, methods: { /** * event-function * @description 切換音頻播放狀態(播放/中止) */ togglePlay: function() { if (this.data.model.loading) return; if (this.data.model.playing) { this.data.model.innerAudioContext.stop(); } else { this.setData( { 'model.loading': true }, () => { app.soundScheduler.dispatch('beforePlay'); app.videoContext.pause(); this.data.model.innerAudioContext.play(); setTimeout(() => { if (this.data.model.loading) { this.setData({ 'model.loading': false }); } }, 3000); } ); } }, /** * common-function * @description 音頻開始播放觸發時的處理函數 */ onPlay: function() { this.setData( { 'model.loading': false }, () => { this.running(); } ); }, /** * common-function * @description 音頻中止播放或者播放結束時的處理函數 */ onStop: function() { this.stop(); }, /** * common-function * @description 音頻播放錯誤時的處理函數 */ onError: function(res) { console.log(res); this.setData( { 'model.loading': false }, () => { this.stop(); } ); }, /** * common-function * @description 啓動音頻小喇叭動畫 */ running: function() { let vm = this; vm.data.model.playing = true; let num = 1; let idx = 1; let timer = null; function animation() { if (!vm.data.model.playing) { clearTimeout(timer); vm.setData({ 'model.trumpetStatus': [false, false, true] }); return; } switch (idx) { case 1: vm.setData({ 'model.trumpetStatus': [true, false, false] }); break; case 2: vm.setData({ 'model.trumpetStatus': [false, true, false] }); break; case 3: vm.setData({ 'model.trumpetStatus': [false, false, true] }); break; } ++idx; if (idx === 4) { idx = 1; } ++num; timer = setTimeout(animation, 600); } timer = setTimeout(animation, 600); }, /** * common-function * @description 中止音頻小喇叭動畫 */ stop: function() { this.data.model.playing = false; } }, /** * life-cycle-function * @description 卸載組件 */ detached: function() { this.data.model.innerAudioContext.stop(); this.data.unsubscribe(); }, });
若是你已經看完了代碼,那麼對這個組件的 代碼執行過程 是否內心已經有數?
這個組件的代碼執行過程是這樣的:
1. 在生命週期鉤子函數attached中初始化組件 2. 組件掛載並渲染完成,到達可響應用戶操做的狀態(這個步驟由小程序自動執行,無需寫額外的代碼) 3. 響應用戶操做 - 用戶點擊語音消息,若是語音沒在播放,則播放語音 - 用戶點擊語音消息,若是語音正在播放,則中止播放 4. 卸載組件
若是內心還沒數,那把除了life-cycle-function
和events-function
的以外的代碼都忽略掉,再看看組件生命週期鉤子函數和用戶交互事件響應函數的代碼與註釋呢?