1. 程式人生 > >Vue2.0筆記——組件2

Vue2.0筆記——組件2

Vue

組件組合

父子組件的通信

組件 A 在它的模板中使用了組件 B。它們之間必然需要相互通信:父組件可能要給子組件下發數據,子組件則可能要將它內部發生的事情告知父組件。
技術分享圖片


首先,需要在Vue實例裏定義一個組件,設置data,然後在這個組件裏再添加一個conponents選項,註意不要添錯位置。
示例:

<div id="app">
    <my-father></my-father>
</div>
//父組件的模板
<template id="fatherTl">
    <div>
        <p>這是父組件</p>
        <p>訪問父組件數據:{{name}},{{age}},姓名:{{user.name}},年齡:{{user.age}}</p>
        <my-child></my-child>
    </div>
</template>
//子組件的模板
<template id="childTl">
    <div>
        <p>這是子組件</p>
        <p>訪問子組件數據:性別:{{sex}},身高:{{height}}</p>
    </div>
</template>
var vm = new Vue({
    el:‘#app‘,
    components:{
        ‘my-father‘:{
            template:‘#fatherTl‘,
            data:function(){
                return {
                    name:‘Xiao‘,
                    age:19,
                    user:{name:‘小冪冪‘,age:31}
                }
            },
            components:{
                ‘my-child‘:{
                    template:‘#childTl‘,
                    data:function(){
                        return {
                            height:166,
                            sex:‘Female‘
                        }
                    }
                }
            }
        }
    }
});

作為子組件my-child,<my-child></my-child>標簽應放在父組件標簽<my-father></my-father>標簽內,而不能是實例掛載元素下。
如果你嘗試直接在父組件模板或子組件模板中通過{{}}模板語法引用則會出現錯誤。
運行此案例,完美運行,你可以通過vue-devtool查看組件結構圖。
目前還沒有通信,只是顯示了一下各自的數據,接下來傳遞數據了。

父向子傳遞數據

父向子傳遞數據,我們需要做的就是將要傳遞的數據綁定到子組件的標簽上,並在子組件內通過props選項來接收。

//father模板中添加
<my-child :childName="user.name" :age="user.age"></my-child>
//接著,在my-child組件中添加選項
props:[‘childName‘,‘age‘]
//最後,我們引用name和age
//my-child模板中
<div>
    <p>這是子組件</p>
    <p>訪問子組件數據:性別:{{sex}},身高:{{height}}</p>
    <p>訪問父組件數據:{{childName}},{{age}}</p>//添加了這一條
</div>

接下來訪問,即可看到數據顯示了。
分析一下,:name和:age,這個冒號“:”後的name和age,就是,props中接收的屬性名,將作為子組件的屬性名,就是說這兩個名可以改,無論改成什麽,最後都需要通過這個名字訪問。
而屬性值就是引號中的user.name,user.age,它直接也是父組件的屬性名

子向父傳遞數據

子向父傳遞書序需要通過事件的方式向上傳遞數據。要做的就是通過$emit方法觸發事件,並添加附加參數(就是屬性),通過事件傳遞數據,父組件中的事件方法接收這參數即可
示例:

//my-child模板中定義一個按鈕,作為媒介,用來觸發
<button @click="send">向上傳遞給父組件數據</button>
//組組件定義
methods:{
    send(){
        this.$emit(‘child-up‘,this.sex,this.height);
    }
}
//my-father組件模板中監聽這個事件
<my-child :name="user.name" :age="user.age"  @child-up="getData"></my-child>
//所以你需要在my-father組件中定義這個getData方法來接收
//但你需註意,你必須提前初始化這些屬性
methods:{
    getData(sex,height){
        this.sex=sex;
        this.height=height;
    }
}
//myfather模板中
<h3>訪問子組件數據,{{sex}},{{height}}</h3>

這樣,通過某個媒介(點擊或其他方式)作為觸發事件的方式,來傳遞數據,並在該實例處監聽該事件,並接收數據。
此處將監聽在my-child標簽中,因my-chlid標簽作為myfather標簽的子組件,所以將getData方法定義在父組件methods中。


單向數據流

props 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,但是反過來不會。這是為了防止子組件無意間修改了父組件的狀態,來避免應用的數據流變得難以理解。

另外,每次父組件更新時,子組件的所有 prop 都會更新為最新值。這意味著你不應該在子組件內部改變 prop。如果你這麽做了,Vue 會在控制臺給出警告。

接下來我們想試著修改父組件內屬性的值,看看是不是會跟著修改,且如果修改prop中屬性是否會出現錯誤。
示例:
代碼較多,我們再新建一個html。我們只註冊使用一個組件,因為Vue實例本身也是一個組件,它是根組件,所以在實例中components中註冊一個組件作為子組件。

<div id="app">
    <p>父組件:{{age}}</p>
    <p><input type="text" v-model="name"></p>
    <hr/>
    <my-component :username="name" :age="age"></my-component>
</div>

<template id="templ">
    <p>子組件中父組件的數據,{{username}}</p>
</template>
var vm = new Vue({
    el:‘#app‘,
    data:{
        name:‘XiaoYao‘,
        age:19
    },
    components:{
        ‘my-component‘:{
            template:‘#templ‘,
            props:[‘username‘,‘age‘]
        }
    }
});

我們已經通過props屬性進行向下傳遞數據了,父組件中我們把name屬性設置為雙向綁定的屬性,以便於修改。
接下來直接在文本框中修改name的值,子組件模板中,值就跟著變了。

那麽,我們開始嘗試著修改它。
示例:

//在組件模板中添加如下按鈕。註意模板中只有一個根元素,需要div包起來
<button @click="change">直接修改父組件傳遞下來的值</button>

//在子組件中定義方法,註意不要寫錯位置,會發生錯誤的
methods:{
    change(){
        this.username=‘I Love You‘;//直接修改它的值
    }
}

運行結果,瀏覽器控制臺發生異常了。

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop‘s value. Prop being mutated: "username"

由此可見,它是不可以更改的,因為它是自動更新值的。

如果你很需要在子組件中修改它的話

當然如果非要這麽做的話,也還是有方法的,因為你很有必要用它。

  • 你可能希望把它當做局部變量處理
  • 你可能需要得到它的值顯示出來,並修改它

那麽你有兩種選擇,

  • 一種是定義局部變量,來操作它。
  • 另一種就是定義計算屬性,依據原值的修改來動態的改變這個計算屬性,而你使用的就是這個計算屬性

接下來我們只需要這樣:

//1.添加屬性,並將傳來的屬性復制給新的局部定義屬性
data:function(){
    return {
        myName:this.username
    }
}
//2.接下來要改變和使用的值就都是myName了
methods:{
    change(){
        this.myName=‘I Love you‘
    }
}
//模板中
<p>子組件中父組件的數據,{{myName}}</p>

對於使用計算屬性,我們可以做:

props: [‘size‘],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}
//接下來就是使用normalizedSize屬性顯示了

以上是單項數據流的問題,如果需要雙向呢,看下面。


雙向數據流,父子雙向綁定

我們使用.sync修飾符,該修飾符在1.0中使用,在2.0中廢除,後又在2.3中重新引用,只是錯了稍加修改,具體情況看官網。

//父組件向下傳遞時,子組件標簽上傳遞的屬性後面添加.sync修飾符
<my-component :username.sync="name" :age="age"></my-component>

然後需要顯式的觸發一個更新事件。

methods:{
    change(){
        this.$emit(‘update:username‘, ‘I Love You‘);
        //this.username=‘I Love you‘;
    }
}

通過$emit事件方法,然後第一個參數,update:是固定寫法,後面是新屬性值,這樣就可以雙向綁定了。使用按鈕觸發不是必需的,只要在某處調用這個觸發方法即可。

假如你向下傳遞的是對象,那麽如果要修改的話會更方便。

我們可以直接修改對象的屬性值而不需要.sync修飾符。

//為父組件定義一個對象,並且顯示他
emp:{salary:6000,workingAge:2,name:‘XiaoChenchen‘}
<p>父組件emp:{{emp}}</p>

//在單擊按鈕方法中直接設置對象的屬性值
this.emp.salary=8000;

單擊按鈕,發現salarys從6000變成了8000,而且不會不會發生任何錯誤。
這是因為對象的引用地址沒有發生改變,改變的只是裏面的屬性,屬性改變並不會影響對象地址。

所以我們建議封裝成對象更方便,但有時也是需要到.sync修飾符的,主要是看情況了。

謝謝觀看,下節繼續講組件,非父子間通信,以及slot插槽分發。


愛自己,更愛需要愛的人。。。

Vue2.0筆記——組件2