Vue元件之props,$emit與$on以及slot分發

王煒發表於2017-10-09

元件例項之間的作用域是孤立存在,要讓它們之間的資訊互通,就必須採用元件的通訊方式

props用於父元件向子元件傳達資訊

1.靜態方式

eg:

<body>
<div id="app">
    <my-component message="hello"></my-component>
</div>
<script>
    Vue.component(`my-component`,{
       template:"<h1>{{message}}</h1>",
       props:[`message`]
    });
    new Vue({
        el: "#app",
    });
</script>
</body>

props以陣列的形式發出自己所需要的資訊(至於父親給不給,就由父親說了算),父作用域給予回應,將message=‘hello’回應回去,兒子得到自己想要的,然後展現在html結構中;

2.動態獲取資料

子元件要得到父親口袋裡面的東西(例項裡面的資料),必須通過v-bind類似於繫結結構屬性的方式傳送給子元件;

eg:

<body>
<div id="app">
    <my-component v-bind:message="message"></my-component>
</div>
<script>
    Vue.component(`my-component`,{
       template:"<div><h1 v-for=`(val,key,index) in message`>{{val}}---{{key}}---{{index}}</h1></div>",
       props:[`message`]
    });
    new Vue({
        el: "#app",
        data:{
            message:{name:"zhangsan",sex:"man",job:"science"}
        }
    });
</script>
</body>
 

渲染結果為:

<div id="app">
   <div>
     <h1>zhangsan---name---0</h1>
     <h1>man---sex---1</h1>
     <h1>science---job---2</h1>
   </div>
</div>

注意:在元件裡面用v-for一定要寫個外層標籤包著v-for,因為大哥只能有一個,不能寫並行標籤

當然也可以傳遞方法給子元件

<body>
<div id="app">
    <my-component v-bind:test="test"></my-component>
</div>
<script>
    Vue.component(`my-component`,{
       template:"<button @click=`test`>{{btn}}</button>",
       props:[`test`],
        data:function(){
           return {
               btn:"按鈕"
           }
        }
    });
    new Vue({
        el: "#app",
        methods:{
            test:function(){
                alert(1)
            }
        }
    });
</script>
</body>

如果傳遞過來的方法中帶有父元件裡面的屬性,也可以用

eg:

<body>
<div id="app">
    <my-component v-bind:test="test"></my-component>
</div>
<script>
    Vue.component(`my-component`,{
       template:"<button @click=`test`>{{btn}}</button>",
       props:[`test`],
        data:function(){
           return {
               btn:"按鈕"
           }
        }
    });
    new Vue({
        el: "#app",
        data:{
            message:"hello,world"
        },
        methods:{
            test:function(){
                alert(this.message)
            }
        }
    });
</script>
</body>

彈出框顯示hello, world

由此我們可以得出:父元件傳遞給子元件的是一個引用地址,但是這個引用是單向的,只能父元件改變的時候子元件獲得的資訊也會發生變化,但是子元件不可以去更改父元件傳遞過來的值,但是可以去加工

eg:

<body>
<div id="app">
    <my-component v-bind:message="message"></my-component>
</div>
<script>
    Vue.component(`my-component`,{
       template:"<button @click=`f`>{{btn}}</button>",
       props:[`message`],
        data:function(){
           return {
               btn:"按鈕"
           }
        },
        methods:{
            f:function(){
                alert(this.message+"  "+"i am god")
            }
        }
    });
    new Vue({
        el: "#app",
        data:{
            message:"hello,world"
        }
    });
</script>
</body>

彈出框顯示:hello,world i am god

eg:

<body>
<div id="app">
    <input type="text" v-model="message">
    <my-component v-bind:message="message"></my-component>
</div>
<script>
    Vue.component(`my-component`, {
        template: "<div><button @click=`reverse`>{{btn}}</button><h1>{{message1}}</h1></div>",
        props: [`message`],
        data: function () {
            return {
                message1: "",
                btn: "反轉"
            }
        },
        methods: {
            reverse: function () {
                this.message1 = this.message.split(``).reverse().join(``)
            }
        }
    });
    new Vue({
        el: "#app",
        data: {
            message: "我愛北京"
        }
    });
</script>
</body>

顯示結果:

1.gif

props可以用來規定自己需要的資料型別,此時props將需求以物件的形式呈現,兒子開始挑剔了,但是父親給他的不符合要求時候,它便會報錯,但是畢竟是父親給的,所以還是會渲染出來

eg:

<body>
<div id=”app”>

<my-component v-bind:message="message"></my-component>

</div>
<script>

Vue.component(`my-component`,{
   template:"<h1>{{message}}</h1>",
   props:{message:Number},

});
new Vue({
    el: "#app",
    data:{
        message:"hello,world"
    }
});

</script>
</body>
顯示結果:

blob.png

關於兒子元件的具體挑剔要求,我直接引個官網文件,就不做過多說明了

Vue.component(`example`, {
props: {

// 基礎型別檢測 (`null` 意思是任何型別都可以)
propA: Number,
// 多種型別
propB: [String, Number],
// 必傳且是字串
propC: {
  type: String,
  required: true
},
// 數字,有預設值
propD: {
  type: Number,
  default: 100
},
// 陣列/物件的預設值應當由一個工廠函式返回
propE: {
  type: Object,
  default: function () {
    return { message: `hello` }
  }
},
// 自定義驗證函式
propF: {
  validator: function (value) {
    return value > 10
  }
}

}
})

$emit與$on,關於這一對兄弟,接觸過angular.js和react的應該都很熟悉,$emit是發射的意思,$on 為監聽,主要用於子元件向父元件傳遞訊號,當然,兒子廣播出去,父親聽不聽就是父親的事情了

eg:

<body>
<div id=”app”>

<h1>{{a}}</h1>
<my-component v-on:ok="add"></my-component>

</div>
<script>

Vue.component(`my-component`, {
    template: "<button @click=`add1`>{{btn}}</button>",
    data:function(){
        return {
            i:10,
            btn:"點選"
        }
    },
   methods:{
        add1:function(){
            this.i++;
            this.$emit("ok")
        }
   }

});
new Vue({
    el: "#app",
    data: {
        a:0
    },
    methods:{
        add:function(){
            this.a++
        }
    }
});

</script>
</body>

顯示如下:

1.gif

父親在監控ok,每當聽到兒子通過$emit傳送過來ok時候,父親就開始執行自己的add方法

當然兒子也可以向父親傳遞資訊過去

eg:

<body>
<div id=”app”>

<h1>{{a}}</h1>
<my-component v-on:ok="add"></my-component>

</div>
<script>

Vue.component(`my-component`, {
    template: "<button @click=`add1`>{{btn}}</button>",
    data:function(){
        return {
            i:10,
            btn:"點選"
        }
    },
    methods:{
        add1:function(){
            this.i++;
            this.$emit("ok",this.i)
        }
    }
});
new Vue({
    el: "#app",
    data: {
        a:0
    },
    methods:{
        add:function(e){
            this.a=e
        }
    }
});

</script>
</body>

顯示效果:

1.gif

兒子將自己的i值傳遞給父親,父親通過接收到的i值將自己的a值更改

監聽原生事件的時候,父親只需要在自己的監聽器上加一個炫酷特效.native,兒子不需要去發廣播,父親就會知道,也就是說有些事情只要老爸願意瞭解,不需要兒子去告訴,他自己也可以選擇知道

eg:

<body>
<div id=”app”>

<h1>{{a}}</h1>
<my-component v-on:click.native="add"></my-component>

</div>
<script>

Vue.component(`my-component`, {
    template: "<div><button @click=`add1`>{{btn1}}</button><button @click=`add2`>{{btn2}}</button></div>",
    data:function(){
        return {
            i:10,
            btn1:"點選1",
            btn2:"點選2"
        }
    },
   methods:{
        add1:function(){
            this.i++;

        },
       add2:function(){
            this.i--
       }
   }

});
new Vue({
    el: "#app",
    data: {
        a:0
    },
    methods:{
        add:function(){
            this.a++
        }
    }
});

</script>
</body>

顯示結果:

1.gif

除了父子直接可以互相通訊外,子元件直接互相通訊,需要一個子元件先將資訊傳遞給父元件,父元件再交給另一個子元件

eg:

<body>
<div id=”app”>

<h1>我是父親且a為:{{a}}</h1>
<child1 v-on:ok="add"></child1>
<child2 v-bind:m="a"></child2>

</div>
<script>

Vue.component(`child1`, {
    template: "<div><h1>我是兒子1號且i為:{{i}}</h1><button @click=`go`>點選傳值</button></div>",
    data:function(){
        return {
            i:100
        }
    },
    methods:{
        go:function(){
            this.i+=100;
            this.$emit("ok",this.i)
        }
    }
});
Vue.component(`child2`,{
    template:"<h2>我是兒子2號且m:{{m}}</h2>",
    props:[`m`]
});
new Vue({
    el: "#app",
    data: {
        a:0
    },
    methods:{
        add:function(e){
            this.a=e
        }
    }
});

</script>
</body>
顯示結果為:

slot分發模式主要用於在元件中間插入標籤或者元件之間的相互巢狀

單個內容插入,可以選擇用slot標籤事先佔個位置

eg:

<body>
<div id=”app”>
<child><span>slot分發</span></child>
</div>
<script>

Vue.component(`child`, {
    template: "<h3>{{message}}<slot></slot></h3>",
    data:function(){
        return {
            message:"我就是:"
        }
    }
});
new Vue({
    el: "#app",
});

</script>
</body>

渲染結果為:

<div id=”app”>

  <h3>我就是:<span>slot分發</span></h3>

</div>

也就是說slot類似於一個插槽,提前站好一個位置,要插入元件中的標籤類似於卡,插入提前站好位置的插槽中

多個標籤插入,就需要按照名字一一對號入座

eg:

<body>
<div id=”app”>

<child>
    <h1 slot="card1">我是1號卡片</h1>
    <h1 slot="card2">我是2號卡片</h1>
    <h1 slot="card3">我是3號卡片</h1>
</child>

</div>
<script>

Vue.component(`child`, {
    template: "<div>{{message}}" +
    "<p>hello world</p>"+
    "<slot name=`card1`></slot>" +
    "<slot name=`card2`></slot>" +
    "<slot name=`card3`></slot>" +
    "</div>",
    data:function(){
        return {
            message:"多個卡片插入:"
        }
    }
});
new Vue({
    el: "#app",
});

</script>
</body>
渲染結果為:

作用域插槽還是有點抽象的,也就是子元件充當插槽,父元件將內容插在子元件上面,並且子元件將值傳遞給父元件,父元件用scope=”props”來接收子元件傳過來的值

<body>
<div id=”app”>

<parent></parent>

</div>
<script>
Vue.component(“son”,{

template:"<ul><slot name=`ww` v-for=`item in items` v-bind:text=`item.name`></slot></ul>",
data:function(){
    return{items:[{name:`張三`},{name:`李四`},{name:"王五"}]
    }
}

});
Vue.component(“parent”,{

template:"<son>" +
             "<template scope=`props` slot=`ww`>" +
               "<li>{{props.text}}</li>" +
             "</template>" +
         "</son>"

});
new Vue({

el:"#app",

})
</script>
</body>
渲染結果為:

eg:

<body>
<div id=”app”>
<dad></dad>
</div>
<script>

Vue.component(`child`, {
   template:"<h3><slot :content=`m` name=`son`></slot></h3>",
    data:function(){
       return{
           m:"我是子元件傳過去的"
       }
    }
});
Vue.component("dad",{
   template:"<child><template scope=`props` slot=`son`><p>{{props.content}}</p></template></child>"
});
new Vue({
    el: "#app",
});

</script>
</body>
渲染結果:

動態元件通過component來動態切換元件的內容

eg:

<body>
<div id=”app”>

<button @click="add1">樣式1</button>
<button @click="add2">樣式2</button>
<button @click="add3">樣式3</button><br>
<component :is="m"></component>

</div>
<script>

Vue.component("child",{
    template:"<div><button v-for=`(val,key) in item` @click=`key`>{{val}}</button></div>",
    data:function(){
        return{
            item:{add1:"樣式1",add2:"樣式2",add3:"樣式3"}
        }
    }
});
var a1={template:"<h1><i style=`color:red`>我是a1</i></h1>"};
var a2={template:"<h1><b style=`color:green`>我是a2</b></h1>"};
var a3={template:"<h1><del style=`color:blue`>我是a3</del></h1>"};
new Vue({
    el: "#app",
    data:{
        m:"a1"
    },
    components:{
        a1:a1,
        a2:a2,
        a3:a3
    },
    methods:{
        add1:function(){
            this.m=`a1`
        },
        add2:function(){
            this.m=`a2`
        },
        add3:function(){
            this.m=`a3`
        }
    }
});

</script>
</body>
渲染結果為:

帶圖原文地址http://www.cnblogs.com/douyae…

相關文章