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>
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>
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>
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>
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>
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>