劍走偏鋒之Vue 元件通訊(一)—通過$parent和$children構建自己的通訊方式

空城裡發表於2019-04-03

在我平常的開發中,很多問題都是見招拆招,遇到了便去解決。長此以往,出現了一個大問題,就是會反覆的碰到這個問題,而反覆去解決,因為上次解決的方式不一定能記到。就像你看你幾個月前的程式碼,都覺得:臥槽,誰的程式碼,這麼爛。所以,最好的方式就是總結,不斷總結。

Vue 的簡便之處便在於元件,元件之間的複用讓Vue專案維護起來十分簡便。而其中元件之間的通訊就是重中之重,不管哪一個專案都有元件之間的通訊。而針對不同情況下的元件之間通訊又各不相同,簡直五花八門。像最基礎的props@emit 父子元件通訊,大型專案官方推薦的Vuex全域性狀態管理,小型專案試用的Bus通訊等等,接下來我就總結出幾種劍走偏鋒的幾種元件通訊。

vue 官方api
這張圖片就是Vue 官方api 中的,通過$parent$children就可以訪問元件的例項,拿到例項代表什麼?代表可以訪問此元件的一切方法和data。雖然官方說節制的使用,但是我還是選擇了無視。接下來就該思考下怎麼去拿到指定元件的例項。

這應該是個通用的方法,原理就是通過不斷遍歷找到符合標準的元件例項,通過拿到的元件例項來拿到該例項的方法和data

要注意邊界情況,如在#app上拿$parent得到的是new Vue()的例項,在這例項上再拿$parent得到的是undefined,而在最底層的子元件拿$children是個空陣列。也要注意得到$parent$children的值不一樣,$children 的值是陣列,而$parent是個物件

/**
* @desc 尋找指定元件例項
* @params {String} type 向上查詢還是向下查詢
* @params {Object} context 當前上下文(一般指this,把this 傳進來就可以了)
* @params {String} componentName 要尋找的指定的元件名
*/
function findComponents (type, context, componentName) {
	if (['$parent', '$children'].indexOf(type) < 0) return

	let currentComponent = context[type]
	if (type === '$parent') currentComponent = [currentComponent]
	let designatedCom = null

	if (currentComponent.length) {
		for(const com of currentComponent) {
			const name = com.$options.name

			if (name === componentName) {
				designatedCom = com
				break
			} else {
				designatedCom = findComponents(type, com, componentName)
				if (designatedCom) break
			}
		}
		return designatedCom
	}
複製程式碼

這個方法可以向上向下尋找跨元件的子,父元件的例項,拿到例項後就可以拿到相應的data和方法。

使用此方法需要注意幾點
一、第一個引數必須是['$parent', '$children']中的一種,否則返回undefined
二、該方法必須在mounted生命週期中使用,不然程式碼中的currentComponent.length的值是0,(別問我為什麼,我也不知道為什麼)

然後就可以通過此方法得到你指定的元件例項,當然你可能會問,有Vuex等其他的通訊方法,為什麼要使用這個方法,或者說在什麼情況下合適使用該方法。如果你自己寫了一個自定義通用元件,現在你的組員想用這個元件,但是你把控制元件狀態的值都寫在了Vuex上了,這時候就麻煩了。這時候使用這個方法應該說比較好,不需要其他的外部依賴,即拿即用。 最後說一句,該方法出自iview原始碼中的尋找元件方法,我只是將其稍微改造了下,你可以點此連結檢視iview原始碼。

相關文章