Vue 组件


组件化开发思想:

组件化规范:  Web Components 规范草案

1.我们希望尽可能多的重用代码

2.自定义组件的方式不太容易(html、css、js)

3.多次使用组件可能导师冲突

Web Components 通过创建封装好的功能定制元素解决上述问题。(目前并没有广泛的被浏览器所支持。)

官网: https://developer.mozilla.org/zh-CN/docs/Web/Web_Components

不同的功能封装到不同的组件当中,不同的组件通过组合完成特定的需求。

Vue实现了部分上述规范。


组件注册:

全局组件注册语法:

Vue.component(组件名称, {

  data: 组件数据,

  template: 组件模版内容

})

用法:

<div id='app'>

  <btn></btn>

</div>

注意事项:

1.data 必须是一个函数。

2.组件模版,必须为单个根元素。

3.组件内容可以是模版字符串。(模版字符串需要浏览提供支持,ES6语法)。

4.组件的命名方式:如果使用驼峰命名,那么在使用组件的时候,只能在字符串模版中使用驼峰的方式使用组件,但是在普通的标签模版中,必须转换成带短横线的标签。

案例:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5   <meta charset="UTF-8">
 6   <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7   <meta http-equiv="X-UA-Compatible" content="ie=edge">
 8   <title>Document</title>
 9   <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
10 </head>
11 
12 <body>
13 
14   <div id='app'>
15     <btn></btn>
16   </div>
17 
18 </body>
19 
20 <script>
21   // 组件注册
22   // 定义一个名为btn的组件
23   Vue.component('btn', {
24     data: function () {
25       return {
26         count: 0
27       }
28     },
29     template: '<button v-on:click="count++">点击了{{count}}次</button>'
30   })
31 
32   var vm = new Vue({
33     el: '#app',
34     data: {
35 
36     }
37   })
38 </script>
39 
40 </html>

 局部组件注册:

局部组件只能在注册他的父组件中使用

案例:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5   <meta charset="UTF-8">
 6   <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7   <meta http-equiv="X-UA-Compatible" content="ie=edge">
 8   <title>Document</title>
 9   <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
10 </head>
11 
12 <body>
13 
14   <div id='app'>
15     <component-a></component-a>
16     <component-b></component-b>
17     <component-c></component-c>
18   </div>
19 
20 </body>
21 
22 <script>
23   // 局部组件注册
24   var ComponentA = {
25     data: function () {
26       return {
27         msg: 'hello A'
28       }
29     },
30     template: '<button>{{msg}}</button>'
31   }
32   var ComponentB = {
33     data: function () {
34       return {
35         msg: 'hello B'
36       }
37     },
38     template: '<button>{{msg}}</button>'
39   }
40   var ComponentC = {
41     data: function () {
42       return {
43         msg: 'hello C'
44       }
45     },
46     template: '<button>{{msg}}</button>'
47   }
48 
49   var vm = new Vue({
50     el: '#app',
51     data: {
52 
53     },
54     components: {
55       'component-a': ComponentA,
56       'component-b': ComponentB,
57       'component-c': ComponentC
58     }
59   })
60 </script>
61 
62 </html>

组件之间数据交互

1.组件内部通过props接受传递过来的值。

父组件向子组件传值:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5   <meta charset="UTF-8">
 6   <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7   <meta http-equiv="X-UA-Compatible" content="ie=edge">
 8   <title>Document</title>
 9   <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
10 </head>
11 
12 <body>
13   <div id='app'>
14     <div>{{pmsg}}</div>
15     <menu-item title='(parent-component)'></menu-item>
16     <menu-item :title='pmsg'></menu-item>
17   </div>
18 </body>
19 <script>
20   Vue.component('menu-item',{
21     data: function () {
22       return {
23         msg:'(children-component)'
24       }
25     },
26     props:['title'],
27     template:'<div>{{msg + title}}</div>'
28   })
29 
30   
31   var vm = new Vue({
32     el: '#app',
33     data: {
34       pmsg:'hello word'
35     }
36   })
37 </script>
38 
39 </html>

props属性名规则:

1.在props中使用驼峰形式,模版中需要使用短横线的形式。

2.字符串形式的模版中没有这个限制。

 props属性值类型:

1.字符串类型 string

2.数值类型 number

3.布尔值 boolean

4.数组 array

5.对象 object


子组件向父组件传值:

props 传递数据原则是单向数据流。

1.子组件通过自定义事件向父组件传递信息。

 <button v-on:click='$emit("hello")'>button</button>

 2.父组件监听子组件的事件

<menu-item v-on:hello ='count+1'></menu-item>

案例:子组件向父组件传值,携带参数

<button v-on:click='$emit("hello","abc123")'>button</button>

<menu-item v-on:hello ='$event'></menu-item>


组件之间数据交互:

1.单独的事件中心管理组件间的通讯。

new 一个新的Vue实例对象作为事件中心

var eventHub = new Vue()

2.监听事件与销毁事件

$on 事件监听,第一参数是自定义事件的名称,第二个参数是事件函数。

eventHub.$on('add-todo',addTodo)

$off 事件销毁

eventHub.$off('add-todo')

3.触发事件

$emit  第一个参数为自定义事件名称,第二个参数为事件函数

eventHub.$emit('add-todo', id)

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5   <meta charset="UTF-8">
 6   <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7   <meta http-equiv="X-UA-Compatible" content="ie=edge">
 8   <title>Document</title>
 9   <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
10 </head>
11 
12 <body>
13 
14   <div id='app'>
15     <test-tom></test-tom>
16     <test-jerry></test-jerry>
17   </div>
18 
19 </body>
20 
21 <script>
22   // 事件中心
23   var hub = new Vue()
24 
25   Vue.component('test-tom', {
26     data: function () {
27       return {
28         num: 0
29       }
30     },
31     template: `
32     <div>
33         <div>Tom:{{num}}</div>
34         <div>
35           <button @click='handle'>点击</button>
36         </div>
37     </div>
38     `,
39     methods: {
40       handle: function () {
41         // 触发兄弟组件的事件
42         hub.$emit('jerry-event', 2)
43       }
44     }
45   })
46 
47   Vue.component('test-jerry', {
48     data: function () {
49       return {
50         num: 5
51       }
52     },
53     template: `
54     <div>
55         <div>Jerry:{{num}}</div>
56         <div>
57           <button @click='handle'>点击</button>
58         </div>
59     </div>
60     `,
61     methods: {
62       handle: function () {
63         // 触发兄弟组件的事件
64         hub.$emit('tom-event', 5)
65       }
66     }
67   })
68 
69   var vm = new Vue({
70     el: '#app',
71     mounted: function () {
72       hub.$on('tom-event', value => {
73         this.num += value
74       })
75 
76       hub.$on('jerry-event', value => {
77         this.num += value
78       })
79     }
80   })
81 </script>
82 
83 </html>

组件插槽

组件插槽的作用:

父组件向子组件传递内容(类似于React 中的 this.props.children)

1.插槽位置

1  Vue.component('alert-box',{
2     template:`
3     <div>
4       hello
5       <slot></slot>
6     </div>
7     `
8   })

2.插槽内容

 1 <alert-box>hello</alert-box>  

 案例:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5   <meta charset="UTF-8">
 6   <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7   <meta http-equiv="X-UA-Compatible" content="ie=edge">
 8   <title>Document</title>
 9   <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
10 </head>
11 
12 <body>
13   <div id='app'>
14     <alert-box>
15       <alert-item></alert-item>
16     </alert-box>
17   </div>
18 </body>
19 <script>
20   // 插槽位置
21   Vue.component('alert-box', {
22     template: `
23     <div>
24       <div>box</div>
25       <slot></slot>
26       <div>box</div>
27     </div>
28     `
29   })
30 
31   Vue.component('alert-item', {
32     template: `
33     <div>
34      <div>item</div>
35     </div>
36     `
37   })
38 
39   var vm = new Vue({
40     el: '#app',
41     data: {
42 
43     }
44   })
45 </script>
46 
47 </html>

具名插槽:自 2.6.0 起被废弃 不推荐使用

1.插槽定义

 1  <div>
 2       <header>
 3         <slot name='header'></slot>
 4       </header>
 5       <main>
 6         <slot></slot>
 7       </main>
 8       <footer>
 9         <slot name='footer'></slot>
10       </footer>
11   </div>

2.插槽内容

1  <div>
2     <h1 slot='header'>标题</h1>
3 
4     <p>内容</p>
5     <p>内容</p>
6     <p>内容</p>
7 
8     <p slot='footer'>底部</p>
9   </div>
原文地址:https://www.cnblogs.com/liea/p/11784330.html