本文简单介绍一下vue中的组件相关的知识点,包括组件的概念,注册,使用,以及组件之间的通信。内容比较简单,代码内有注释,适合入门。
目录
组件的概念
通俗的来理解,组件就是一个功能模块。
组件是可以复用的vue的一个实例,并且带有一个名字 -- 来自官方
扩展:定义组件考虑的问题:提升组件的复用性,降低组件之间耦合性 加强内聚。
组件的注册
全局组件的注册
可以通过vue.component的方式来定义全局组件,接收两个参数,第一个参数是组件名,第二个参数是一个对象。
属性的对象:组件的属性对象为vue的实例的对象,组件就是对vue做了一个实例化
Vue.component('组件名', {})
组件的命名
1.短横线 --- <my-component-name>
2.驼峰命名 -- <myComponentName>(比较推荐驼峰命名法)
注意:使用驼峰命名的的时候,首字母最好是大写字母开头(大驼峰)
如:
Vue.component('MyComponentName', {//大驼峰命名法
})
Vue.component('my-component-name', {//或者短横线命名法
})
全局组件的注册和使用
全局组件注册
引用模板template内为模板字符串,存放你要渲染的dom结构和相关数据。推荐使用反引号+dom结构,统一规范。
Vue.component('myComponent', {
// 添加模板 -- 模板一定要有唯一的一个根元素
//模板字符串一般使用es6里面的反引号,统一规范
template: `
<div>
hello
</div>
`
})
全局组件的使用
全局组件可以在项目中的任何位置被使用,使用的方式就是标签的使用方式
注意把驼峰命名法里面的大写变小写,并用短横线连接起来
双闭合后面可以使用组件,但是单闭合不可以
如单标签,双标签(双标签内还可以写东西):
<my-component-name />//单标签写法
<my-component-name></my-component-name>//双标签写法
例子
把hello渲染到页面上。
我们定义一个组件名为MyComponent,在函数内写了模板字符串,div内写hello。在div内使用双标签的方式使用这个组件。就可以成功在页面上渲染hello。
<div id="app">
<my-component></my-component>
</div>
//全局组件
Vue.component('MyComponent',{//大写的Vue,这个组件就相当于一个实例
//使用组件的时候,就把大写字母变小写,使用-拼接,类似标签一样使用
//字符串模板必须要有唯一的根元素
template:`
<div>
hello
</div>
`
})
let vm = new Vue({
el: '#app',
data: {
msg: 'aaa',
}
})
局部组件的注册以及使用
局部组件与全局组件相似,但它需要在根组件中注册 使用components写在Vue实例里面。它与methods,data等是同级的兄弟关系。
例子
把hello渲染到页面上。
与全局组件相似,但是写在了Vue实例的components里面。
<div id="app">
<my-component></my-component>
</div>
let vm = new Vue({
el: "#app",
data: {
},
methods:{
},
components: {
'myComponent': {
template: `
<div>
hello
</div>
`
}
}
})
局部组件的第二种注册方式
我们可以单独把局部组件的注册代码注释掉,自己单独写一个对象,对象中含有data数据,template标准字符串等,再把它赋值给一个变量,把这个变量拿到Vue实例的components中,同样可以实现局部组件的注册。
var helloWord={//声明一个变量helloWord,赋值一个对象
data:function(){//data是个函数
return{
msg:'helloword'//返回值为字符串helloword
}
},
methods:{
},
//渲染,div内用差值表达式渲染msg的数据
template:`
<div>
{
{msg}}
</div>
`
}
//组件就是一个功能模块
//局部组件
let vm = new Vue({
el: '#app',
data: {
msg: 'aaa',
},
components:{//局部组件的注册
// 'MyComponent':{
// template:`
// <div>
// hello
// </div>
// `
// }
helloWord//把helloWord这个对象拿过来,相当于替代了上面被注释掉的局部组件的注册
}
})
注册组件的注意事项
- 组件模板内容(template内)必须是单个根元素,也就是只有一个根元素
- 组件模板内容可以是模板字符串 -- 是用反引号
- 模板字符串需要浏览器支持(es6中的语法,所以浏览器得兼容es6)
- data必须是一个函数,data:{} // 其实在运行的时候,是函数的调用
组件间的通信
组件间的通信解释
组件之间是独立的,不同组件之间的数据是无法相互引用的,需要使用特定的方式来实现数据的通用
父给子组件传值
父组件通过props属性向子组件传递数据,子组件利用组件的实列props属性定组件需要接收的参数
在父组件中使用子组件,把需要传的值,以属性的方式绑定到子组件上
在子组件中使用 props属性接收这个值 数组中使用引号把属性名引起来,多个属性之间使用逗号隔开
例子
<div id="app">
<parent></parent>
</div>
// 定义parent组件
Vue.component('parent', {
//在template中把组件child的name和age渲染出来
//把父组件中需要专递的值,以属性的方式绑定到子组件上
template: `
<child :name="name" :age="age" />//在父组件中使用子组件
`,
data: function () {//定义data函数,以对象的形式返回name和age的值
return {
name: '王大爷',
age: 22
}
}
})
// 定义 child 组件
Vue.component('child', {
//在子组件中使用props的方式接收传递过来的值
props: ['name', 'age'],//在props属性接受父组件name和age的值
//渲染,div中的name和age
template: `
<div>{
{name}}{
{age}}</div>
`
})
let vm = new Vue({
el: '#app',
data: {
msg: 'aaa',
},
components:{//局部组件的注册
}
})
结果:渲染出数据如下
步骤总结:
1、定义一个父组件和一个子组件
2、在父组件中使用子组件
3、把父组件中需要专递的值,以属性的方式绑定到子组件上
4、在子组件中使用props的方式接收传递过来的值
定义props中值的默认值和数据类型
父给子组件传值,props接收数据的方式,就应该把数组的方式,变为对象的方式
所以我们尝试把parent组件内的data函数注释了,在child组件内添加props的数据,和数据类型的约束,以对象的形式。
// 定义parent组件
Vue.component('parent', {
//在template中把组件child的name和age渲染出来
template: `
<child :name="name" :age="age" />
`,
data: function () {//定义data函数,以对象的形式返回name和age的值
return {
name: '王大爷',
age: 22
}
}
})
// 定义 child 组件
Vue.component('child', {
//添加props的数据,和数据类型的约束,以对象的形式
props: {
name: {
type: String,
default: '二大爷'
},
age: {
type: Number,
default: 80
}
},
//渲染,div中的name和age
template: `
<div>{
{name}}{
{age}}</div>
`
})
let vm = new Vue({
el: '#app',
data: {
msg: 'aaa',
},
components: {//局部组件的注册
},
})
结果:
所以在渲染页面的时候,name和age数据由child组件的props给出默认值,parent组件内的定义的data函数给出数据可以去覆盖这个默认值。
子组件通过$emit 传递数据给父组件
//其实就是子组件去获取了父组件的值,对这个值进行了操作,并不是去直接改变父组件的数据
//其实可以通过子组件去修改父组件的数据,但其数据发生改变,父组件向多个子组件传值,这些子组件的值都要发生改变,所以我们不可以使用这个办法
// 定义parent组件
Vue.component('parent', {
//把$emit自定义的事件函数age-add拿过来用,并且把methods内定义的函数内获取的age值拿给age-add操作
//在template中把组件child的name和age渲染出来,age-add操作完age值后,会改变age值,在页面上渲染出来
template: `
<child :name="name" :age="age" @age-add="age_data" />
`,
methods: {
//这个函数用来拿取data内的age数据
age_data(age) {
this.age = age
}
},
data: function () {
return {
name: '王大爷',
age: 22
}
}
})
// 定义 child 组件
Vue.component('child', {
//使用props拿取父元素的数据
props: ['name', 'age'],
//template内的dom节点内,按钮应用add方法实现age的点击自增
template: `
<div>
{
{name}}{
{age}}
<button @click="add">按钮</button>
</div>
`,
methods: {
add: function () {
//在子组件中使用$emit(事件名,数据) 触发一个自定义事件,事件名自定义。
//事件名推荐使用小写和短横线
this.$emit('age-add', this.age + 1)
}
}
})
let vm = new Vue({
el: '#app',
data: {
msg: 'aaa',
},
components: {//局部组件的注册
},
})
结果:
点击按钮实现自增
兄弟组件之间的传值
兄弟组件之间的通信,可以通过父组件为中继站,来实现。简而言之就是把父传子组件和子传父组件结合在一起。
// 定义parent组件
Vue.component('parent', {
//把$emit自定义的事件函数age-add拿过来用,并且把methods内定义的函数内获取的age值拿给age-add操作
//在template中把组件child的name和age渲染出来,age-add操作完age值后,会改变age值,在页面上渲染出来
template: `
<div>
<child :name="name" :age="age" @age-add="age_data" />
<child1 :name="name" :age="age"/>
</div>
`,
methods: {
//这个函数用来拿取data内的age数据
age_data(age) {
this.age = age
}
},
data: function () {
return {
name: '王大爷',
age: 22
}
}
})
// 定义 child 组件
Vue.component('child', {
//使用props拿取父元素的数据
props: ['name', 'age'],
//template内的dom节点内,按钮应用add方法实现age的点击自增
template: `
<div>
{
{name}}{
{age}}
<button @click="add">按钮</button>
</div>
`,
methods: {
add: function () {
//在子组件中使用$emit(事件名,数据) 触发一个自定义事件,事件名自定义。
//事件名推荐使用小写和短横线
this.$emit('age-add', this.age + 1)
}
}
})
// 定义 child1 组件
Vue.component('child1', {
//使用props拿取父元素的数据
props: ['name', 'age'],
//template内的dom节点内
template: `
<div>
{
{name}}{
{age}}
</div>
`,
})
let vm = new Vue({
el: '#app',
data: {
msg: 'aaa',
},
components: {//局部组件的注册
},
})
兄弟组件传值-中央事件总线
我们可以利用vue的原型对象,把兄弟组件的数据想办法挂载到原型对象上,由其他组件拿取。
主要是利用$emit和$on自定义事件,来传输数据和拿取数据。
定义事件总线
let bus = new Vue()
Vue.prototype.a = bus
定义发送的事件
this.a.$emit('事件名称', data)
定义接收事件 并在回调函数中接收参数
this.a.$on('事件名称', (data) => { })
上代码,内有详细注释:
<div id="app">
<person></person>
<detail />
</div>
/*
// 定义事件总线
let bus = new Vue()
Vue.prototype.a = bus
// 定义发送的事件
this.a.$emit('事件名称', data)
// 定义接收事件 并在回调函数中接收参数
this.a.$on('事件名称', (data) => { })
*/
// 逻辑代码
let bus = new Vue()//创建一个vue实例
Vue.prototype.bus = bus//把这个vue实例挂载到vue的原型对象上
//相当于把person内的数据,挂载到vue的原型对象上,供其他兄弟组件拿取,主要是$emit和$on自定义事件的使用
Vue.component('person', {
template: `
<div>
<div>姓名:<input type="text" v-model="name"></div>
<div>年龄:<input type="text" v-model="age"></div>
<button @click="midfiy">修改</button>
</div>
`,
methods: {
//定义midfiy方法,用bus实例和$emit自定义事件,拿取data里面的name和age,相当于把数据存放到bus里面,挂载到vue的原型对象里面
midfiy() {
this.bus.$emit('midfiy', { name: this.name, age: this.age })
}
},
data() {
return {
name: '张三',
age: 20
}
}
})
Vue.component('detail', {
template: `
<div>
我是: {
{name}},
我今年:{
{age}} 岁了
</div>
`,
data() {
return {
name: '李四',
age: 18
}
},
mounted() {//使用声明周期函数内的mounted
//使用bus和$on自定义一个事件,用来拿取存放在bus内的,person组件内的数据,并且把数据赋值给detail组件内data的数据
this.bus.$on('midfiy', (detail) => {
this.name = detail.name
this.age = detail.age
})
}
})
let vm = new Vue({
el: "#app",
data: {
}
})
结果:
刚打开页面,detail组件会拿取自己data里面的默认数据。
点击按钮后,detail组件就会拿取person组件内的数据
动态组件
动态组件就是让多个组件使用同一个挂载点,并实现动态切换
动态组件如何使用
通过使用保留的<compionent>元素,动态的把组件名称绑定到 is 特性上 可以实现动态组件
代码如下
<div id="app">
<!-- 通过使用保留的<compionent>元素,动态的把组件名称绑定到 is 特性上 可以实现动态组件 -->
<component :is="currentView"></component>
<!-- 为三个按钮设置点击事件changeView('A'),并为其传参A,B,C -->
<button @click="changeView('A')">切换到A</button>
<button @click="changeView('B')">切换到B</button>
<button @click="changeView('C')">切换到C</button>
</div>
//定义组件A,B,C
Vue.component('componentA', {
template: `<div>组件A</div>`,
})
Vue.component('componentB', {
template: `<div>组件B</div>`
})
Vue.component('componentC', {
template: `<div>组件C</div>`,
})
let vm = new Vue({
el: "#app",
data() {
//在data中定义默认组件currentView,并且赋值默认值
return {
currentView: 'componentB' // 显示默认组件
}
},
methods: {
//点击事件的函数,获取传递的参数
changeView: function (name) {
//为currentView重新赋值,值为字符串拼接成组件名字
this.currentView = `component${name}`
}
}
})
结果如下
keep-alive
是vue提供的一个抽象组件用来对组件进行缓存,从而节省性能
基础用法
结合上面动态组件如何使用模块的代码,如下
<keep-alive>
<component :is="currentView"></component>
</keep-alive>
activated 和 deactivated 生命周期
activated 和 deactivated 和之前的生命周期函数是一样的,这两个只是在 <keep-alive> 内的所有嵌套的组件中触发
activated : 进入组件的时候触发
deactivated :退出组件的时候触发
代码如下,直接在原来代码上添加
Vue.component('componentA', {
template: `<div>组件A</div>`,
activated(){
console.log('进入A');
},
deactivated(){
console.log('退出A');
}
})
结果:
当我们点击A的时候,打印'进入A',当我们点击别的按钮,就会打印'退出A'。
include 和 exclude
是keep-alive的属性,允许组件有条件的缓存
include :可以是字符串或者正则表达式,用来表示只有名称匹配的组件会被缓存
exclude :可以是字符串或者正则表达式,用来表示只有名称匹配的组件不会被缓存
使用方法如下
include
<keep-alive include="componentA,componentB">
<component :is="currentView"></component>
</keep-alive>
exclude
<keep-alive exclude="componentA,componentB">
<component :is="currentView"></component>
</keep-alive>
结合例子来看:
//定义组件A,B,C
Vue.component('componentA', {
template: `<div>组件A</div>`,
created() {
console.log('显示组件A');
}
})
Vue.component('componentB', {
template: `<div>组件B</div>`,
created() {
console.log('显示组件B');
}
})
Vue.component('componentC', {
template: `<div>组件C</div>`,
created() {
console.log('显示组件C');
}
})
结果:
在频繁点击下,c只会被打印一次,而a,b被多次打印,因为我们exclude设置 组件a,b不应用缓存,而c保持默认设置使用缓存