前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue组件化开发

Vue组件化开发

作者头像
别先生
发布2020-04-24 15:47:47
3K0
发布2020-04-24 15:47:47
举报
文章被收录于专栏:别先生别先生

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语法规则)。

代码语言:javascript
复制
 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', {/** ... */});

代码语言:javascript
复制
 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)、局部组件,只能在注册他的父组件当中使用,在别的组件中是不可以使用的。

代码语言:javascript
复制
 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、父组件通过属性将值传递给子组件。通过静态传递和动态绑定传递属性。

代码语言:javascript
复制
 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、字符串形式的模板中没有这个限制。

代码语言:javascript
复制
 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。

代码语言:javascript
复制
 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:事件名称,直接绑定处理事件的名称,后面跟着事件处理逻辑。

代码语言:javascript
复制
 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是固定写法。

代码语言:javascript
复制
 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);参数一,触发指定的事件名称,参数二是携带的参数。

代码语言:javascript
复制
  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>表示。

代码语言:javascript
复制
 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="插槽名称"就可以使用该插槽了。

代码语言:javascript
复制
 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)、应用场景,父组件对子组件的内容进行加工处理。

代码语言:javascript
复制
 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、逐个实现各个组件的功能,包含标题组件,列表组件,结算组件。

代码语言:javascript
复制
  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>

效果,如下所示:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
事件总线
腾讯云事件总线(EventBridge)是一款安全,稳定,高效的云上事件连接器,作为流数据和事件的自动收集、处理、分发管道,通过可视化的配置,实现事件源(例如:Kafka,审计,数据库等)和目标对象(例如:CLS,SCF等)的快速连接,当前 EventBridge 已接入 100+ 云上服务,助力分布式事件驱动架构的快速构建。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档