专栏首页别先生Vue组件化开发

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>

效果,如下所示:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring之AOP源码理解,Spring4.3.12.RELEASE版本

    1、AOP原理,核心从@EnableAspectJAutoProxy注解进行入手研究。

    别先生
  • Spring之Bean容器源码理解,Spring4.3.12.RELEASE版本

    1、Spring容器创建以及初始化过程。Spring容器的refresh(),是容器的创建以及刷新功能。整个容器就是通过refresh()方法运行完成以后,实现...

    别先生
  • Java攻城狮面试考题

    1 <html> 2 <head> 3 <meta http-equiv="Content-Type" content="text/html; chars...

    别先生
  • 构建Vue.js组件的10个技巧

    Vue.js提供了两种加载组件的方法:一种在Vue实例全局,另一种在组件级别。两种方法都有其自身的优点。

    前端知否
  • Java中GUI的继承体系图

    组件:组件就是对象。 容器组件:是可以存储基本组件和容器组件的组件。 基本组件:是可以使用的组件,但必须依赖容器组件。 注意: 由于Compone...

    黑泽君
  • Vue组件嵌套时生命周期触发的顺序是什么?

    使用过 Vue 的大家,对于生命周期一定都很熟悉,在官方文档一开始,就给我们介绍了 Vue 的生命周期有哪些,是怎么样的顺序。这个难不倒大家。

    歪马
  • Vue 05.组件

    组件: 组件是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可; 组件化和模块...

    LittlePanger
  • 「vue基础」手把手教你编写 Vue 组件(下)

    如果你以前使用过React,那么你已经熟悉了组件相关的生命周期的概念。所谓的组件生命周期,就如同人一般从出生到消亡一样,有几个关键的阶段,在这几个关键的阶段,我...

    前端达人
  • 【译】选择Bit.dev构建组件库的15个理由

    2019年的时候,UI组件库在普及度上有了巨大的飞跃。当然这并不多么令人惊奇,因为像Uber、Airbnb、Booking等等公司都在通过共享的UI组件来保证其...

    腾讯IVWEB团队
  • 干货 | 已配置4000+页面,携程前端组件化探索之“乐高”运营系统

    市场部活动组主要负责各种运营活动的相关开发,分为常规运营活动和定制运营活动。常规运营活动因为组件(模块)具有复用性,并且配置化需求非常多,因此我们建设了一个可视...

    携程技术

扫码关注云+社区

领取腾讯云代金券