Vue的組件是可復用的 Vue 實體,且帶有一個名字 ,我們可以在一個通過 new Vue 創建的 Vue 根實體中,把這個組件作為自定義元素來使用,因為組件是可復用的 Vue 實體,所以它們與 new Vue 接收相同的選項,例如 data、computed、watch、methods 以及生命周期鉤子等,僅有的例外是像 el 這樣根實體特有的選項,
一 創建組件
Vue提供了三種不同的方式來定義組件,分別是:全域組件,私有組件,單檔案組件,接下來就讓我一一道來,
1,全域組件
注冊全域組件非常簡單,也是很常用的一種方式,
1 Vue.component('myCom',{
2 template:'<div><p>我是一個全域<span>組件</span></p></div>'
3 });
Vue.component()方法需要兩個引數:
第一個,組件名稱;
第二個,實體(初始化)物件,可以包含所有使用new方式創建Vue實體時提供的所有屬性,除了el,
注意:組件的實體物件必須提供一個template屬性,用作該組件的HTML代碼模板,且在該模板中有且只能有一個根元素,全域組件的注冊必須在創建Vue實體之前,
小技巧:由于在撰寫JS時,一般沒有HTML代碼提示,創建組件模板代碼會很不方便,所有可以在HTML檔案中使用<template>元素創建模板,然后在組件的template屬性中使用id選擇器參考該模板,
注意:<template>元素必須在new Vue實體接管的根元素外部,
1 <template id="tem">
2 <div>
3 <p>我是組件內的p</p>
4 <span>我是組件中的span</span>
5 </div>
6 </template>
7 <!-- 在HTML中 -->
1 Vue.component('myCom',{ 2 template:'#tem' 3 });
4 //在組件中
2,私有組件
全域創建的組件在所有Vue實體中均可以使用,有時候這并不符合我們的需求,你可以通過以下方式定義Vue實體的私有組件,這些組件只能在該Vue實體根元素內部使用,
1 var vm = new Vue({
2 el:'#app',
3 components:{
4 mycom:{
5 template:'#tem'
6 }
7 }
8 });
通過Vue實體的components屬性可以定義私有組件,該屬性系結一個物件,物件的屬性名是組件名,屬性值是組件實體物件,
3,單檔案組件
Vue的單檔案組件是一個以.vue為后綴名的檔案,由于HTML和JavaScrip不能識別.vue檔案,所以不能直接使用這種方式的組件,必須配合webpack或vue-cli工具才能正確決議.vue檔案,這里的重點是Vue單檔案組件,所以有興趣的同學請移步webpack中文網,
1 <tempalte>
2 //HTML模板
3 </template>
4 <script>
5 //JS代碼
6 </script>
7 <style>
8 //CSS代碼
9 </style>
.vue檔案的名稱就是組件的名稱,其結構非常簡單、清晰:
<template>標簽是組件的HTML模板;
<script>標簽是邏輯代碼;
<style>標簽中是樣式代碼,
二 組件的使用
不管以哪種方式創建Vue組件,我們最終的目的是在HTML頁面中展示出來,本節將詳細介紹Vue組件使用方式,
1,組件標簽
要把我們創建的Vue組件添加到頁面中去,只需要把組件名當做標簽來使用即可,
1 Vue.component('myCom',{
2 template:"#tem"
3 });
4 var vm = new Vue({
5 el:"#app"
6 });
7 //JS部分
1 <div id="app">
2 <my-com></my-com>
3 </div>
4 <!-- HTML部分 -->
小技巧:注冊組件時,建議使用全小寫形式命名,因為HTML標簽要求使用小寫字母,如果你一定要遵守小駝峰命名規則,那么你應該在使用組件時用“-”短橫線把單詞分隔開,
2,組件復用
Vue的組件可以重復使用,
1 <div id="app">
2 <my-com></my-com>
3 <my-com></my-com>
4 <my-com></my-com>
5 </div>
當然,全域組件可以在任何地方使用,而私有組件只能在實體接管元素內部使用,
組件不僅可以簡單的重復使用,還可以嵌套,
1 var vm = new Vue({
2 el:'#app',
3 compontents:{
4 mycom1:{
5 template:'<div>組件一 <mycom2></mycom2></div>'
6 },
7 mycom2:{
8 template:'<div>組件二</div>'
9 }
10 }
11 });
3,另一種使用方式
1 var mycom = {
2 tempalte:'<div id="app2">hello</div>'
3 };
4 var vm = new Vue({
5 el:'#app',
6 render:function(createEl){
7 return createEl(mycom);
8 }
9 });
使用render方式渲染組件:給Vue實體添加render屬性,該屬性值是一個接收一個方法作為引數的函式,引數用于創建Vue組件,return該組件將替代Vue實體接管的#app元素,最終的表現是:頁面上將不再出現#app的div,取而代之的是#app2的div,
這種方式一般配合單檔案組件使用,如果要渲染多個組件,只需要創建多個Vue實體即可,
三 資料傳遞(通信)
1,props傳遞資料(父組件 --> 子組件)
通過在子組件系結props屬性,實作父組件向子組件傳遞資料,props屬性值是一個陣列,陣列元素被定義用來接收父組件傳遞來的資料,然后通過v-bind指令指定陣列元素接收哪些資料,子組件通過訪問props陣列元素就可以訪問到父組件傳遞過來的資料了,就如同訪問data里面的值,
1 <div id="app">
2 <mycom :fromFatherMsg="toSonMsg"></mycom>
3 </div>
4 <!-- HTML部分 -->
1 Vue.component({
2 template:"<div>{{fromFatherMsg}}</div>",
3 props:["fromFatherMsg"]
4 });
5 var vm = new Vue({
6 el:'#app',
7 data:{
8 toSonMsg:'這是給子組件的資料'
9 }
10 });
11 //JS部分
通過上面的例子,我們可以將這個程序簡單的分為三步:
第一步,在子組件上添加一個陣列屬性props,在陣列中定義用來接收資料的變數(以字串形式存盤);
第二步,使用子組件時通過v-bind指令,系結預先定義的接收變數和父組件將要傳遞過來的值;
第三步,在子組件中,如同訪問data中的資料一樣,訪問props陣列元素接收到的資料,
2,$emit傳遞方法(父組件 --> 子組件)
父組件向子組件傳遞方法,是通過自定義事件來實作的,
監聽(同時注冊)自定義事件有兩種方式:組件上使用v-on指令、實體的$on()方法,這里我們將使用第一種方式來做演示,
子組件通過實體的$emit()方法觸發自定義事件,這里的事件名將成為$emit()方法的第一個引數,
1 <div id="app">
2 <mycom @fromFatherFun="toSonFun"></mycom>
3 </div>
4 <!-- HTML部分 -->
1 Vue.component({
2 template:"<div><button @click="myFun">點擊執行來自父組件的方法</button></div>",
3 methods:{
4 myFun:function(){
5 this.$emit('fromFatherFun');
6 }
7 }
8 });
9 var vm = new Vue({
10 el:'#app',
11 methods:{
12 toSonFun(){
13 console.log( "這是給子組件的方法");
14 }
15 });
16 //JS部分
注意:和傳遞資料一樣,子組件不能直接使用父組件的方法,子組件需要通過實體的$emit()方法間接執行來自父組件的方法,
這一程序也可以分為三步:
第一步,使用子組件時,通過v-on指令自定義一個事件;
第二步,系結自定義事件和父組件需要傳遞的方法(指定回呼函式);
第三步,通過子組件的$emit()方法(通過實參指定需要觸發的自定義事件)觸發父組件的方法執行;
3,子組件拋出值(子組件 --> 父組件)
子組件在通過$emit()觸發自定義事件時,可以同時利用方法的第二個引數,向外拋出一個值,回呼函式(上面父組件傳遞下來的方法)需要定義一個形參來接收這個子組件拋出的值,
1 //接上面的例子
2 Vue.component({
3 template:"<div><button @click="myFun">點擊執行來自父組件的方法</button></div>",
4 data(){
5 return {name:'ren'};
6 },
7 methods:{
8 myFun:function(){
9 this.$emit('fromFatherFun',this.name);
10 }
11 }
12 });
13 var vm = new Vue({
14 el:'#app',
15 data:{
16 nameFromSon:null
17 }
18 methods:{
19 toSonFun(data){
20 this.nameFromSon = data;
21 },
22 });
子組件拋出一個值的原理和父組件給子組件傳遞方法原理是一樣的,只不過是不同的用法而已,雖然有點繞,但有用哦,
4,獲取子組件的參考
在使用子組件時,通過系結ref屬性,父組件可以通過Vue實體的$refs屬性拿到子組件的參考,然后就可以直接訪問子組件的屬性或方法了,
1 <div id="app">
2 <mycom ref="sonCom"></mycom>
3 <button @click="printMsgFromSon">點擊列印子組件的資訊</button>
4 </div>
5 <!-- HTML部分 -->
1 Vue.component('mycom',{
2 data:function(){return {name:'ren'}}
3 });
4
5 var vm = new Vue({
6 el:'#app',
7 methods:{
8 printMsgFromSon:function(){
9 console.log(this.$refs.sonCom.name);
10 }
11 }
12 });
13 //JS部分
小技巧:ref屬性不僅可以用在組件上,也可以用在其他標準HTML標簽上,這樣Vue實體就可以獲取到原生的DOM物件了,
注意:即使子組件是Vue實體的私有組件,實體也不能直接使用組件的相關資料,還是需要通過$refs等屬性來間接訪問,
5,兄弟組件間傳值
兄弟組件間實作通信也是采用自定義事件的形式,不過,這一般需要一個空的Vue實體作為中介,配合使用$on()和$emit()實作兄弟組件間的傳值,
1 <div id="app"> 2 <com1></com1> 3 <com2></com2> 4 </div> 5 <template id="com1"> 6 <div> 7 <p>com1組件:{{name}}</p> 8 <button @click="send">將資料發送給com2</button> 9 </div> 10 </template> 11 <template id="com2"> 12 <div> 13 <p>com2組件:{{name}}</p> 14 </div> 15 </template> 16 <!-- HTML部分 -->
1 var event = new Vue(); 2 var vm = new Vue({ 3 el:'#app', 4 components:{ 5 com1:{ 6 template:'#com1', 7 data(){ 8 return{name:'ren'}; 9 }, 10 methods:{ 11 send(){ 12 event.$emit('sendMsg',this.name); 13 } 14 } 15 }, 16 com2:{ 17 template:'#com2', 18 data(){ 19 return {name:null}; 20 }, 21 created(){//因為不知道什么時候會被觸發,所以一般選擇在生命周期鉤子中監聽 22 event.$on('sendMsg',name => {this.name = name;}) 23 //這里需要使用箭頭函式,使其內部的this指向com2 24 } 25 } 26 } 27 });
28 //JS部分
四 其他事項
1,單獨的data
經過上面的學習,你可能已經發現了一個問題:組件中的data屬性是一個函式回傳的物件,
1 Vue.component("mycom",{
2 template:"",
3 data(){
4 return { //some code };
5 }
6 });
7 //這是ES6的寫法,等同于data:function(){return {some code};}
由于data屬性系結的是一個物件,而物件是一個參考型別,為了保證為每個組件維護一份獨立的資料,組件的data屬性必須是一個函式,
2,插槽<slot>
當你讀到這里時,你可能會有一個疑問:既然我們可以用標簽形式使用Vue組件,那么是否可以在開始標簽和結束標簽之間填些內容呢?如果可以的話,該如何做呢?Vue的答案是肯定的,
首先請看下面的例子:
1 <div id="app">
2 <com>我是插槽內容</com>
3 </div>
4 <!-- HTML部分 -->
1 Vue.compenent('com',{
2 template:'<div><p>我是組件</p><slot>我是默認值<slot></div>'
3 });
4 var vm = new Vue({
5 el:'#app'
6 });
7 //JS部分
"我是插槽內容"將替換com組件中<slot>元素,
注意:如果在使用子組件時沒有提供插槽值,那么<slot>元素中的默認值將會生效,前提是你已經定義了這些值,
上面的例子中,組件最終渲染的HTML結構如下:
1 <div>
2 <p>我是組件</p>
3 我是插槽內容
4 </div>
注意:插槽的內容不僅可以是文本內容,還可以是HTML代碼,甚至另一個組件,
如果你需要在一個組件中定義多個插槽,那么你應該需要用到<slot>元素的name屬性,來指定每個插槽應該擁有怎么樣的模板,
1 <div>
2 <com>
3 <template v-slot:"header">
4 <!-- 單獨的HTML模板 -->
5 </template>
6 <div><p>我是默認的模板</p></div>
7 <template v-slot:"footer">
8 <!-- 單獨的HTML模板 -->
9 </template>
10 </com>
11 </div>
12 <!-- HTML部分 -->
1 Vue.component('com',{
2 tempalte:'<div><slot name="header"></slot><slot></slot><slot name="footer"></slot></div>'
3 });
4 var vm = new Vue({
5 el:'#app'
6 });
具名的插槽需要在使用組件時,用<template>元素單獨定義模板,并通過v-slot指令以引數的形式指定:“我是xxx插槽的模板”,
其他所有沒有包裹在<template>元素內的模板,將自動歸為匿名的<slot>元素下面,
3,特殊的嵌套元素
有些 HTML 元素,諸如 <ul>、<ol>、<table> 和 <select>,對于哪些元素可以出現在其內部是有嚴格限制的,而有些元素,諸如 <li>、<tr> 和 <option>,只能出現在其它某些特定的元素內部,要怎樣才能在這些元素中正確的渲染組件呢?幸好,Vue提供了is特性:
1 <table>
2 <tr is="mycom"></tr>
3 </table>
注意:如果你使用字串定義組件模板(例如:template: '...')、或者單檔案組件(.vue)、或者<script>標簽(<script type="text/x-template">),那么你完全可以忽略掉這個限制,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/164486.html
標籤:JavaScript
