Vue組件化開發


1、Vue組件化開發思想。

引述:組件化規范Web Components。

  1)、我們希望盡可能多的重用代碼。
  2)、自定義組件的方式不太容易(html、css、js)。
  3)、多次使用組件可能導致沖突。
  4)、Web Components通過創建封裝好功能的定制元素解決上述問題。
  5)Vue部分實現了上述Web Components規范。

 

2、Vue組件注冊。Vue組件注冊注意事項。

  1)、data必須是一個函數。分析函數與普通對象的對比,Vue的data是一個對象,區別於組件的data是一個函數。組件的data是函數,可以形成一個閉包的環境,這可以保證每一個組件都可以擁有一份獨立的數據。
  2)、組件模板內容必須是單個根元素,分析演示實際的效果,比如多個div包了多個button標簽。類比Vue實例的el容器中。
  3)、組件模板內容可以是模板字符串。模板字符串需要瀏覽器提供支持(ES6語法規則)。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <div v-text="msg"></div>
10 
11             <!-- Vue組件注冊成功之后,就可以使用了 -->
12             <!-- 這個組件是一個子組件,因為Vue也是一個組件,子組件寫到Vue父組件當中,形成父子關系。 -->
13             <button-counter></button-counter>
14 
15             <!-- 組件的重用,可以拷貝多份,每個組件相互獨立,不互相影響的。 -->
16             <button-counter></button-counter>
17             <button-counter></button-counter>
18         </div>
19 
20         <script src="vue.js" type="text/javascript"></script>
21         <script type="text/javascript">
22             // Vue的組件化開發,Vue的注冊。參數一是組件的名稱,參數二是組件的內容,是一個對象。
23             // Vue.component('', {
24             //     data: '', //data表示組件數據。
25             //     template: '', // template表示組件模板內容。可以做數據的綁定、分支、事件的操作、循環的結構都可以在這里面使用。
26             // });
27             // Vue的組件化開發,Vue的注冊,下面的語法就將組件注冊成功了。
28             // Vue.component('button-counter', {
29             //     data: function() {
30             //         // 提供一個具體的對象,對象當中存放的具體的數據
31             //         return {
32             //             count: 0,
33             //         }
34             //     },
35             //     // template: '<button @click="count++">點擊了{{count}}次</button>',
36             //  // 組件模板內容必須是單個根元素,分析演示實際的效果
37             //     template: '<div><button @click="counts">點擊了{{count}}次</button><button @click="counts">點擊了{{count}}次</button></div>',
38             //     methods: {
39             //         counts: function() {
40             //             this.count++;
41             //         }
42             //     }
43             // })
44             //---------------------------------------------------------------------------------------
45             Vue.component('button-counter', {
46                 data: function() {
47                     // 提供一個具體的對象,對象當中存放的具體的數據
48                     return {
49                         count: 0,
50                     }
51                 },
52                 // template: '<button @click="count++">點擊了{{count}}次</button>',
53                 // 組件模板內容可以是模板字符串。模板字符串需要瀏覽器提供支持(ES6語法規則)
54                 template: `
55                     <div>
56                     <button @click="counts">點擊了{{count}}次</button>
57                     <button @click="counts">點擊了{{count}}次</button>
58                     </div>
59                 `,
60                 methods: {
61                     counts: function() {
62                         this.count++;
63                     }
64                 }
65             })
66 
67             // 創建Vue對象
68             var vm = new Vue({
69                 el: '#app',
70                 data: { // 對象,區別於組件的data是一個函數。
71                     msg: 'hello world!',
72                 },
73                 methods: {}
74             });
75         </script>
76     </body>
77 </html>

 

3、Vue組件注冊,組件名稱方法。

  1)、短橫線方式。Vue.component('button-counter', {/** ... */});
  2)、駝峰方式,駝峰方式要用到根組件里面,需要換成短橫線方式。如果使用駝峰式命名組件,那么在使用組件的時候,只能在字符串模板中用駝峰的方式使用組件,但是在普通的標簽模板中,必須使用短橫線的方式使用組件。Vue.component('buttonCounter', {/** ... */});

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <Hello-world></Hello-world>
10             <div v-text="msg"></div>
11 
12             <!-- Vue組件注冊成功之后,就可以使用了 -->
13             <!-- 這個組件是一個子組件,因為Vue也是一個組件,子組件寫到Vue父組件當中,形成父子關系。 -->
14             <button-counter></button-counter>
15 
16             <!-- 組件的重用,可以拷貝多份,每個組件相互獨立,不互相影響的。 -->
17             <button-counter></button-counter>
18             <button-counter></button-counter>
19         </div>
20 
21         <script src="vue.js" type="text/javascript"></script>
22         <script type="text/javascript">
23             // Vue的組件化開發,Vue的注冊。參數一是組件的名稱,參數二是組件的內容,是一個對象。
24             // Vue.component('', {
25             //     data: '', //data表示組件數據。
26             //     template: '', // template表示組件模板內容。可以做數據的綁定、分支、事件的操作、循環的結構都可以在這里面使用。
27             // });
28             // Vue的組件化開發,Vue的注冊,下面的語法就將組件注冊成功了。
29             // Vue.component('button-counter', {
30             //     data: function() {
31             //         // 提供一個具體的對象,對象當中存放的具體的數據
32             //         return {
33             //             count: 0,
34             //         }
35             //     },
36             //     // template: '<button @click="count++">點擊了{{count}}次</button>',
37             //  // 組件模板內容必須是單個根元素,分析演示實際的效果
38             //     template: '<div><button @click="counts">點擊了{{count}}次</button><button @click="counts">點擊了{{count}}次</button></div>',
39             //     methods: {
40             //         counts: function() {
41             //             this.count++;
42             //         }
43             //     }
44             // })
45 
46             Vue.component('HelloWorld', {
47                 data: function() {
48                     return {
49                         msg: '您好,Vue!',
50                     }
51                 },
52                 template: '<div>{{msg}}</div>',
53             });
54 
55             //---------------------------------------------------------------------------------------
56             Vue.component('buttonCounter', {
57                 data: function() {
58                     // 提供一個具體的對象,對象當中存放的具體的數據
59                     return {
60                         count: 0,
61                     }
62                 },
63                 // template: '<button @click="count++">點擊了{{count}}次</button>',
64                 // 組件模板內容可以是模板字符串。模板字符串需要瀏覽器提供支持(ES6語法規則)
65                 template: `
66                     <div>
67                     <button @click="counts">點擊了{{count}}次</button>
68                     <button @click="counts">點擊了{{count}}次</button>
69                     <HelloWorld></HelloWorld>
70                     </div>
71                 `,
72                 methods: {
73                     counts: function() {
74                         this.count++;
75                     }
76                 }
77             })
78 
79             // 創建Vue對象
80             var vm = new Vue({
81                 el: '#app',
82                 data: { // 對象,區別於組件的data是一個函數。
83                     msg: 'hello world!',
84                 },
85                 methods: {}
86             });
87         </script>
88     </body>
89 </html>

 

4、Vue組件注冊,局部組件注冊。

  1)、局部組件,只能在注冊他的父組件當中使用,在別的組件中是不可以使用的。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <!-- 使用局部組件 -->
10             <component-a></component-a>
11             <component-b></component-b>
12             <component-c></component-c>
13         </div>
14 
15         <script src="vue.js" type="text/javascript"></script>
16         <script type="text/javascript">
17             /* 通過這種方式注冊的組件只能在父組件中使用,在別的組件中是使用不了的。 */
18             var componentA = {
19                 data: function() {
20                     return {
21                         msg: 'hello world componentA.',
22                     }
23                 },
24                 template: '<div>{{msg}}</div>',
25             };
26             var componentB = {
27                 data: function() {
28                     return {
29                         msg: 'hello world componentB.',
30                     }
31                 },
32                 template: '<div>{{msg}}</div>',
33             };
34             var componentC = {
35                 data: function() {
36                     return {
37                         msg: 'hello world componentC.',
38                     }
39                 },
40                 template: '<div>{{msg}}</div>',
41             };
42 
43             // 創建Vue對象
44             var vm = new Vue({
45                 el: '#app',
46                 data: { // 對象,區別於組件的data是一個函數。
47 
48                 },
49                 methods: {
50 
51                 },
52                 // Vue的局部組件注冊。
53                 components: {
54                     // 將局部組件通過components注冊進來
55                     'componentA': componentA,
56                     'componentB': componentB,
57                     'componentC': componentC
58                 }
59             });
60         </script>
61     </body>
62 </html>

 

5、Vue組件注冊,Vue調式工具vue-devtools用法。

  1)、克隆地址,https://github.com/vuejs/vue-devtools.git
  2)、安裝依賴包npm install。
  3)、構建npm run build。生成一個Chrome擴展的包。
  4)、打開Chrome擴展頁面。加載構建的包。
  5)、選中開發者模式。
  6)、加載已解壓的擴展,選擇shells/chrome。

 

6、Vue組件,組件之間的關系,包含父子關系(祖孫關系)和兄弟關系。組件間數據交互。

1)、父組件向子組件傳值。

  a、組件內部通過props接收傳遞過來的值,它的值是一個數組,數組中可以包含很多的屬性,這些屬性都是從父組件傳輸過來的。
  b、父組件通過屬性將值傳遞給子組件。通過靜態傳遞和動態綁定傳遞屬性。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <!-- 父組件打印 -->
10             <div>{{pmsg}}</div>
11             <!-- 子組件的使用,父組件以屬性的方式將值傳遞給子組件 -->
12             <menu-item title="我是來自父組件的標題" concent="我是父組件的內容!"></menu-item>
13             <!-- 父組件給子組件動態傳值 -->
14             <menu-item v-bind:title="title" concent="我是父組件的內容!"></menu-item>
15             <menu-item :title="title" concent="我是父組件的內容!"></menu-item>
16         </div>
17 
18         <script src="vue.js" type="text/javascript"></script>
19         <script type="text/javascript">
20             // 創建一個組件,父組件向子組件傳值。
21             Vue.component('menu-item', {
22                 props: ['title',
23                     'concent'
24                 ], // 子組件接收父組件傳遞的值
25                 data: function() {
26                     return {
27                         msg: '子組件本身的數據'
28                     }
29                 },
30                 template: '<div>{{msg + " : " + title + " " + concent}}</div>',
31             });
32 
33             // 創建Vue對象
34             var vm = new Vue({
35                 el: '#app',
36                 data: { // 對象,區別於組件的data是一個函數。
37                     pmsg: '父組件中的內容',
38                     title: '我是來自父組件的標題!',
39                 },
40                 methods: {
41 
42                 },
43 
44             });
45         </script>
46     </body>
47 </html>

2)、props屬性名規則。

  a、在props中使用駝峰形式,在html模板中需要使用短橫線的形式。因為dom元素的屬性不區分大小的,如果傳遞駝峰形式就出現問題了。
  b、字符串形式的模板中沒有這個限制。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <!-- 父組件打印 -->
10             <div>{{pmsg}}</div>
11             <!-- 子組件的使用,父組件以屬性的方式將值傳遞給子組件 -->
12             <menu-item menu-title="我是來自父組件的標題" concent="我是父組件的內容!"></menu-item>
13 
14             <!-- 在html模板中需要使用短橫線的形式 -->
15             <!-- 父組件給子組件動態傳值,title值是動態傳值,是父組件里面定義的變量 -->
16             <menu-item v-bind:menu-title="title" concent="我是父組件的內容!"></menu-item>
17             <menu-item :menu-title="title" concent="我是父組件的內容!"></menu-item>
18         </div>
19 
20         <script src="vue.js" type="text/javascript"></script>
21         <script type="text/javascript">
22             // 創建一個組件,父組件向子組件傳值。
23             Vue.component('third-component', {
24                 // 子組件接收父組件傳遞的值
25                 props: ['thirdTitle'],
26                 // 子組件接收父組件傳遞的值menuTitle、concent就可以使用了。
27                 // 這里面指定的就是字符串形式的模板。這里面可以使用駝峰形式的數據是沒有問題的。
28                 template: '<div>{{thirdTitle}}</div>',
29             });
30             Vue.component('menu-item', {
31                 // 子組件接收父組件傳遞的值
32                 props: ['menuTitle',
33                     'concent'
34                 ],
35                 data: function() {
36                     return {
37                         msg: '子組件本身的數據'
38                     }
39                 },
40                 // 子組件接收父組件傳遞的值menuTitle、concent就可以使用了。
41                 // 這里面指定的就是字符串形式的模板。這里面可以使用駝峰形式的數據是沒有問題的。
42                 template: '<div>{{msg + " : " + menuTitle + " " + concent}}<third-component thirdTitle="hello"></third-component></div>',
43             });
44 
45             // 創建Vue對象
46             var vm = new Vue({
47                 el: '#app',
48                 data: { // 對象,區別於組件的data是一個函數。
49                     pmsg: '父組件中的內容',
50                     title: '我是來自父組件的標題!',
51                 },
52                 methods: {
53 
54                 },
55 
56             });
57         </script>
58     </body>
59 </html>

3)、props屬性值規則。

  a、字符串String。
  b、數值Number。
  c、布爾值Boolean。
  d、數組Array。
  e、對象Object。 

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <!-- 第二步、在父組件進行打印輸出 -->
10             <div>{{pmsg}}</div>
11 
12             <!-- 第二步、在子組件進行引用父組件的數據pstr -->
13             <menu-item v-bind:pstr2='pstr' v-bind:pnum2='pnum' v-bind:pboo2='pboo' v-bind:parr2='parr' v-bind:pobj2='pobj'>
14             </menu-item>
15 
16             <br />
17             <menu-item :pstr2='pstr' :pnum2='pnum'></menu-item>
18             <br />
19 
20             <!-- pnum2前面不加冒號就是字符串類型的,加上冒號就是數值number類型 -->
21             <menu-item v-bind:pstr2='pstr' pnum2='pnum'></menu-item>
22         </div>
23 
24         <script src="vue.js" type="text/javascript"></script>
25         <script type="text/javascript">
26             // 父組件向子組件傳值props屬性名類型
27             Vue.component('menu-item', {
28                 /* 第三步、在子組件進行引用父組件傳來的數據 */
29                 props: ['pstr2', 'pnum2', 'pboo2', 'parr2',
30                     'pobj2'
31                 ],
32                 template: `
33                     <div>
34                         <div>{{pstr2}}</div>
35                         <div>{{typeof pnum2}}</div>
36                         <div>{{pboo2}}</div>
37                         <div>{{parr2}}</div>
38                         <ul>
39                             <li v-bind:key='index' v-for='(item,index) in parr2'>{{item}}</>
40                         </ul>
41                         <div>
42                             <span>{{pobj2.name}}</span>
43                             <span>{{pobj2.age}}</span>
44                         </div>
45                     </div>
46                 `
47             });
48 
49             // 創建Vue對象
50             var vm = new Vue({
51                 el: '#app',
52                 data: { // 對象,區別於組件的data是一個函數。
53                     pmsg: '父組件中內容', // 第一步、在父組件中進行打印顯示
54                     pstr: 'hello', // 第一步、在子組件進行打印顯示,字符串類型
55                     pnum: 12, //數組類型
56                     pboo: true, //布爾類型
57                     parr: ['apple', 'orange', 'banana'], //數組類型
58                     pobj: {
59                         name: '張颯颯',
60                         age: 25,
61                     },
62                 },
63                 methods: {
64 
65                 },
66             });
67         </script>
68     </body>
69 </html>

 

7、Vue組件,子組件向父組件傳值。

  1)、props傳值數據原則,單向數據流,意思就是只允許父組件向子組件傳遞數據,而不允許子組件直接操作props中的數據。如果子組件直接操作props中的數據,數據的控制邏輯就比較復雜,不容易進行控制,單向數據流處理邏輯比較清晰,所以推薦使用單向數據流。
  2)、Vue子組件向父組件傳值的方式,是通過子組件通過自定義事件向父組件傳遞信息。$emit方法名稱攜帶一個參數,這個參數名稱就是自定義事件,這個事件就可以傳遞給父組件,父組件需要監聽這個事件,父組件通過v-on:事件名稱,直接綁定處理事件的名稱,后面跟着事件處理邏輯。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <!-- 第二步、在父組件進行打印輸出 -->
10             <!-- v-bind:style綁定樣式字體大小,可以通過子組件向父組件傳遞信息,通過自定義事件 -->
11             <div v-bind:style='{fontSize:fontSize2 + "px"}'>{{pmsg}}</div>
12 
13             <!-- 第二步、在子組件進行引用父組件的數據pstr -->
14             <menu-item v-bind:parr2='parr' v-on:enlarge-text='handle'></menu-item>
15             <br />
16             <menu-item v-bind:parr2='parr' @enlarge-text='handle'></menu-item>
17         </div>
18 
19         <script src="vue.js" type="text/javascript"></script>
20         <script type="text/javascript">
21             // 父組件向子組件傳值props屬性名類型
22             Vue.component('menu-item', {
23                 /* 第三步、在子組件進行引用父組件傳來的數據 */
24                 props: ['parr2'],
25                 template: `
26                     <div>
27                         <ul>
28                             <li v-bind:key='index' v-for='(item,index) in parr2'>{{item}}</li>
29                         </ul>
30                         <button @click='parr2.push("lemon")'>點擊</button>
31                         
32                         <button @click='$emit("enlarge-text")'>擴大父組件中字體大小</button>
33                     </div>
34                 `
35                 /* <button @click='$emit("")'>擴大父組件中字體大小</button>中的$emit("")固定方法名稱,參數是自定義事件的名稱 */
36                 /* 然后在父組件中進行自定義事件的監聽, */
37             });
38 
39             // 創建Vue對象
40             var vm = new Vue({
41                 el: '#app',
42                 data: { // 對象,區別於組件的data是一個函數。
43                     pmsg: '父組件中內容', // 第一步、在父組件中進行打印顯示
44                     parr: ['apple', 'orange', 'banana'], //數組類型
45                     fontSize2: 10,
46                 },
47                 methods: {
48                     // Vue子組件向父組件傳值的方式
49                     handle: function() {
50                         // 擴大字體大小
51                         this.fontSize2 += 1;
52                     }
53                 },
54             });
55         </script>
56     </body>
57 </html>

3)、子組件通過自定義事件向父組件傳值。子組件通過自定義事件向父組件傳遞信息,$emit方法名稱可以攜帶兩個參數,第二個參數可以是傳遞給父組件的參數。在父組件中通過$event接收到子組件傳輸的數據,$event是固定寫法。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <!-- 第二步、在父組件進行打印輸出 -->
10             <!-- v-bind:style綁定樣式字體大小,可以通過子組件向父組件傳遞信息,通過自定義事件 -->
11             <div v-bind:style='{fontSize:fontSize2 + "px"}'>{{pmsg}}</div>
12 
13             <!-- 第二步、在子組件進行引用父組件的數據pstr -->
14             <menu-item v-bind:parr2='parr' v-on:enlarge-text='handle($event)'></menu-item>
15             <br />
16             <!-- $event是固定寫法,接收子組件傳遞的參數值 -->
17             <menu-item v-bind:parr2='parr' @enlarge-text='handle($event)'></menu-item>
18         </div>
19 
20         <script src="vue.js" type="text/javascript"></script>
21         <script type="text/javascript">
22             // 父組件向子組件傳值props屬性名類型
23             Vue.component('menu-item', {
24                 /* 第三步、在子組件進行引用父組件傳來的數據 */
25                 props: ['parr2'],
26                 template: `
27                     <div>
28                         <ul>
29                             <li v-bind:key='index' v-for='(item,index) in parr2'>{{item}}</li>
30                         </ul>
31                         <button @click='parr2.push("lemon")'>點擊</button>
32                         
33                         <button @click='$emit("enlarge-text",100)'>擴大父組件中字體大小</button>
34                     </div>
35                 `
36                 /* <button @click='$emit("")'>擴大父組件中字體大小</button>中的$emit("")固定方法名稱,參數是自定義事件的名稱 */
37                 /* 然后在父組件中進行自定義事件的監聽, */
38                 /* $emit固定方法,第二個參數可以是子組件向父組件傳遞的參數值 */
39             });
40 
41             // 創建Vue對象
42             var vm = new Vue({
43                 el: '#app',
44                 data: { // 對象,區別於組件的data是一個函數。
45                     pmsg: '父組件中內容', // 第一步、在父組件中進行打印顯示
46                     parr: ['apple', 'orange', 'banana'], //數組類型
47                     fontSize2: 10,
48                 },
49                 methods: {
50                     // Vue子組件向父組件傳值的方式
51                     handle: function(val) {
52                         // 擴大字體大小
53                         this.fontSize2 += val;
54                     }
55                 },
56             });
57         </script>
58     </body>
59 </html>

 

8、Vue組件,組件間數據交互,非父子組件間傳值。

  1)、單獨的事件中心管理組件間的通信。比如兄弟組件之間的數據交互,此時使用props和自定義事件就不好使了,此時就要使用事件中心的管理模式。比如組件A和組件B需要通過事件中心,組件A觸發事件,組件B監聽事件中心的事件,反之亦然。
  2)、監聽事件與銷毀事件。事件中心通過var eventHub = new Vue()即可。eventHub.$on('add-todo',addTodo)用於監聽事件,參數1是自定義事件的名稱,參數2是事件函數。eventHub.$off('add-todo')用於銷毀時間事件,參數1是事件的名稱。
  3)、觸發事件。eventHub.$emit('add-todo',id);參數一,觸發指定的事件名稱,參數二是攜帶的參數。

  1 <!DOCTYPE html>
  2 <html>
  3     <head>
  4         <meta charset="utf-8">
  5         <title></title>
  6     </head>
  7     <body>
  8         <div id="app">
  9             <div>
 10                 <span>事件中心的事件銷毀</span>
 11                 <button @click="handle">銷毀</button>
 12             </div>
 13 
 14             <br />
 15             <menu-tom></menu-tom>
 16 
 17             <br />
 18             <!-- 兄弟組件,相互傳遞數據 -->
 19             <menu-jack></menu-jack>
 20         </div>
 21 
 22         <script src="vue.js" type="text/javascript"></script>
 23         <script type="text/javascript">
 24             // 提供Vue的事件中心,在事件中心可以進行事件的監聽
 25             var hub = new Vue();
 26 
 27             // 兄弟之間組件數據傳遞
 28             Vue.component('menu-tom', {
 29                 data: function() {
 30                     return {
 31                         num: 0,
 32                     }
 33                 },
 34                 template: `
 35                     <div>
 36                         <div>Tom:{{num}}</div>
 37                         <div>
 38                             <button @click='handle'>點擊</button>
 39                         </div>
 40                     </div>
 41                 `,
 42                 /* 點擊按鈕觸發事件 */
 43                 methods: {
 44                     handle: function() {
 45                         // 觸發兄弟組件的事件
 46                         hub.$emit('jack-event', 5);
 47                     }
 48                 },
 49                 // Vue的鈎子函數,Vue聲明周期里面的,mounted鈎子函數一旦被觸發,模板就就緒了,即可以對模板進行操作了。
 50                 mounted: function() {
 51                     // 監聽事件,箭頭函數,接收對方傳遞過來的數據
 52                     hub.$on('tom-event', (val) => {
 53                         // 拿到這對方的數據之后,進行累加操作,val是兄弟組件傳遞過來的
 54                         this.num += val;
 55                     });
 56                 }
 57             });
 58 
 59             // 兄弟組件
 60             Vue.component('menu-jack', {
 61                 data: function() {
 62                     return {
 63                         num: 0,
 64                     }
 65                 },
 66                 template: `
 67                     <div>
 68                         <div>Jack:{{num}}</div>
 69                         <div>
 70                             <button @click='handle'>點擊</button>
 71                         </div>
 72                     </div>
 73                 `,
 74                 /* 點擊按鈕觸發事件 */
 75                 methods: {
 76                     handle: function() {
 77                         // 觸發兄弟組件的事件
 78                         hub.$emit('tom-event', 10);
 79                     }
 80                 },
 81                 // Vue的鈎子函數,Vue聲明周期里面的,mounted鈎子函數一旦被觸發,模板就就緒了,即可以對模板進行操作了。
 82                 mounted: function() {
 83                     // 監聽事件,箭頭函數,接收對方傳遞過來的數據
 84                     hub.$on('jack-event', (val) => {
 85                         // 拿到這對方的數據之后,進行累加操作,val是兄弟組件傳遞過來的
 86                         this.num += val;
 87                     });
 88                 }
 89             });
 90 
 91             // 創建Vue對象
 92             var vm = new Vue({
 93                 el: '#app',
 94                 data: { // 對象,區別於組件的data是一個函數。
 95 
 96                 },
 97                 methods: {
 98                     handle: function() {
 99                         // 事件中心的事件銷毀
100                         hub.$off('tom-event');
101                         hub.$off('jack-event');
102                     }
103                 },
104             });
105         </script>
106     </body>
107 </html>

 

9、Vue組件,組件插槽。組件插槽的作用。

  1)、父組件向子組件傳遞內容,這個內容是模板的內容。上面分析的是數據的交互。
  2)、子組件使用<slot></slot>預留插槽,可以將父組件的中標簽之間的內容展示出來。
  3)、插槽的位置位於子組件的模板中,使用<slot></slot>表示,語法固定。
  4)、使用的時候,使用這個組件的時候通過標簽中的內容傳遞給<slot></slot>表示。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <menu-alert>此處有Bug!!!</menu-alert>
10             <menu-alert>此處有Warn!!!</menu-alert>
11         </div>
12 
13         <script src="vue.js" type="text/javascript"></script>
14         <script type="text/javascript">
15             // 提供Vue的事件中心,在事件中心可以進行事件的監聽
16             var hub = new Vue();
17 
18             // 兄弟之間組件數據傳遞
19             Vue.component('menu-alert', {
20                 /* 插槽的內容是在組件標簽的中間傳遞過來的,如果不傳遞內容,這里有默認顯示 */
21                 template: `
22                     <div>
23                         <strong>Error:</strong>
24                         <slot>默認內容!</slot>
25                     </div>
26                 `,
27             });
28 
29             // 創建Vue對象
30             var vm = new Vue({
31                 el: '#app',
32                 data: { // 對象,區別於組件的data是一個函數。
33 
34                 },
35                 methods: {
36 
37 
38                 },
39             });
40         </script>
41     </body>
42 </html>

 

10、Vue組件,組件插槽。具名插槽用法。

  1)、在子組件模板定義的時候,使用<slot name="插槽名稱"></slot>來定義,也可以省略name的屬性定義,就是默認插槽。
  2)、在父組件中使用的時候,在標簽上面使用slot="插槽名稱"就可以使用該插槽了。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6     </head>
 7     <body>
 8         <div id="app">
 9             <menu-alert>
10                 <p slot='header'>標題信息</p>
11             </menu-alert>
12             <menu-alert>
13                 <p>詳細內容1</p>
14                 <p>詳細內容2</p>
15             </menu-alert>
16             <menu-alert>
17                 <p slot='footer'>底部信息</p>
18             </menu-alert>
19 
20             <br />
21 
22             <menu-alert>
23                 <!-- template臨時包裹內容,並不會渲染到界面上,可以同時把多條內容填充到文本中 -->
24                 <template slot='header'></template>
25                 <p>標題信息1</p>
26                 <p>標題信息2</p>
27             </menu-alert>
28             <menu-alert>
29                 <p>詳細內容1</p>
30                 <p>詳細內容2</p>
31             </menu-alert>
32             <menu-alert>
33                 <template slot='footer'>
34                     <p>底部信息1</p>
35                     <p>底部信息2</p>
36                 </template>
37 
38             </menu-alert>
39         </div>
40 
41         <script src="vue.js" type="text/javascript"></script>
42         <script type="text/javascript">
43             // 提供Vue的事件中心,在事件中心可以進行事件的監聽
44             var hub = new Vue();
45 
46             // 兄弟之間組件數據傳遞
47             Vue.component('menu-alert', {
48                 /* 插槽的內容是在組件標簽的中間傳遞過來的,如果不傳遞內容,這里有默認顯示 */
49                 template: `
50                     <div>
51                         <header>
52                             <slot name='header'></slot>
53                         </header>
54                         <main>
55                             <slot></slot>
56                         </main>
57                         <footer>
58                             <slot name='footer'></slot>
59                         </footer>
60                     </div>
61                 `,
62             });
63 
64             // 創建Vue對象
65             var vm = new Vue({
66                 el: '#app',
67                 data: { // 對象,區別於組件的data是一個函數。
68 
69                 },
70                 methods: {
71 
72 
73                 },
74             });
75         </script>
76     </body>
77 </html>

 

11、Vue組件,組件插槽。作用域插槽。

  1)、應用場景,父組件對子組件的內容進行加工處理。

 1 <!DOCTYPE html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title></title>
 6         <style type="text/css">
 7             .orange {
 8                 color: orange;
 9             }
10         </style>
11     </head>
12     <body>
13         <div id="app">
14             <!-- 應用場景,父組件對子組件的內容進行加工處理。 -->
15             <fruit-list v-bind:list2='list'>
16                 <!-- <template slot-scope='slotProps'> -->
17                 <!-- 父組件提供template標簽,來進行插槽的填充,slot-scopek屬性可以得到子組件中綁定的那個屬性,即子組件綁定的v-bind:info='item'的屬性 -->
18                 <template slot-scope='slotProps'>
19                     <!-- 就得到了子組件的數據了,就可以開始對子組件的數據進行加功處理了。 -->
20                     <strong v-bind:class="orange2" v-if='slotProps.info.id==2'>
21                         {{slotProps.info.name}}
22                     </strong>
23 
24                 </template>
25 
26             </fruit-list>
27             <br />
28         </div>
29 
30         <script src="vue.js" type="text/javascript"></script>
31         <script type="text/javascript">
32             // 提供Vue的事件中心,在事件中心可以進行事件的監聽
33             var hub = new Vue();
34 
35             // 兄弟之間組件數據傳遞
36             Vue.component('fruit-list', {
37                 props: ['list2'],
38                 /* 插槽的內容是在組件標簽的中間傳遞過來的,如果不傳遞內容,這里有默認顯示 */
39                 template: `
40                     <div>
41                         <li v-bind:key='item.id' v-for='(item,id) in list2'>
42                             <slot v-bind:info='item'>{{item.name}}</slot>
43                         </li>
44                     </div>
45                 `,
46             });
47 
48             // 創建Vue對象
49             var vm = new Vue({
50                 el: '#app',
51                 data: { // 對象,區別於組件的data是一個函數。
52                     orange2: 'orange',
53                     list: [{
54                         id: 1,
55                         name: 'apple',
56                     }, {
57                         id: 2,
58                         name: 'orange',
59                     }, {
60                         id: 3,
61                         name: 'banana',
62                     }, ]
63                 },
64                 methods: {
65 
66 
67                 },
68             });
69         </script>
70     </body>
71 </html>

 

12、基於組件的案例,按照組件化方式實現業務需求。

1)、根據業務功能進行組件化划分。

  a、標題組件,展示文本。
  b、列表組件,列表展示,商品數量變更,商品刪除。
  c、結算組件,計算商品金額。
2)、功能實現步驟。
  a、實現整體布局和樣式效果。
  b、划分獨立的功能組件。
  c、組合所有的子組件形成整體結構。
  d、逐個實現各個組件的功能,包含標題組件,列表組件,結算組件。

  1 <!DOCTYPE html>
  2 <html lang="en">
  3     <head>
  4         <meta charset="UTF-8">
  5         <title>Document</title>
  6         <style type="text/css">
  7             .container {}
  8 
  9             .container .cart {
 10                 width: 300px;
 11                 /*background-color: lightgreen;*/
 12                 margin: auto;
 13             }
 14 
 15             .container .title {
 16                 background-color: lightblue;
 17                 height: 40px;
 18                 line-height: 40px;
 19                 text-align: center;
 20                 /*color: #fff;*/
 21             }
 22 
 23             .container .total {
 24                 background-color: #FFCE46;
 25                 height: 50px;
 26                 line-height: 50px;
 27                 text-align: right;
 28             }
 29 
 30             .container .total button {
 31                 margin: 0 10px;
 32                 background-color: #DC4C40;
 33                 height: 35px;
 34                 width: 80px;
 35                 border: 0;
 36             }
 37 
 38             .container .total span {
 39                 color: red;
 40                 font-weight: bold;
 41             }
 42 
 43             .container .item {
 44                 height: 55px;
 45                 line-height: 55px;
 46                 position: relative;
 47                 border-top: 1px solid #ADD8E6;
 48             }
 49 
 50             .container .item img {
 51                 width: 45px;
 52                 height: 45px;
 53                 margin: 5px;
 54             }
 55 
 56             .container .item .name {
 57                 position: absolute;
 58                 width: 90px;
 59                 top: 0;
 60                 left: 55px;
 61                 font-size: 16px;
 62             }
 63 
 64             .container .item .change {
 65                 width: 100px;
 66                 position: absolute;
 67                 top: 0;
 68                 right: 50px;
 69             }
 70 
 71             .container .item .change a {
 72                 font-size: 20px;
 73                 width: 30px;
 74                 text-decoration: none;
 75                 background-color: lightgray;
 76                 vertical-align: middle;
 77             }
 78 
 79             .container .item .change .num {
 80                 width: 40px;
 81                 height: 25px;
 82             }
 83 
 84             .container .item .del {
 85                 position: absolute;
 86                 top: 0;
 87                 right: 0px;
 88                 width: 40px;
 89                 text-align: center;
 90                 font-size: 40px;
 91                 cursor: pointer;
 92                 color: red;
 93             }
 94 
 95             .container .item .del:hover {
 96                 background-color: orange;
 97             }
 98         </style>
 99     </head>
100     <body>
101         <div id="app">
102             <div class="container">
103                 <my-cart></my-cart>
104             </div>
105         </div>
106         <script type="text/javascript" src="js/vue.js"></script>
107         <script type="text/javascript">
108             var CartTitle = {
109                 props: ['username'],
110                 template: `
111                     <div class="title">{{username }} 的商品</div>
112                 `
113             };
114             var CartList = {
115                 props: ['lists'],
116                 template: `
117                     <div>
118                         <div v-bind:key='id' v-for='(item,id) in lists' class="item">
119                             <img v-bind:src="item.img" />
120                             <div class="name">{{item.name}}</div>
121                             <div class="change">
122                                 <a href="" @click.prevent='sub(item.id)'>-</a>
123                                 <input type="text" class="num" v-bind:value='item.num' @blur='changeNum(item.id,$event)' />
124                                 <a href="" @click.prevent='add(item.id)'>+</a>
125                             </div>
126                             <div class="del" @click='del(item.id)'>×</div>
127                         </div>
128                     </div>
129                 `,
130                 methods: {
131                     del: function(id) {
132                         // 不建議直接在子組件中操作props: ['lists'],的數據。將id傳給父組件,讓父組件進行刪除。
133                         console.log(id);
134                         // 將id傳遞給父組件,通過自定義事件的方式向父組件傳遞信息
135                         this.$emit('cart-del', id);
136                     },
137                     /* 通過事件對象$event可以將參數傳遞過來 */
138                     changeNum: function(id, event) {
139                         // 在父組件進行處理商品數量的變更,告訴父組件改的數量也要傳遞過去。
140                         console.log(id, event.target.value);
141                         // 觸發自定義事件
142                         this.$emit('change-num', {
143                             id: id,
144                             num: event.target.value,
145                             type: 'change',
146                         });
147                     },
148                     sub: function(id) {
149                         this.$emit('change-num', {
150                             id: id,
151                             type: 'sub',
152                         });
153                     },
154                     add: function(id) {
155                         this.$emit('change-num', {
156                             id: id,
157                             type: 'add',
158                         })
159                     },
160                 }
161             };
162             var CartTotal = {
163                 props: ['lists'],
164                 template: `
165                     <div class="total">
166                         <span>總價:{{totalPrice}}</span>
167                         <button>結算</button>
168                     </div>
169                 `,
170                 // 計算屬性
171                 computed: {
172                     totalPrice: function() {
173                         // 計算商品的總價,遍歷數組,讓單價乘以數量再累加。
174                         var total = 0;
175                         this.lists.forEach(item => {
176                             // 計算出總價
177                             total += item.price * item.num;
178                         });
179                         // 將計算的總價返回。
180                         return total;
181                     }
182                 }
183             };
184 
185             // 全局組件,這個全局組件里面包含三個局部子組件。
186             Vue.component('my-cart', {
187                 data: function() {
188                     return {
189                         uname: '張颯颯',
190                         list: [{
191                             id: 1,
192                             name: 'TCL彩電',
193                             price: 1000,
194                             num: 1,
195                             img: 'img/a.jpg'
196                         }, {
197                             id: 2,
198                             name: '機頂盒',
199                             price: 1000,
200                             num: 1,
201                             img: 'img/b.jpg'
202                         }, {
203                             id: 3,
204                             name: '海爾冰箱',
205                             price: 1000,
206                             num: 1,
207                             img: 'img/c.jpg'
208                         }, {
209                             id: 4,
210                             name: '小米手機',
211                             price: 1000,
212                             num: 3,
213                             img: 'img/d.jpg'
214                         }, {
215                             id: 5,
216                             name: 'PPTV電視',
217                             price: 1000,
218                             num: 2,
219                             img: 'img/e.jpg'
220                         }]
221                     }
222                 },
223                 /* 通過父組件監聽子組件的刪除事件,將id傳輸給delCart方法的$event參數 */
224                 template: `
225                     <div class="cart">
226                         <cart-title v-bind:username='uname'></cart-title>
227                         <cart-list v-bind:lists='list' v-on:cart-del='delCart($event)' @change-num='changeNum($event)'></cart-list>
228                         <cart-total v-bind:lists='list'></cart-total>
229                     </div>    
230                 `,
231                 components: {
232                     'cart-title': CartTitle,
233                     'cart-list': CartList,
234                     'cart-total': CartTotal,
235                 },
236                 methods: {
237                     delCart: function(id) {
238                         console.log(id);
239                         // 通過id刪除list集合中的數據,第一步,找到id所對應數據的索引,第二步,根據索引刪除對應的數據。
240                         // 第一步,找到id所對應數據的索引。
241                         var index = this.list.findIndex(item => {
242                             return item.id == id;
243                         });
244 
245                         // 第二步,根據索引刪除對應的數據
246                         this.list.splice(index, 1);
247                     },
248                     changeNum: function(val) {
249                         console.log(val);
250                         // 分為三種情況,輸入域變更,加好變更,減號變更。
251                         if (val.type == 'change') {
252                             // 將子組件傳遞過來的數據num更新list中對應的數據
253                             this.list.some(item => {
254                                 // 如果集合里面的和子組件傳遞過來的匹配相等就進行更新即可。
255                                 if (item.id == val.id) {
256                                     // 此時就完成了更新
257                                     item.num = val.num;
258                                     // 終止遍歷
259                                     return true; // 返回true表示終止遍歷
260                                 }
261                             });
262                         } else if (val.type == 'add') {
263                             this.list.some(item => {
264                                 // 如果集合里面的和子組件傳遞過來的匹配相等就進行更新即可。
265                                 if (item.id == val.id) {
266                                     // 此時就完成了更新
267                                     item.num += 1;
268                                     // 終止遍歷
269                                     return true; // 返回true表示終止遍歷
270                                 }
271                             });
272                         } else if (val.type == 'sub') {
273                             this.list.some(item => {
274                                 // 如果集合里面的和子組件傳遞過來的匹配相等就進行更新即可。
275                                 if (item.id == val.id) {
276                                     // 此時就完成了更新
277                                     item.num -= 1;
278                                     // 終止遍歷
279                                     return true; // 返回true表示終止遍歷
280                                 }
281                             });
282                         }
283                     }
284                 }
285             });
286 
287             var vm = new Vue({
288                 el: '#app',
289                 data: {
290 
291                 }
292             });
293         </script>
294     </body>
295 </html>

效果,如下所示:

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM