1.组件化概念
在开发中,我们将页面的某一部分功能编写成一个组件,以后直接在页面中引用即可,如导航栏,轮播图,等,封装成一个个的组件,以后直接使用即可
Vue的官方也推荐我们组件化开发,即一个组件就是一个vue文件
组件化的特点:
- 组件化可以将功能实现模块化,奖该组件需要的html,js,csss代码集中在一起
- 有利于代码的重用性
- 提高开发效率
2.局部组件和全局组件
2.1 局部组件
局部组件只能在当前页面使用,其他组件是无法使用的,建议在开发中尽可能的使用全局组件,也就是单页面开发(一个文件只有一个组件)
局部组件定义在当前组件的components中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 引入vue.js-->
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 局部组件只能在定义的当前文件中使用-->
<navbar></navbar>
</div>
</body>
<script>
new Vue({
// vue管理的区域,所有的vue语法仅在该区域内生效
el: '#app',
data: {},
// 定义局部组件
components: {
navbar: {
template: `
<div>我是一个局部组件{{ name }}
<button @click="handler">点我</button>
</div>`,
data() {
return {
name: 'kunmzhao'
}
},
methods: {
handler() {
alert('hello')
}
}
}
}
})
</script>
</html>
2.2 全局组件
全局组件定义之后,在任意的vue文件中都可以直接使用,就像html中的div标签一样使用
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <!-- 引入vue.js-->
7 <script src="js/vue.js"></script>
8 </head>
9 <body>
10 <div id="app">
11 <!-- 全局组件的使用-->
12 <navbar></navbar>
13
14 </div>
15 </body>
16 <script>
17 // 定义一个全局组件
18 Vue.component('navbar', {
19 template: `
20 <div>我是一个全局组件{{ name }}
21 <button @click="handler">点我</button>
22 </div>`,
23 // 组件大data必须是一个函数,返回的是一个对象
24 data() {
25 return {
26 name: 'kunmzhao'
27 }
28 },
29 methods: {
30 handler() {
31 alert('hello')
32 }
33 }
34 })
35 new Vue({
36 // vue管理的区域,所有的vue语法仅在该区域内生效
37 el: '#app',
38 data: {},
39 })
40 </script>
41 </html>
View Code
3.组件间的通信
各个组件之间数据,方法都是隔离的,因此我们不同担心组件之间存在变量或者方法重名的方法,vue中组件之间的通信方式主要有以下3种
3.1 自定义属性实现父传子
该方式可以是全局组件,也可以是局部组件和父组件之间的通信
通信步骤
- 父组件将数据传递给子组件的自定义属性中
- 子组件接收自定义的属性
- 子组件使用自定义的属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 引入vue.js-->
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<!-- 全局组件的使用: 将父组件的name传递给子组件自定义的属性 myname -->
<navbar :myname="name"></navbar>
</div>
</body>
<script>
// 定义一个全局组件
Vue.component('navbar', {
template: `
<div>我是一个全局组件{{ myname }}</div>`,
props: ['myname']
})
new Vue({
el: '#app',
data: {
name: 'Victor'
},
})
</script>
</html>
3.2 自定义事件实现子传父
有一点需要特别注意,自定义的事件不能使用驼峰命名!!!,最好都用小写
通信步骤:
- 子组件将需要发送的数据通过emit发送给指定的事件
- 父组件注册事件
- 父组件接收到事件之后,执行对应的函数
- 父组件接收数据
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <!-- 引入vue.js-->
7 <script src="js/vue.js"></script>
8 </head>
9 <body>
10 <div id="app">
11 <!-- 将子组件信息传递给父组件-->
12 <navbar @sendname="receiveName"></navbar>
13 <hr>
14 父组件接收来自子组件的信息 name:{{myname}}
15 </div>
16 </body>
17 <script>
18
19 Vue.component('navbar', {
20 template: `
21 <div>
22 <span><input type="text" v-model="name"></span> ==>{{name}}
23 <br>
24 <button @click="handlerClick">点我,传递信息给父组件</button>
25
26 </div>`,
27 data() {
28 return {
29 name: ''
30 }
31 },
32 methods: {
33 handlerClick() {
34 // 子组件发送事件
35 this.$emit('sendname', this.name)
36 }
37 }
38
39
40 })
41 new Vue({
42 el: '#app',
43 data: {
44 myname: ''
45 },
46 methods: {
47 receiveName(name) {
48 this.myname = name
49 }
50 }
51 })
52 </script>
53 </html>
View Code
3.3 ref属性实现父子组件间通信
ref可以引用普通的标签,也可以引用自定义组件,引用普通标签可以在父组件中通过$refs获取标签的DOM 对象,引用组件则可以获取组件对象
在父组件中既然已经拿到组件或者标签的对象了,那我们就可以修改,获取内部数据,设置可以指定其内部方法
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <!-- 引入vue.js-->
7 <script src="js/vue.js"></script>
8 </head>
9 <body>
10 <div id="app">
11
12 <hr>
13 <!-- ref引用自定义组件-->
14 <navbar ref="mynavbar"></navbar>
15 <hr>
16 <!-- ref引用普通组件-->
17 <input type="text" ref="myinput" v-model="myname">
18 <button @click="tosonclick">点我,将父组件消息传递给子组件</button>
19 <button @click="tofatherclick">点我,将子组件消息传递给父组件</button>
20
21 </div>
22 </body>
23 <script>
24
25 Vue.component('navbar', {
26 template: `
27 <div>
28 <span><input type="text" v-model="name"></span> ==>{{ name }}
29 <br>
30 </div>`,
31 data() {
32 return {
33 name: ''
34 }
35 },
36 methods: {}
37
38
39 })
40 new Vue({
41 el: '#app',
42 data: {
43 myname: ''
44 },
45 methods: {
46 tosonclick() {
47 // 将父组件数据传递给子组件
48 this.$refs.mynavbar.name = this.myname
49 },
50 tofatherclick() {
51 // 将子组件数据传递给父组件
52 this.myname = this.$refs.mynavbar.name
53 }
54 }
55 })
56 </script>
57 </html>
View Code
3.4.写在本涨最后
该篇仅仅介绍了父子组件之间的通信方式,其实组件之间,或者嵌套很深的组件之间都是可以通信的,不过要借助Vuex第三方组件实现,后续补充
4. Vue内置组件
4.1 component组件
渲染一个“元组件”为动态组件。依 is
的值,来决定哪个组件被渲染。is
的值是一个字符串,它既可以是 HTML 标签名称也可以是组件名称。
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <!-- 引入vue.js-->
7 <script src="js/vue.js"></script>
8 </head>
9 <body>
10 <div id="app">
11
12 <ul>
13 <li @click="myname='input1'">输入框</li>
14 <li @click="myname='button1'">按钮</li>
15 <li @click="myname='navbar'">navbar</li>
16 </ul>
17 <!-- 动态的显示某个组件-->
18 <component :is='myname'></component>
19
20 </div>
21 </body>
22 <script>
23 // 组件1
24 Vue.component('input1', {
25 template: `
26 <div>
27 <input type="text">
28 </div>`,
29 })
30 // 组件2
31 Vue.component('button1', {
32 template: `
33 <div>
34 <button>点我</button>
35 </div>`,
36
37 })
38 // 组件3
39 Vue.component('navbar', {
40 template: `
41 <div>
42 <span><input type="text" v-model="name"></span> ==>{{ name }}
43 <br>
44 </div>`,
45 data() {
46 return {
47 name: ''
48 }
49 },
50 methods: {}
51
52
53 })
54 new Vue({
55 el: '#app',
56 data: {
57 myname: ''
58 },
59 })
60 </script>
61 </html>
View Code
4.2 keep-alive组件
<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们,常搭配component使用
比如我们希望在某个组件输入框输入了内容,此时有切换到别的组件,当我们切回之间的输入框组件时,期望输入的内容保存,就可以使用该组件
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <!-- 引入vue.js-->
7 <script src="js/vue.js"></script>
8 </head>
9 <body>
10 <div id="app">
11
12 <ul>
13 <li @click="myname='input1'">输入框</li>
14 <li @click="myname='button1'">按钮</li>
15 <li @click="myname='navbar'">navbar</li>
16 </ul>
17 <!-- 动态的显示某个组件并且缓存-->
18 <keep-alive>
19 <component :is='myname'></component>
20
21 </keep-alive>
22
23 </div>
24 </body>
25 <script>
26 // 组件1
27 Vue.component('input1', {
28 template: `
29 <div>
30 <input type="text">
31 </div>`,
32 })
33 // 组件2
34 Vue.component('button1', {
35 template: `
36 <div>
37 <button>点我</button>
38 </div>`,
39
40 })
41 // 组件3
42 Vue.component('navbar', {
43 template: `
44 <div>
45 <span><input type="text" v-model="name"></span> ==>{{ name }}
46 <br>
47 </div>`,
48 data() {
49 return {
50 name: ''
51 }
52 },
53 methods: {}
54
55
56 })
57 new Vue({
58 el: '#app',
59 data: {
60 myname: ''
61 },
62 })
63 </script>
64 </html>
View Code
4.3 slot组件
在前面定义的子组件中,我们没有好的办法可以实现向子组件添加内容,如
但是通过slot就可以很好的实现这一功能
4.3.1 不具名插槽
在子组件中只有一个slot插槽,因此不需要指定名字
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 引入vue.js-->
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<navbar>
<div>hello</div>
</navbar>
</div>
</body>
<script>
Vue.component('navbar', {
template: `
<div>
<p>我是子组件</p>
<!-- 在子组件中定义一个插槽-->
<slot></slot>
</div>`,
data() {
return {
name: ''
}
},
methods: {}
})
new Vue({
el: '#app',
data: {
myname: ''
},
})
</script>
</html>
4.3.2 具名插槽
在子组件中有多个插槽,需要指定名字
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 引入vue.js-->
<script src="js/vue.js"></script>
</head>
<body>
<div id="app">
<navbar>
<div slot="img"><img src="https://img0.baidu.com/it/u=284864485,3694629534&fm=253&fmt=auto&app=138&f=JPEG?w=333&h=500" alt=""></div>
<div slot="button"><button>点我</button></div>
</navbar>
</div>
</body>
<script>
Vue.component('navbar', {
template: `
<div>
<p>我是子组件</p>
<!-- 在子组件中定义多个插槽-->
<slot name="img"></slot>
<slot name="button"></slot>
</div>`,
data() {
return {
name: ''
}
},
methods: {}
})
new Vue({
el: '#app',
data: {
myname: ''
},
})
</script>
</html>
4.3.3 具名插槽的+<template v-slot>使用
将4.3.2中的例子改进如下:
这样在浏览器熏染后的页面就少了一层div
<navbar>
<template v-slot:img><img src="https://img0.baidu.com/it/u=284864485,3694629534&fm=253&fmt=auto&app=138&f=JPEG?w=333&h=500" alt=""></template>
<template v-slot:button><button>点我</button></template>
</navbar>