Vue 的組件作用域都是孤立的,不允許在子組件的模板內直接引用父組件的數據。必須使用特定的方法才能實現組件之間的數據傳遞。
首先用腳手架工具 vue-cli 創建一個項目,其中 App.vue 是父組件,components 文件夾下都是子組件。
在 Vue 中,父組件可以使用 props 向子組件傳遞數據。
子組件部分:
這是 header.vue 的 HTML 部分,logo 是在 data 中定義的變量。
如果需要從父組件獲取 logo 的值,就需要使用props: ['logo']。
在 props 添加了元素之后,就不需要在 data 中再添加變量了。
父組件部分:
在調用組件的時候,使用 v-bind 將 logo 的值綁定為 App.vue 中定義的變量 logoMsg。
然后就能將App.vue中 logoMsg 的值傳給 header.vue 了:
子組件主要通過事件傳遞數據給父組件。
子組件部分:
這是 login.vue 的 HTML 部分,當<input>的值發生變化的時候,將 username 傳遞給 App.vue。
首先聲明一個方法setUser,用change事件來調用 setUser。
在 setUser 中,使用了 $emit 來遍歷 transferUser 事件,并傳參this.username。
其中transferUser是一個自定義的事件,功能類似于一個中轉,this.username將通過這個事件傳遞給父組件。
父組件部分:
在父組件 App.vue 中,聲明了一個方法 getUser,用 transferUser 事件調用 getUser 方法,獲取到從子組件傳遞過來的參數 username。
getUser方法中的參數 msg 就是從子組件傳遞過來的參數username。
Vue 沒有直接子對子傳參的方法,建議將需要傳遞數據的子組件,都合并為一個組件。如果一定需要子對子傳參,可以先從子組件傳到父組件,再傳到子組件。
為了便于開發,Vue 推出了一個狀態管理工具 Vuex(詳參博文《Vue進階(五):與 Vuex 的第一次接觸》),可以很方便實現組件之間的參數傳遞。
子組件用Props接收父組件傳來的消息有多種形式:
1.數組形式
props: [data1, data2]
數組形式相當于直接接收消息,不做任何校驗,一般來說,不太建議使用數組形式。
2.簡單對象形式
props: { data1: String, data2: Array}
簡單對象形式對父組件傳遞的值進行了類型校驗,如果傳過來的值類型不一致,控制臺會報錯。
3.復雜對象形式
props: {
data1: {
type: String, //設定類型
required: true, //是否必須
default: 'default value', //默認值
validator (value) { return (value.length < 5) } }, //校驗規則
data2: {
type: Array,
required: true,
default: () => ['', '', '']
}}
復雜對象形式的情況下,作為對象屬性參數可以寫為對象形式,參數對象含有4個屬性,
注意:prop 會在一個組件實例創建之前進行驗證,所以實例的屬性 (如 data、computed 等) 在 default 或 validator 函數中是不可用的。
type 可以是下列原生構造函數中的一個:
String、Number、Boolean、Array、Object、Date、Function、Symbol
type 還可以是一個自定義的構造函數,并且通過 instanceof 來進行檢查確認。
例如,給定下列現成的構造函數:
function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
你可以使用:
Vue.component('blog-post', {
props: {
author: Person
}
})
來驗證 author prop 的值是否是通過 new Person 創建的。
言
我們可能聽過C語言中的傳值和傳指針,在其他語言中,也有傳引用一說,那么他們到底有什么區別呢?如果你還不能準確地分辨,就該好好了解一下了。
傳值
我們在初學C語言的時候就被老師教過,下面的方式是無法交換a和b的值的:
#include<stdio.h> void swap(int a,int b) { int temp = a; a = b; b = temp; printf("swap a = %d,b = %d\n",a,b); } int main(void) { int a = 10; int b = 20; printf("before swap:a = %d,b = %d\n",a,b); swap(a,b); printf("after swap:a = %d,b = %d\n",a,b); return 0; }
運行結果如下:
before swap:a = 10,b = 20 internal swap a = 20,b = 10 after swap:a = 10,b = 20
可以看到,a和b的值最終并沒有被交換。開始時a,b的值為10,20,而最終還是同樣的值。
為什么呢?因為函數參數在傳遞的時候,都是傳原數據的副本,也就是說,swap內部使用的a和b只是最初始a和b的一個副本而已,所以無論在swap函數內部對a和b做任何改變,都不會影響初始的a和b的值。
正因如此,我們常常被告知,不要把直接把結構體直接作為參數,這樣效率會很低。由于結構體本身占用字節數較大,如果直接作為參數,那么將會產生一個較大的”副本“,如此一來,效率也就很低了。
我們再結合下面的圖來理解:
值傳遞
首先圖中方框中的上部分a和b代表了main函數中的a和b,即原始數據,而方框中的下部分a和b代表了函數的參數a和b,即原始數據的“副本”。(后面的圖都是如此,上部分代表原始值,下部分代表函數參數值)。
調用swap函數前后的情形如下:
調用swap前后
由于在swap中永遠只是對a和b的副本進行操作,因此完全不影響原始的a和b的值。最終也不可能達到交換a和b的值的目的。
傳指針
那么為解決上面的問題,我們知道,需要傳指針。其代碼如下:
#include<stdio.h> void swap(int *a,int *b) { int temp = *a; *a = *b; *b = temp; printf("swap a = %d,b = %d\n",*a,*b); } int main(void) { int a = 10; int b = 20; printf("before swap:a = %d,b = %d\n",a,b); swap(&a,&b); printf("after swap:a = %d,b = %d\n",a,b); return 0; }
運行結果:
before swap:a = 10,b = 20 swap a = 20,b = 10 after swap:a = 20,b = 10
可以看到在這種情況下,a,b的值才是真正交換了。
為什么又有傳值,又有傳指針
看到這里,不知道你是否會疑惑,為什么給函數傳遞參數的時候,一會是傳值,一會是傳指針呢?為什么傳指針就能改變參數的值呢?實際上,C語言里,參數傳遞都是值傳遞!也就是說,你認為的傳指針也是傳值,只不過它的值是指針類型罷了。
我們再通過圖來理解前面為什么傳指針就可以交換a,b的值:
傳指針
從圖中可以看出,雖然傳遞給函數的是指向a和b的指針的副本,但是它的副本同樣也是指向a和b,因此雖然不能改變指針的指向,但是能改變參數a和b指向的內容,即改變原始a和b的值。
再看傳指針
如果是為指針p申請一段內存,下面的代碼能達到目的嗎?
#include<stdio.h> #include<stdlib.h> void getMemery(int *p) { /*申請1024個int大小*/ p = malloc(sizeof(int)*1024); if(NULL == p) { printf("malloc failed\n"); p = NULL; } } int main(void) { int *p = NULL; getMemery(p); printf("address of p is %p\n",p); return 0; }
通過前面的內容分析,肯定是達不到預期效果的。
運行結果:
address of p is (nil)
這是為什么呢?我們還是利用前面所知來分析,由于傳遞給getMemory函數的參數都是一個副本,因此函數內的p也是外部p的一個副本,因此即便在函數內部,將p指向了一塊新申請的內存,仍然不會改變外面p的值,即p還是指向NULL。
、
如何修改呢?我們需要傳入p的地址,即指向int類型指針的指針。
#include<stdio.h> #include<stdlib.h> void getMemery(int **p) { /*申請1024個int大小*/ *p = malloc(sizeof(int)*1024); if(NULL == *p) { printf("malloc failed\n"); *p = NULL; } } int main(void) { int *p = NULL; getMemery(&p); printf("address of p is %p\n",p); free(p); p = NULL; return 0; }
運行結果如下:
address of p is 0x144f010
從運行結果可以看到,p的值被改變了。
可配合下面的圖進行理解:
總結
本文總結如下:
本文原地址:https://www.yanbinghu.com/2019/06/20/53981.html
思考
微信公眾號【編程珠璣】:專注但不限于分享計算機編程基礎,Linux,C語言,C++,數據結構與算法,工具,資源等編程相關[原創]技術文章,號內包含大量經典電子書和視頻學習資源。歡迎一起交流學習,一起修煉計算機“內功”,知其然,更知其所以然。
JavaScript 類似,要在 TypeScript 中將函數作為參數傳遞,定義一個函數期望接收回調函數的參數,然后在父函數內部觸發回調函數。 例如,請注意我們在以下示例中調用 foo 函數時如何將 bar 作為回調函數傳遞:
但是,此代碼存在問題。如果復制此代碼到 JavaScript 文件中,不會出現任何語法錯誤,因為我們沒有使用任何 TypeScript 類型。此外,我們遇到了傳遞任何參數值的可能性,這意味著我們可以提供非函數的任意類型作為 foo 的參數,而不會“出錯”,直到代碼執行。因為這里callback被默認解釋為any類型。
使用Function定義函數參數類型
現在我們把 callback 指定為函數類型,
如果我們再傳入非函數,就會報錯了!
定義從 Function 類型返回的期望值
使用 Function 類型是防止由于 JavaScript 中缺少類型定義而導致的常見錯誤的一大步。 但是,使用 Function 類型仍然會為邏輯中的潛在錯誤留下空間。
如果接收回調函數的函數使用回調函數的返回值來運行額外的進程怎么辦? 為了使這個假設更清楚,讓我們對 foo 函數進行更改。
注意 foo 函數不僅調用回調函數,而且還使用回調函數返回的值來獲取該值的平方根,假設回調函數返回的值是一個數字。如果你回顧返回函數的定義,如果這個函數沒有返回任何東西,默認返回值是undefined。
它返回undefined
因此,如果我們將 bar 作為 foo 的回調函數傳遞,在運行時可能可能會出現意外行為。
所以,我們可以通過定義回調函數的返回值的類型來防止 TypeScript 中出現這種意外行為。 于是我們就不能在這里繼續使用Function類型。 相反,使用返回類型的箭頭函數表達式來提供有效的類型定義。 讓我們再修改一下 foo 函數的定義來理解這個概念,
現在我們定義了函數參數的返回值類型,所以現在的bar函數將不再滿足,因為它返回是undefined, 自然它就會報錯。
我們修改一下bar函數,讓它滿足callback的函數簽名,就可以解決了?,F在運行代碼就安全多了。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。