組件是可複用的實例,且帶有一個名字,下面的例子中,button-counter就是一個實例.咱們能夠在一個經過 new Vue 建立的 Vue 根實例中,把這個組件做爲自定義元素來使用
由於組件是可複用的 Vue 實例,因此它們與 new Vue 接收相同的選項,例如 data、computed、watch、methods 以及生命週期鉤子等。僅有的例外是像 el 這樣根實例特有的選項。html
<div id="components-demo"> <button-counter></button-counter> </div>
Vue.component('button-counter',{ data:function () { return{ count:0 } }, template: '<button v-on:click="count++">You clicked me {**加粗文字**{count}}times</button>' }) new Vue({ el:'#components-demo' })
注意:要先註冊組件(Vue.component),再建立vue的實例,不然會出現如下的報錯:
vue.js:634 [Vue warn]: Unknown custom element: <button-counter> - did you register the component correctly? For recursive components, make sure to provide the "name" option.(found in <Root>)
Vue.component('my-component-name', { // ... 選項 ... })
組件名 (W3C:字母全小寫且必須包含一個連字符)
組件名定義方式有兩種:使用 kebab-case或 PascalCase
也就是說 <my-component-name> 和 <MyComponentName> 都是可接受的。vue
組件註冊分爲全局註冊和局部註冊npm
全局註冊的組件能夠用在其被註冊以後的任何 (經過 new Vue) 新建立的 Vue 根實例,也包括其組件樹中的全部子組件的模板中。數組
<div id="global"> <component-a></component-a> <component-b></component-b> <component-c></component-c> </div> Vue.component('component-a',{ data:function () { return{ clicked:0 } }, template:'<button v-on:click="clicked++">You clicked me {{clicked}}times</button>' }) Vue.component('component-b',{ data:function () { return{ clicked:0 } }, template:'<button v-on:click="clicked++">You clicked me {{clicked}}times</button>' }) Vue.component('component-c',{ data:function () { return{ clicked:0 } }, template:'<div><span>You have clicked</span><input type="button" v-model="clicked" v-on:click="clicked++"><span>times.</span></div>' }) new Vue({ el:'#global' })
局部註冊的組件在其子組件中不可用緩存
<div id="part"> <component-a></component-a> <component-b></component-b> <component-c></component-c> </div> var ComponentA = { data:function () { return { clicked:0 } }, template:'<button v-on:click="clicked++">You clicked me {{clicked}}times</button>' } var ComponentB = { data:function () { return { clicked:0 } }, template:'<button v-on:click="clicked++">You clicked me {{clicked}}times</button>' } var ComponentC = { data:function () { return { clicked:0 } }, template:'<button v-on:click="clicked++">You clicked me {{clicked}}times</button>' } new Vue({ el:'#part', components:{ 'component-a':ComponentA, 'component-b':ComponentB, 'component-c':ComponentC, } })
對於 components 對象中的每一個屬性來講,其屬性名就是自定義元素的名字,其屬性值就是這個組件的選項對象。app
Prop 是你能夠在組件上註冊的一些自定義特性。Prop 是你能夠在組件上註冊的一些自定義特性。一個組件默承認以擁有任意數量的 prop,任何值均可以傳遞給任何 prop。一個 prop 被註冊以後,你就能夠像這樣把數據做爲一個自定義特性傳遞進來異步
<div id="prop-demo"> <blog-post title="prop just like data"></blog-post> </div> //給prop傳遞一個靜態值
<div id="blog-post-demo"> <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:title="post.title"></blog-post> </div> //給prop傳遞一個動態值 Vue.component('blog-post', { props: ['likes','title'], template: '<div><strong>{{likes}}</strong><span>{{title}}</span></div>' }) new Vue({ el: '#prop-demo' }) new Vue({ el: '#blog-post-demo', data: { posts: [ {likes:'1',title: 'My journey with Vue'}, {likes:'2',title: 'Blogging with Vue'}, {likes:'3',title: 'Why vue is so fun'} ] } })
<div id="blog-post-demo"> <blog-post v-for="post in posts" v-bind:post="post" v-bind:key="post.id" ></blog-post> </div> Vue.component('blog-post', { props: ['post'], template: '<div><span>{{post.title}}</span></div>' }) //接受一個單獨的 post prop new Vue({ el: '#blog-post-demo', data: { posts: [ {id:'1',title: 'My journey with Vue'}, {id:'2',title: 'Blogging with Vue'}, {id:'3',title: 'Why vue is so fun'} ] } })
傳入一個數字:用 v-bind 綁定async
<blog-post v-bind:likes="42"></blog-post>
傳入一個布爾值:用 v-bind 綁定ide
<blog-post v-bind:is-published="false"></blog-post>
傳入一個數組:用 v-bind 綁定函數
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
傳入一個對象:用 v-bind 綁定
<blog-post v-bind:author="{ name: 'Veronica', company: 'Veridian Dynamics' }" ></blog-post>
傳入一個對象的全部屬性:能夠用一個不帶參數的v-bind來綁定
<blog-post v-bind="post"></blog-post> post: { id: 1, title: 'My Journey with Vue' }
單項數據流
全部的 prop 都使得其父子 prop 之間造成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中,可是反過來則不行。這樣會防止從子組件意外改變父級組件的狀態。
額外的,每次父級組件發生更新時,子組件中全部的 prop 都將會刷新爲最新的值。這意味着你不該該在一個子組件內部改變 prop。
<!--監聽子組件事件--> <div id="blog-posts-events-demo"> <div :style="{ fontSize: postFontSize + 'em' }"> <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post" v-on:enlarge-text="postFontSize += 0.1" ></blog-post> </div> </div> Vue.component('blog-post', { props: ['post'], template: ` <div class="blog-post"> <h3>{{ post.title }}</h3> <button v-on:click="$emit('enlarge-text')"> Enlarge text </button> <div v-html="post.content"></div> </div> ` }) new Vue({ el: '#blog-posts-events-demo', data: { posts: [{title:'I want to be bigger'}], postFontSize: 1 } })
<!--在組件上使用v-model--> <div id="model-demo"> {{value}} <my-com v-model="value"></my-com> <button @click="valueMinus">-1</button> </div> Vue.component('my-com', { props:{ value:{ type:Number } }, template: '<div>{{currentValue}}<button @click="handleClick">+1</button></div>', data: function () { return { currentValue: this.value } }, watch: { value(val) { this.currentValue = val; } }, methods: { handleClick: function () { this.currentValue++; this.$emit('input', this.currentValue); } } }) new Vue({ el: '#model-demo', data: { value: 1 }, methods:{ valueMinus:function () { return this.value-- } } })
Slot是父組件與子組件的通信方式,能夠將父組件的內容顯示在子組件中。
demo實例
<div id="slot-demo"> <say-to pname="Kayee"> 歡迎學習vue.js 的 組件之slot插槽。 </say-to> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> <script> Vue.component('say-to',{ props:['pname'], template:'<div>' + '您好<strong>{{pname}}</strong>' + '<slot></slot>' + '</div>' }) new Vue({ el:'#slot-demo', }) </script>
<div id="slot-couple"> <welcome a="嘉儀"> <<span slot="Kayee">Kayee</span> <<span slot="Crystal">Crystal</span> <<span slot="Jiayi">Jiayi</span> </welcome> </div> Vue.component('welcome',{ props: ['a'], template: '<div>' + '<p>您好{{a}}</p>'+ '<p>您好<slot name="Kayee"></slot> </p>'+ '<p>您好<slot name="Crystal"></slot> </p>'+ '<p>您好<slot name="Jiayi"></slot> </p>'+ '</div>' }) new Vue({ el:'#slot-couple' })
<div id="app"> <base-layout> <template v-slot:header> This is hedaer. </template> <template v-slot:main> This is main. </template> <template v-slot:footer> This is footer. </template> </base-layout> </div> Vue.component('base-layout',{ template:'<div class="container">\n' + ' <header>\n' + ' <slot name="header"></slot>\n' + ' </header>\n' + ' <main>\n' + ' <slot name="main"></slot>\n' + ' </main>\n' + ' <footer>\n' + ' <slot name="footer"></slot>\n' + ' </footer>\n' + ' </div>' })
name用來定義額外的插槽,一個不帶 name 的 <slot> 出口會帶有隱含的名字「default」(即爲默認的插槽)。<template> 元素中的全部內容都將會被傳入相應的插槽。任何沒有被包裹在帶有 v-slot 的 <template> 中的內容都會被視爲默認插槽的內容。
與已經廢棄的slot特性不一樣,新版本使用v-slot: 來代替 slot=" "
注意 v-slot 只能添加在一個 <template> 上 (只有一種例外狀況),這一點和已經廢棄的 slot 特性不一樣。
Vue.component('submit-button',{ template:'<button type="submit">\n' + ' <slot>Submit</slot>\n' + ' </button>' }) <submit-button></submit-button> //按鈕內文字爲Submit <submit-button>POST</submit-button> //按鈕內文字爲POST
<div id="app2"> <comp v-slot="user"> {{user.username}} </comp> </div> var CompA =Vue.component('comp', { template:'<div>' + '<slot :username="usernameA"></slot>' + '</div>', data(){ return { usernameA:'Kayee' } } })
子組件中的usernameA傳到父組件中,綁定在 <slot> 元素上的特性被稱爲插槽 prop
<div id="app1"> <div id="title"> <button @click="changeTab('tab1')">Tab01</button> <button @click="changeTab('tab2')">Tab02</button> </div> <keep-alive> <component v-bind:is="currentTab"></component> </keep-alive> </div> Vue.component('tab1',{ data:function () { return{ count:0 } }, template:'<div class="tab">' + '{{count}}' + '<button @click="addCounter">+1</button>' + '</div>', methods: { addCounter(){ this.count++ } } }) Vue.component('tab2',{ data:function () { return{ count:100 } }, template:'<div class="tab">' + '{{count}}' + '<button @click="subCounter">-1</button>' + '</div>', methods: { subCounter(){ this.count-- } } }) new Vue({ el:'#app1', data:{ currentTab:'tab1' }, methods:{ changeTab(tabName){ this.currentTab = tabName } } })
1.關於is特性來切換tab組件
2.keep-alive 來使數據獲得緩存記錄
Vue.component('async-example',function (resolve,reject) { setTimeout(function () { // 向 `resolve` 回調傳遞組件定義 resolve({ template:'<div>I am async!</div>' }) },1000) })