1. 程式人生 > >關於vue組件的一個小結

關於vue組件的一個小結

demo例子 data [0 timeout lee ret 框架 討論 添加

用vue進行開發到目前為止也有將近一年的時間了,在項目技術選型的時候隔壁組選 react的時候我們堅持使用vue作為前端的開發框架。雖然兩者思想上的差異不大,但是vue的語法在代碼的可讀性以及後期的維護成本更加的適合,而且最近看到Apache對react的相關許可限制;這裏不討論react和vue的對比哪個好,技術框架沒有最好的,只有適合項目才是最好的。

進入主題。。。。。。。

組件,是vue的核心之一。


我們可以把頁面各個子模塊看成一個組件,可以獨立拆分出來。這樣不僅維護變得簡單了,而且代碼復用性也高。

vue組件分為全局組件和局部組件。組件中屬性和vue實例基本類似,基本可以使用其所有屬性如computed,methods,components,filter,directive.....但data屬性不同,在組件中data是函數,而且數據需要return出來;因為組件可能會被引用多次,就會創建多次實例,如果data是個對象的話那引用到這個組件的地方都講公用一個data這樣就回造成了數據的汙染。如果使用data屬性函數返回一個對象的話就可以解決這個問題,每次引入到這個組件實例的時候就可以在data函數中返回一個初始的數據對象。

組件的介紹

全局組件

使用Vue.component進行全局註冊,所有vue實例都會共享此組件

 1   <div id="app">
 2         {{msg}}
 3         <const-comp></const-comp>
 4     
 5     </div>
 6     <script>
 7         
 8         Vue.component(‘constComp‘, {
 9             template: "<h3>我是全局組件</h3>"
10 
11
}); 12 13 new Vue({ 14 el: "#app", 15 data: { 16 msg: "hello component" 17 } 18 }); 19 20 </script>

局部組件

局部組件只能在引入當前的vue實例中有效,在當前vue實例中components屬性加上引入進來的組件實例即可

    <div id="app">
        {{msg}}
        <!-- <const-comp></const-comp> -->
        <local-comp></local-comp>
    </div>
    <script>
        
        /*
Vue.component(‘constComp‘, { template: "<h3>我是全局組件</h3>" });*/ let localComp = { template: "<div>我是局部組件</div>" }; new Vue({ el: "#app", data: { msg: "hello component" }, components: { localComp } }); </script>

單文件組件(xxx.vue)

其實就是將寫在js中的組件提出到一個vue文件中寫而已,這樣組件更加的好維護以及閱讀性也會好,提取出來了相應的引入即可,不會顯得文件很多行很長。

其主要有<template></template><script></script><style></style>這三個標簽,每個標簽做自己的事。template就像我們在html中寫dom,script寫js代碼當前的組件實例,style寫組件樣式,註意:加上scoped即可使當前樣式只在當前組件生效,組件渲染的時候此組件的dom會加上data-v-xxx屬性來選擇當前組件樣式。如果沒加上scoped的話當前組件的樣式就會在引入這個組件的實例中造成影響

如我寫的一個found.vue文件demo

技術分享
 1 <template>
 2     <div>
 3         <div class="saerchDiv">
 4             <Search
 5             @result-click="resultClick"
 6             @on-change="changeResult"
 7             :results="results"
 8             v-model="searchVal"
 9             position="absolute"
10             auto-scroll-to-top
11             top="46px"
12             @on-focus="onFocus"
13             @on-cancel="onCancel"
14             @on-submit="onSubmit"
15              ref="search"></Search>
16         </div>
17 
18     </div>
19 </template>
20 <script>
21 import {Search} from ‘vux‘;
22 
23 export default {
24     name:"found",
25     data() {
26         return {
27             msg:"found page",
28             // searchVal:"尋找更多好文章",
29             searchVal:"",
30             results:[]
31         }
32     },
33     components:{
34         Search
35     },
36     methods:{
37         resultClick(item) { //選中搜索
38             console.log(item.title);
39         },
40         changeResult(val) { //獲取搜索關鍵字
41             console.log(val);
42             /*this.$http.get(‘‘).then(res => {
43 
44             }).catch(err => {
45 
46             });*/
47 
48             this.results = this.getResults(val);
49         },
50         onFocus(){
51             console.log("on focus");
52             // this.searchVal = ""
53         },
54         onCancel(){
55             console.log("點擊取消按鈕");
56         },
57         onSubmit(){
58             console.log("on submit");
59         },
60         getResults(keyword) { //暫時獲取假數據
61             let rsArr = [];
62             for(let i = 0; i < 6; i++) {
63                 rsArr.push({
64                     title:keyword + (i+1),
65                     other:i //文章id
66                 });
67             }
68             return rsArr;
69         }
70 
71     }
72 }
73 </script>
74 <style scoped>
75 
76     .saerchDiv {
77         height: .75rem;
78         font-size: .27rem;
79     }
80 
81 </style>
View Code

組件的通信

vue組件的通信是vue組件的核心,組件不僅僅是要把模板的內容進行復用;更主要的是組件間要進行通信;組件之間的通信數據傳遞是組件的生命力之一。

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

props可以是一個數據類型也可以是一個數組,也可以是對象,對象下的數據有3個屬性type,default,require。其中default,require值都是布爾類型值。type有Number,String,Boolean,Array,Object,Function,Symbol。如果props數據是對象或數組時默認值default必須是一個函數來返回初始化數據。而且因為對象或數據是引用類型,指向的是同一個內存空間所以當props數據是這兩個類型時,數據改變時子組件內改變是會影響父組件的。

props數據類型及相關樣例

技術分享
 1 // props: [‘propsDataA‘],
 2         props: {
 3             propA: {
 4                 type: String,
 5                 default: "",
 6                 require: true
 7             },
 8             propB: {
 9                 type: Number,
10                 default: 1,
11                 require: false
12             },
13             propC: {
14                 type: Array,
15                 default: function() {
16                     return [];
17                 },
18                 require: true
19             },
20             propD: {
21                 type: Object,
22                 default: function() {
23                     return {};
24                 },
25                 require: true
26             },
27             propE: {
28                 type: Function,
29                 fn: function(val) { //一個時間未滿兩位數前面補零驗證
30                     return val > 9 ? val : ‘0‘ + val;
31                 },
32                 require: true
33             },
34             propF: {
35                 type: Boolean,
36                 default: false,
37                 require: true
38             },
39             propG: [String, Number],
40             propH: Number
41         }
View Code

這裏稍微改動一下局部組件的代碼,父組件向子組件傳遞數據;

 1    <div id="app">
 2         {{msg}}
 3         <!-- <const-comp></const-comp> -->
 4         <local-comp :props-a="info"></local-comp>
 5     </div>
 6     <script>
 7         
 8         /*Vue.component(‘constComp‘, {
 9             template: "<h3>我是全局組件</h3>"
10 
11         });*/
12         let localComp = {
13             template: "<div>我是局部組件<p>父組件傳過來的數據為-->{{propsA}}</p></div>",
14             props: {
15                 propsA: {
16                     type: String,
17                     default: "",
18                     require: true
19                 }
20             }
21         };
22         new Vue({
23             el: "#app",
24             data: {
25                 msg: "hello component",
26                 info: "hello props"
27             },
28             components: {
29                 localComp
30             }
31         });
32 
33     </script>

自定義事件$emit,子組件向父組件通信

這裏還是在原來的基礎上改,子組件使用$emit自定義一個send事件向父組件發送數據

 1    <div id="app">
 2         {{msg}}
 3         <!-- <const-comp></const-comp> -->
 4         <div>子組件數據為---->{{fromChildData}}</div>
 5         <local-comp :props-a="info" @send="getChildData"></local-comp>
 6     </div>
 7     <script>
 8         
 9         /*Vue.component(‘constComp‘, {
10             template: "<h3>我是全局組件</h3>"
11 
12         });*/
13         let localComp = {
14             template: "<div>我是局部組件15                     <p>父組件傳過來的數據為-->{{propsA}}</p>16                     <button @click=‘sendMsg‘>使用$emit子組件向父組件傳遞事件</button>17                 </div>",
18             props: {
19                 propsA: {
20                     type: String,
21                     default: "",
22                     require: true
23                 }
24             },
25             data() {
26                 return {
27                     msg: "子組件數據"
28                 }
29             },
30             methods: {
31                 sendMsg(evt) {
32                     this.$emit(‘send‘, this.msg);
33                 }
34             }
35         };
36         new Vue({
37             el: "#app",
38             data: {
39                 msg: "hello component",
40                 info: "hello props",
41                 fromChildData: ""
42             },
43             components: {
44                 localComp
45             },
46             methods: {
47                 getChildData(val) {
48                     this.fromChildData = val
49                 }
50             }
51         });
52 
53     </script>

非子父組件通信,使用一個空的Vue實例作為一個事件總線監聽數據變化

這種場景用於組件之間不為子父層級關系的時候相關通信,我們使用的那個空vue實例裏也可以放vue的屬性。用這個空的vue實例來$emit自定義一個事件然後再用這個實例來$on監聽自定義事件,從而達到非子父組件之間的通信。(PS:這裏暫時不討論vuex),看demo代碼。demo例子使用了ref組件索引。

    <div id="app">
        {{message}}
        <component-a ref="a"></component-a>
        <component-a ref="b"></component-a>
    </div>
    <script>
        const bus = new Vue({});

        Vue.component(‘component-a‘, {
            data () {
                return {
                    msg: 1
                }
            },
            template: ‘<button @click="handleEvent">傳遞事件</button>‘,
            methods: {
                handleEvent () {

                    this.$parent

                    bus.$emit(‘on-message‘, ‘來自組件 com-a 的內容‘);
                }
            }
        });


        const app = new Vue({
            el: ‘#app‘,
            data: {
                message: ‘‘
            },
            mounted () {
                bus.$on(‘on-message‘, (msg) => {
                    this.message = msg;
                });

                this.$children.msg = 2;

            }
        })
    </script>

slot組件內容分發

單個就默認slot,多個使用具名slot,$slots訪問對應slot,vue2.0新增;因為vue2使用render函數來渲染,所以需要使用this.$slots來訪問slot。this.$slots.xxx訪問具體的slot,即slot中name指定的值 值類型{ [name: string]: ?Array<VNode> }

如果需要給slot添加默認內容的時候直接在slot上寫就可以了,這個時候默認的slot內容所在的作用域就是其所在的組件實例,可以根據其所在的組件來控制slot默認的內容展示如:<slot>{{msg}}</slot>。如果沒有指定默認數據的話slot內容根據其父組件所在的作用域。

當 vue 組件中當需要組件混合使用的時候需要用到內容分發,內容不確定的時候需要用到slot內容分發。

看demo代碼;

 1        <div id="app">
 2         <com-out>
 3             <div slot="b">{{msgB}}</div>
 4             <div slot="a">{{msgA}}</div>
 5             
 6         </com-out>
 7     </div>
 8     <template id="co">
 9         <div>
10             hello 
11             <slot name="a"></slot> 
12             <slot name="b"></slot>
13         </div>
14     </template>
15     <script>
16         Vue.component(‘com-out‘, {
17             template: "#co",
18             mounted() {
19                 console.log("com-out slot" + this.$slots.a[0]);
20             }
21         });
22         new Vue({
23             el: "#app",
24             data: {
25                 msgA: ‘父組件數據a‘,
26                 msgB: ‘父組件數據b‘
27             }
28         })
29     </script>    

遞歸組件

遞歸組件要記住兩點:

1.遞歸組件必須要給組件設置name。

2.要在一個合適的時間(條件)跳出遞歸否則會報棧溢出異常。

 1 <div id="app">
 2         <com :count="1"></com>
 3     </div>
 4     <template id="cr">
 5         <div><com :count="count + 1" v-if="count < 3"></com>{{count}}</div>
 6     </template>
 7     <script>
 8         Vue.component(‘com‘, {
 9             name: ‘comr‘,
10             template: "#cr",
11             props: {
12                 count: {
13                     type: Number,
14                     default: 1
15                 }
16             }
17         })
18         new Vue({
19             el: ‘#app‘
20         })
21 
22 
23     </script>

動態組件

vue動態組件其實就是在組件中使用:is屬性根據值來判斷顯示哪個組件。

 1 <div id="app">  
 2         <button @click="changeCom">點擊讓子組件顯示</button>  
 3         <com v-bind:is="activeCom"></com>  
 4     </div>  
 5 <script>  
 6     new Vue({  
 7         el: ‘#app‘,  
 8         data: {  
 9             activeCom: "comA"  
10         },  
11         methods: {  
12             changeCom: function () {   
13                 let arr = ["comA", "comB", "comC"], index; 
14                 index = Math.ceil(Math.random()*arr.length);
15                 this.activeCom = arr[index];
16             }  
17         },  
18         components: {  
19             comA: {  
20                 template: "<div>組件comA</div>"  
21             },  
22             comB: {   
23                 template: "<div>組件comB</div>"  
24             },  
25             comC: {   
26                 template: "<div>組件comC</div>"  
27             },  
28         }  
29     });  
30 </script>  

異步組件

異步組件在性能上有一定的優勢,不僅加快了渲染時間也減少了不必要的加載;在路由中經常用到

看demo;

<div id="app">
        <child-component></child-component>
        
    </div>
    <script>
        Vue.component(‘child-component‘, function (resolve, reject) {
            window.setTimeout(function () {
                resolve({
                    template: ‘<div>異步組件的內容</div>‘
                })
            }, 2000)
        });
        new Vue({
            el: ‘#app‘
        })
    </script>

組件相關屬性

$nextTick 虛擬dom完成後觸發回調。進行dom操作。不過相關dom操作一般都建議放在指令中,或者自己自定義指令來進行操作,用合適的方式來做合適的事才能達到最優。

$ref當組件使用ref來作為索引時$ref獲取當前組件

關於vue組件的一個小結