小程式和 Vue 的區別 [入門]

yaojin發表於2020-02-20

前言

部落格小程式第一版本釋出了 搜尋小程式 ==遙近部落格== , 就可以在手機上看文章了

生命週期

關於Vue的生命週期,你可以看 Vue生命週期, 相比Vue,小程式的生命週期有點特別,它有全域性生命週期、頁面生命週期以及元件生命週期

全域性生命週期

全域性生命週期需要你在app.js檔案中定義,有以下幾個生命週期

onLaunch – 小程式初始化完成,全域性只觸發一次
onShow – 小程式啟動時,或者從後臺進入前臺
onHide – 小程式從前臺進入後臺時執行
onError – 小程式執行指令碼出錯或者api呼叫失敗時執行,會帶上錯誤資訊

==執行順序: onLaunch–> onShow –> onHide==

其中, ==onShow以及 onHiden會多次觸發==,比如你從小程式切換到微信聊天再切換回來,可以監察使用者的行為

頁面生命週期

頁面的生命週期主要有以下幾種:

onLoad
一個頁面只會執行一次, 並且==可以獲取當前頁面的路徑中的 query 引數==

onShow
頁面顯示/切入前臺時觸發,會執行多次

onReady
表示頁面初始渲染完畢, 只會執行一次, ==對介面內容進行設定的API需要該鉤子結束後執行==

onHide
頁面隱藏/切入後臺時觸發,==例如 wx.navigateTo或者tab切換到別的頁面執行==

onUnload
頁面解除安裝時觸發, ==例如 wx.redirectTo或wx.navigateBack到其他頁面時==

==注意點==:當切換頁面需要多次渲染資料改變狀態,建議在onShow中使用,當只需初始化一次的時候,可在onLoad或者onReady中使用。當需要清除定時器時,可在onUnload中使用

==切換頁面時觸發的生命週期==:
當首次載入A頁面,A觸發的生命週期為:onLoad –> onShow –> onReady,從A頁面切換到B頁面時,A頁面觸發onHide,B頁面觸發的生命週期順序與上面一致,當B頁面返回到A頁面時,觸發onUnload,當不清快取,再次進入A頁面時,只觸發onShow

想了解更多,你可以檢視 PageApi

元件生命週期

常用的有以下幾種:

created
元件剛剛被建立,==此時還不能呼叫this.setData方法==

attached
在元件例項進入頁面節點樹時執行, ==此時可以使用this.setData方法,讀取節點資料, 例如wx.createSelectorQuery==

detached
在元件例項被從頁面節點樹移除時執行

想了解更多: 檢視 元件生命週期

頁面/路由 跳轉

在Vue中,我們通過router物件的 push 或者 replce 方法進行路由的跳轉, 已達到顯示對應的頁面,

小程式有所區別, 因為它有tab頁,跳轉會有所區別

wx.switchTab
可以跳轉到對應的tab頁面,==需要在app.json檔案中定義tabBar欄位設定對應的路徑以及名稱==

wx.reLaunch
關閉所有頁面,開啟到應用內的某個頁面
路徑為程式碼包中對應頁面的路徑,可以傳遞引數

wx.redirectTo
關閉當前頁面,跳轉到應用內的某個頁面。但是不允許跳轉到 tabbar 頁面

wx.navigateTo
保留當前頁面,跳轉到應用內的某個頁面。但是不能跳到 tabbar 頁面。使用 wx.navigateBack 可以返回到原頁面。

==頁面跳轉的時候,想傳遞資料==
定義succsee方法, 將需要傳遞的資料進行傳送, 如index頁面跳轉到page1頁面

// index.js
    wx.navigateTo({
      url: '/page1/page1?id=666',
      success: function (res) {
        // 通過eventChannel向被開啟頁面傳送資料
        res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' })
      }
    })

在 page1 中 ==onLoad== 鉤子進行接收

onLoad: function (option) {
    console.log(option) // {id: 666}
    const eventChannel = this.getOpenerEventChannel()
    eventChannel.on('acceptDataFromOpenerPage', function (data) {
      console.log(data) // {data: test}
    })
  }

如果頁面跳轉成功後, 跳轉到的頁面某些資料想傳遞給原來的頁面
在index.js檔案中,在==定義一個events物件==, 接收資料(監聽事件)

events: {
    // 為指定事件新增一個監聽器,獲取被開啟頁面傳送到當前頁面的資料
    acceptDataFromOpenedPage: function(data) {
      console.log(data)
    },
    someEvent: function(data) {
      console.log(data)
    }
    ...
  }

在page1.js檔案中, 傳遞資料(發出事件)

eventChannel.emit('acceptDataFromOpenedPage', {data: 'test'});
    eventChannel.emit('someEvent', {data: 'test'})

想了解更多, 你可以檢視微信路由API

語法相關

資料繫結
在Vue中,我們通過bind來進行硬繫結

<img :src="imgSrc"/>

而在小程式,你需要通過大括號的方式表示

<image src="{{imgSrc}}"></image>

列表展示
在Vue中,我們通過v-for, 小程式我們使用wx:for

顯示與隱藏元素
vue中,使用v-if 和v-show控制元素的顯示和隱藏
小程式中,使用wx-if和hidden控制元素的顯示和隱藏

事件繫結
vue中,我們通過@click 來繫結點選事件,stop時間修飾符來阻止冒泡, 在小程式,你需要使用bindtap來繫結點選事件(傳遞事件的字串名稱), ==catchtap來定義阻止冒泡的點選事件==
或者你可以定義一個wxs檔案, 裡面寫相應的邏輯

<wxs module="wxs" src="./test.wxs"></wxs>
<view id="tapTest" data-hi="WeChat" bindtap="{{wxs.tapName}}"> Click me! </view>

function tapName(event, ownerInstance) {
  console.log('tap wechat', JSON.stringify(event))
}
module.exports = {
  tapName: tapName
}

觸發事件的時候,vue想傳遞資料,只需要在函式中進行傳參即可
小程式事件傳遞引數, 需要在元件的wxml中定義dataset,通過currentTarget物件獲取

<view data-alpha-beta="1" data-alphaBeta="2" bindtap="bindViewTap"> DataSet Test </view>

Page({
  bindViewTap:function(event){
    event.currentTarget.dataset.alphaBeta === 1 //  會轉為駝峰寫法
    event.currentTarget.dataset.alphabeta === 2 // 大寫會轉為小寫
  }
})

資料雙向繫結
vue中,通過使用v-model可以很方便的實現, 小程式需要使用bindinput來繫結一個事件,再setData來改變值

取值
vue中通過this.xxx 讀取, 小程式需要使用this.data.xxx讀取

通訊

開發中, 元件之間通訊幾乎是必不可少的,下面是vue和小程式通訊之間的一些總結

父元件傳遞子元件

==Vue傳遞==
Vue中父元件傳遞資料給子元件,我們通過prop將需要傳遞的資料給到子元件中

<parent>
   <child :list="list"></child> //在這裡繫結list物件
</parent>

子元件定義props物件接受相應的資料

 props:{
    list:{
      type:Array,//type為Array,default為函式
      default(){
        return [
          "hahaxixihehe"//預設初始值
        ]}}
    },//用props屬性進行傳資料,此時子元件已經獲取到list的資料了
       data(){
         return {}  
    }   

==父元件傳遞給子元件的資料,不能改變==

==小程式傳遞==
小程式傳遞跟Vue類似, 一樣通過props傳遞,只是語法有所區別

<articleItem wx:for="{{articles}}" wx:key="{{index}}" articleItem="{{item}}"/>

子元件定義properties物件接受對應的資料

properties: {
    articleItem: {
      type: Object,
      value: {}
    }
  }

子元件與父元件通訊

在Vue中, 子元件跟父元件通訊,通過$emit來實現
在子元件中我們通過 $emit 向父元件傳送一個事件,並且傳遞資料

this.$emit('success',false);

父元件通過繫結自定義事件接受

<app-form v-bind:dialogCreate = "dialogCreate" v-on:success="success(res)"></app-form>

methods: {
     success(res){
        this.dialogCreate = res;
     }
}

小程式中,跟Vue差不多, 只是語法不一樣, 小程式不是 $emit ,而是 使用 ==triggerEvent== 傳送事件給父元件, 然後在wxml中bind: 方法名稱 來繫結自定義事件觸發

兄弟之間通訊

vue中兄弟之間通訊,可以將需要傳遞到的資料放到父元件,父元件提供一個方法給到子元件,子元件觸發方法改變資料, 父元件再將新的資料給到兄弟元件, 讓父做一箇中間人,當然,我們也可以使用事件匯流排(eventBus)來進行

主要是在Vue的原型上新增一個Vue的例項,或者建立一個Vue的例項,需要使用到的地方引入, 我們就使用這個vue的例項通過on 和emit 來實現通訊, 它的原理就是通過公用一個vue的例項來進行事件的發放和監聽,已達到資料共享的目的,==關於小程式兄弟元件通訊,目前比較常用的方法是,通過父元件作為中間人==

父元件獲取子元件

在vue中,父元件呼叫子元件的方法比較簡單,可以給元件定義ref或者通過$children來讀取到子元件,直接呼叫元件對應的方法即可,==ref需要確保你的子元件已經在頁面渲染, 不然沒法獲取==

// 父元件
<template>
  <component-a ref="comA"></component-a>
</template>
<script>
  export default {
    mounted () {
      const comA = this.$refs.comA;
      console.log(comA.title);  // Vue.js
      comA.sayHello();  // 彈窗
    }
  }
</script>

在小程式中,也有類似的方法, 我們可以通過給子元件繫結一個id值, 然後在 通過 ==selectComponent== 函式獲取對應id的元件例項,就可以輕鬆的呼叫子元件的方法和訪問對應的資料了

父元件中我們如下定義

// index.wxml
<test id='test'></test>
<button bindtap="test">觸發子元件方法</button>

// index.js
test () {
    let child = this.selectComponent('#test')
    console.log(child) // 子元件例項
    child.fun() // 呼叫子元件的方法
    console.log(child.data.test) // 讀取子元件的資料或者改變都可以
  }

子元件js檔案

 data: {
    test: '我的子元件資料'
  },
  methods: {
    fun () {
      console.log('我的子元件方法')
    }
  }

子元件獲取父元件

既然我們可以通過$children獲取子元件的,相應的我們子元件可以獲取父組,vue中我們可以通過this.$parent來獲取父元件,這樣就可以輕鬆訪問父的方法或者資料

小程式中,我們可以在子元件使用 ==selectOwnerComponent== 來獲取父元件的例項

全域性通訊方式

vue中如果該資料使用地方較多,推薦使用vuex來管理, 在小程式中,建議使用 globalData 來存放多個地方使用到的資料

vue通訊擴充

vue還有2種用的比較少用的通訊的方式,這些通訊方式適合在一些高階元件

$attrs和$listeners

==它們可以實現父元件的資料傳遞到深層次的子元件中,改變父元件的資料==

我們平時通過prop將資料傳遞給子元件, 子元件需要props物件來進行接收, 但是如果我們沒有在props中接收對應的資料,那麼這個資料就沒法使用的,那麼這些資料去哪裡了呢, 它會作為父元件根元素的attribute顯示在dom元素中

而在子元件中, ==$attrs 可以訪問到沒有給使用到的props屬性==

// 父元件傳遞資料
<Button type='success' @click="test" size="medium" to="/btnTest"></Button>
// 子元件中的prop中我們並不接收to的值
<span>{{this.$attrs}}</span>

這個時候this.$attrs列印的值就是 to 傳遞過來的資料,我們就可以通過v-bind的方式傳遞給更深層次的元件, 為了不讓父元件的attribute中顯示to的值, 我們需要在子元件中設定==inheritAttrs: false==, 這樣你的父元件就不會顯示你子元件中沒在props中接受的資料,保證你的資料安全

// 子元件中的prop中我們並不接收to的值
<span>{{this.$attrs}}</span>
<test v-bind="$attrs"></test> // 傳遞給更深的子元件

那最終的子元件拿到了資料之後,我應該如何改變我父級的資料呢, 這個時候我們就可以在子元件中v-on繫結 $listeners 讓更深層次的子元件可以獲取到父元件中的自定義事件,我們就可以在更深層次的子元件中 $emit 傳送事件,來觸發父元件的方法從而達到資料的更新

<span>{{this.$attrs}}</span>
<test v-bind="$attrs" @test2="handleClick" v-on="$listeners"></test> // 傳遞給更深的子元件
// 更深層次的子元件中
methods: {
    changeParentData () {
      this.$emit("change", 'ninhao') // 爺爺的方法
      this.$emit("test2", 'ninhao') // 父級的方法
    }
  }

provide/inject

剛剛的方法的確幫我們解決了很多的通訊的問題,但是視乎有點麻煩, provide/inject可以更好的幫助我們深層次的通訊

我們可以在父元件中定義provide物件/物件函式,它可以讓所有的子孫元素都可以使用到你在其定義的值

// 父元件中
provide() {
     return {
        color: this.color
     },
     data () {
       return {
         size: 'medium',
         color: 'green'
      }
    }
  },

子元件中通過inject通過key獲取對應的值

inject: ['color']

==需要注意的是, 子元件中獲取到的父元件的值,是不響應的,也就是父改變了,子不會改變==

==如果想父改變子同時改變,可以傳遞的是父級的例項==,那麼父改變的時候,子的資料也會相應的改變,但是這樣會造成不必要的methods等父級資料傳遞

第二種方法就是==通過 observable 方法 來讓你的物件是可監聽的==
這個時候,我們在provide中定義data的值, 這樣確保你傳遞的物件是可響應的, 那麼父級改變的時候,你的子級也會相應的改變了

// 父元件中
provide() {
    this.data = Vue.observable({color: 'green'})
    return {
      data: this.data
    }
  },
methods: {
    changeColor () {
      this.data.color = 'red'
      console.log(this.color,23232)
    }
  }
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章