vue子組件用父組建方法改變執行上下文環境的問題?

請大家試想這樣一個場景,比方說,一個父組建,裡面有很多個子組件,每個子組件內部有他自己的方法和數據。但是他們的方法中有部分相同,比方都有getoptions這個方法,這個方法就是獲取當前子組件裡面的需要的數據的,那麼每個子組件的這個方法唯一的區別就是執行上下文環境不同。那麼我想把它提取到父組建裡面,可通過this.$parent來訪問父組建的方法,那麼只要在子組件裡面使用的時候用call或者apply來改變下執行環境就好了,是不是這個道理。但是自己試了下,得到是不能,請問是否可以?再問,既然數據管理有了vuex,那麼方法管理是否有?


hi!

我的理解是你題目中的getoptions是想更新組件自己內部的data數據,而且很多組件都想共享這個方法。

ok,我們先討論一下vue組件如何復用選項的。據我所知,官方提供了兩種方法,分別是混合(mixins)繼承(extends)

兩者應該都可以達到題主的目的,這裡我們簡單說一下二者的區別:

混合(mixins)是一種靈活的分散式復用 Vue 組件的方式。混合對象可以包含任意組件選項(包括題主想要的methods)。

先看一個官方例子:

// 定義一個混合對象
var myMixin = {
created () {
this.hello()
},
methods: {
hello () {
console.log("hello from mixin!")
}
}
}

// 定義一個使用混合對象的組件
var Component = Vue.extend({
mixins: [myMixin]
})

var component = new Component() // -&> "hello from mixin!"

可以看到,當組件使用一個混合對象時,所有混合對象中的選項都會被混入組件本身的選項中。這樣就實現了組件選項的復用,這裡我們注意到組件的混合對象是一個數組,也就是說我們可以給同一個組件使用多個混合對象,他們將在 vue.extend()里合併到組件里。

接下來我們具體看一下vue在是如何合併混合對象的,這裡要分幾種情況。

1)當混合選項是鉤子函數時,例如created(),同名的鉤子函數將混合成一個數組,按照順序依次被調用。注意:混合組件的鉤子函數將在組件自身鉤子之前被調用。

還是看一個例子:

var mixin = {
created () { console.log(1) }
}
var vm = new Vue({
created () { console.log(2) },
mixins: [mixin]
})
// -&> 1
// -&> 2

2)當混合選項是一個對象時,例如methods、components,將會被混合為同一個對象,如果對象鍵名衝突,取組件自身選項的鍵值對。

舉個例子:

var mixin = {
methods: {
foo () {
console.log("foo")
},
conflicting () {
console.log("from mixin")
}
}
}

var vm = new Vue({
mixins: [mixin],
methods: {
bar () {
console.log("bar")
},
conflicting () {
console.log("from self")
}
}
})

vm.foo() // -&> "foo"
vm.bar() // -&> "bar"
vm.conflicting() // -&> "from self"

3)如果是自定義選項,默認的合併策略是覆蓋已有值。 如果想讓自定義選項以自定義邏輯混合,可以向 Vue.config.optionMergeStrategies 添加一個函數:

Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
// return mergedVal
}

對於大多數對象選項,可以使用 methods 的合併策略:

var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods

這種情況比較少用,這裡就不詳細說明了,有興趣的同學可以參考官方文檔。

另外vue提供了全局混合但是!不推薦使用!因為一旦使用全局混合對象,將會影響到所有之後創建的vue實例,為了不誤導新手,這裡就不舉例了...

另外一種組件復用的方法是繼承(extends),說到繼承,其實大家並不陌生,我們寫的所有組件(component)其實都是繼承自vue實例(Vue)。

繼承和混合的區別主要在一下兩點:

1)一個組件只能有一個繼承源組件。不同於mixins接受一個混合對象數組,extends只能接受一個對象或者函數。

2)合併選項時,組件自身的選項會比繼承過來的選項具有更高的優先順序。

例子:

var CompA = { ... }
var CompB = {
extends: CompA,
...
}

以上就是vue對組件復用提供的兩種方法,接下來我想討論一下題主說的getoptions這個方法是不是應該放在組件里的問題。

如果我沒猜錯,這個getoptions多半是包含一個非同步請求,在組件的某個鉤子節點調用一個api,拿到數據後重置組件的data數據,題主說的上下文環境我猜就是不同組件調用的api的地址和參數不同。

個人觀點,這種將組件和數據請求耦合的方式存在一下幾個問題:

  1. 修改api數據,組件也要跟著修改;
  2. 測試組件需要一個mock的api數據;
  3. 如果同一個頁面包含兩個相同的組件,api數據要請求兩次;
  4. api的參數需要添加或者傳入組件內部才能使用,而這些參數和組件並沒有關係。

將數據請求分散在組件內部是一種很糟糕的設計方案,儘管vue官方的很多例子就是這麼乾的。(我想作者應該是為了化簡demo,但沒想到誤導了很多新人...)

我認為組件需要的只有數據,而並不應該關心數據從哪來。

那麼問題來了,我應該在哪請求數據並如何把數據傳入組件呢?

這裡介紹一種我自己的方案:

我們可以給每個頁面提供一個框架組件,用來控制當前頁面需要的數據,類似於數據中心。然後在這個組件中引入其他組件,通過屬性把數據下發到對應的子組件中。當子組件需要請求數據時,通過事件通知到框架組件,由框架組件統一請求數據,完成後再下發到子組件。

這樣我們就把數據請求和下發統一到一個組件中完成,實現了組件和數據的解耦。

當然,我們也可以使用vuex或者event bus,採用Observable的設計模式實現組件和業務的解耦。

希望可以幫到題主。

最後:請允許我發一下廣告...58招聘FE團隊招收高級前端工程師,如果你覺得自己是vue、react、node大牛,或者尋求一個積極向上的團隊磨練技術,請私信我們!

內容由 58招聘FE 朱雀 提供


這是組件間通信的問題,你應該子組件實例化時通過 props 接收父組件的方法


推薦閱讀:

歷史遺留項目,如何採用vue+webpack的形式改造呢?
Vue.js 官方中文文檔寫的很爛嗎?
jQuery、Ajax 和 JS 之間是什麼關係,如何學習 JS ?
為什麼很多網站的靜態資源會使用獨立的域名?

TAG:前端開發 | JavaScript | Vuejs |