Vue組件基礎

一、定義

組件 (Component) 是 Vue.js 最強大的功能之一。組件可以擴展 HTML 元素,封裝可重用的代碼。在較高層面上,組件是自定義元素,Vue.js 的編譯器爲它添加特殊功能。在有些情況下,組件也可以表現爲用 is 特性進行了擴展的原生 HTML 元素。所有的 Vue 組件同時也都是 Vue 的實例,所以可接受相同的選項對象 (除了一些根級特有的選項) 並提供相同的生命週期鉤子。


二、全局組件

在很多 Vue 項目中,我們使用 Vue.component 來定義全局組件,緊接着用 new Vue({ el: '#container '}) 在每個頁面內指定一個容器元素。
全局註冊的組件可以用在其被註冊之後的任何 (通過 new Vue) 新創建的 Vue 根實例,也包括其組件樹中的所有子組件的模板中。
註冊組件:
Vue.component( id, [definition] )
參數:

  • {string} id
  • {Function | Object} [definition]

data 必須是一個函數

當我們定義這個 組件時,你可能會發現它的 data 並不是像這樣直接提供一個對象:

data:{
       aaa:"h1"
},

取而代之的是,一個組件的 data 選項必須是一個函數,因此每個實例可以維護一份被返回對象的獨立的拷貝:

data(){
       return {
              aaa:"h1"
          }
 },

基本示例

(一、)定義一個名爲con-a 的新組件

Vue.component("con-a",{
            //這裏的data要用return
            data(){
                return {
                    aaa:"h1"
                }
            },
            template:"<h1>我是{{aaa}}裏面的內容</h1>"//{{aaa}}是前面定義的東西
            })

組件是可複用的 Vue 實例,且帶有一個名字:在這個例子中是 <con-a>。我們可以在一個通過 new Vue 創建的 Vue 根實例中,把這個組件作爲自定義元素來使用:

<div id="all">
        <con-a></con-a>
    </div>
 new Vue({
            el:"#all",
        })

結果
在這裏插入圖片描述


三、局部組件

Vue實例裏面的component是:{}。局部組建無法被其他實例對象使用

示例

例:

    <div id="all">
        <con-a></con-a>
        <con-b></con-b>
        <con-a></con-a>
        <con-b></con-b>
    </div>
    <script>
        new Vue({
            el:"#all",
            components:{
                "con-a":{template:"<h1>我是h1裏面的內容</h1>"},
                "con-b":{template:"<h2>我是h2裏面的內容</h2>"}

            }
        })
    </script>

結果
在這裏插入圖片描述


四、Vue組件的其他寫法

使用template標籤

<template> 元素 是一種用於保存客戶端內容的機制,該內容在頁面加載時不被渲染,但可以在運行時使用JavaScript進行實例化。
在此處的用法


    <template id="conAB">
        <h3>我是用template標籤寫的</h3>//多內容輸出必須有一個根元素
    </template>

全局組件

Vue.component("con-a-b",{template:"#conAB"})

局部組件

 new Vue({
        el:"#tem",
        components:{
            "com-a-b":{template:"#conAB"}
        }
 })

顯示

<div id="tem">
        <com-a-b></com-a-b>
        <con-a-b></con-a-b>
    </div>

結果
在這裏插入圖片描述

使用script標籤

跟前一個僅僅在標籤使用的不同,調用方法相同

   <div id="tem">
        <com-a-b></com-a-b>
        <con-a-b></con-a-b>
    </div>
    <script type="text/template" id="conAB">
    <h3>我是用template標籤寫的</h3>//多內容輸出必須有一個根元素
    </script>
    <script>
        Vue.component("con-a-b",{template:"#conAB"})
        new Vue({
            el:"#tem",
            components:{
                "com-a-b":{template:"#conAB"}
            }
        })
    </script>

結果
在這裏插入圖片描述


五、組件的複用

你可以將組件進行任意次數的複用:

 <div id="all">
        <con-a></con-a>
        <con-a></con-a>
        <con-a></con-a>
    </div>

在這裏插入圖片描述


六、通過 Prop 向子組件傳遞數據

props單向數據流,父組件向子組件傳遞數據
vue實例

 new Vue({
            el:"#co",
            data:{
                msg:"parent msg"
            }
        })

利用props獲取父級中的數據
props可以是一個數據類型也可以是一個數組,也可以是對象,對象下的數據有3個屬性type,default,require。其中default,require值都是布爾類型值。type有Number,String,Boolean,Array,Object,Function,Symbol。

 <template id="comAB">
     <h3>我是父級傳遞過來的數據->{{aaa}}</h3>
 </template>
Vue.component("comAB",{
            // props:["aaa"],
            props:{
                "aaa":String,
            },
            template:"#comAB"
        })
 <div id="co">
        <com-a-b :aaa="msg">   </com-a-b>// 
 </div>

結果
在這裏插入圖片描述

問題:單項數據裏,所以子級修改父級數據一般是不允許的

解決方法:父級傳遞一個對象或數組給子級
因爲對象或數組是引用類型,指向的是同一個內存空間所以當props數據是這兩個類型時,數據改變時子組件內改變是會影響父組件的。
示例:點擊更改父級中的數據

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
   <title>prop父級向子級傳遞數據</title>
</head>
<body>
    <div id="co">
       我是父級中的數據 {{msg.a}}
        <com-a-b :aaa="msg">   </com-a-b>

    </div>
    <template id="comAB">
        <h3 @click="change">我是父級傳遞過來的數據->{{aaa.a}}</h3>
    </template>
    <script>
        Vue.component("comAB",{
            props:["aaa"],
            template:"#comAB",
            methods:{
                change(){
                    this.aaa.a="zzz";
                }
            }
        })
        new Vue({
            el:"#co",
            data:{
                msg:{a:"parent msg"}
            }
        })
    </script>
</body>
</html>

還有一個注意項:Prop 的大小寫
HTML 中的特性名是大小寫不敏感的,所以瀏覽器會把所有大寫字符解釋爲小寫字符。這意味着當你使用 DOM 中的模板時,camelCase (駝峯命名法) 的 prop 名需要使用其等價的 kebab-case (短橫線分隔命名) 命名:
例如:

   <div id="co">
       我是父元素中數據-> {{msg.a}}
        <com-a-b :aa-a="msg">   </com-a-b>//此處講aaA改爲aa-a

    </div>
    <template id="comAB">
        <h3 @click="change">我是父級傳遞過來的數據->{{aaA.a}}</h3>//此處利用駝峯式命名
    </template>
    <script>
        Vue.component("comAB",{
            props:["aaA"], //此處利用駝峯式命名
            template:"#comAB",
            methods:{
                change(){
                    this.aaA.a="changes";//此處利用駝峯式命名
                }
            }
        })
        new Vue({
            el:"#co",
            data:{
                msg:{a:"parent msg"}
            }
        })
    </script>

七、父級獲取子級數據

Vue 實例提供了一個自定義事件的系統來解決這個問題。
子組件通過this.$emit()派發事件,父組件利用v-on對事件進行監聽,實現參數的傳遞
調用 $emit 方法並傳入事件的名字,來向父級組件觸發一個事件:

    <template id="ch">
        <h3 @click="send()">子級數據->{{cmsg}}</h3>
    </template>
        <script>
        Vue.component("com",{
            data(){
                return {
                    cmsg:"cMsg"
                }
            },
            template:"#ch",
            methods:{
                send(){
                    this.$emit("child-say",this.cmsg)
                }
            }
	 })
    </script>	 

然後我們可以用 v-on 監聽這個事件,就像監聽一個原生 DOM 事件一樣:

    <div id="co">
        <h3 >父級數據->{{pmsg}}</h3>
        <com @child-say="show"></com>
    </div>
 <script>
      new Vue({
            el:"#co",
            data:{
                pmsg:"pMsg"
            },
            methods:{
                show(msg){
                    this.pmsg=msg;
                }
            }
        })
</script>

結果:點擊自己元素,父級元素獲得子級元素


八、子級與子級間數據傳遞

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>子級與子級間數據傳遞</title>
</head>
<body>
    <div id="co">
        <coma></coma>
        <comb></comb>
    </div>
    <template id="cha">
        <h3 @click="send()">子級A數據->{{cmsga}}</h3>
    </template>
    <template id="chb">
        <h3 @click="send()">子級B數據->{{cmsgb}}</h3>
    </template>
    <script>
        let ev=new Vue();
        Vue.component("coma",{
            data(){
                return {cmsga:"cMsgA"}
            },
            template:"#cha",
            methods:{
                send(){
                    ev.$emit("a-say",this.cmsga)
                }
            },
            mounted(){//此處是mounted()掛載結束後執行
                ev.$on("b-say",msg=>{
                    this.cmsga=msg;
                })
            }
        })
        Vue.component("comb",{
            data(){
                return {cmsgb:"cMsgB"}
            },
            template:"#chb",
            methods:{
                send(){
                    ev.$emit("b-say",this.cmsgb)
                }
            },
            mounted(){//此處是mounted()掛載結束後執行
                ev.$on("a-say",msg=>{
                    this.cmsgb=msg;
                })
            }
            
        })
        new Vue({
            el:"#co"
        })
    </script>
</body>
</html>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章