1. 什么是组件
组件化就是把页面拆分成一块块的,后期维护很简单
组件其实也是vue的实例,组件是可以反复使用的vue实例
- 全局注册组件
就是把组件用Vue.component()注册
<body>
<div id="app">
<!-- 3、使用组件 -->
<my-header></my-header>
</div>
</body>
<script src="vue.js"></script>
<script>
// 全局注册组件
// 1、定义组件
const MyHeader = {
template: `<header>头部</header>`,
}
// 2、全局注册组件
Vue.component('my-header', MyHeader)
new Vue({
el: '#app'
})
</script>
- 局部注册组件
就是把组件注册在某个Vue实例中,用components:{}注册
<body>
<div id="app">
<!-- 3、使用组件 -->
<my-header></my-header>
</div>
</body>
<script src="vue.js"></script>
<script>
// 局部注册组件
// 1、定义组件
const MyHeader = {
template: `<header>头部</header>`,
}
new Vue({
el: '#app',
// 2、局部注册组件
components: {
'my-header': MyHeader
}
})
</script>
2. 组件间的传值
1. 父组件给子组件传值
- 父组件在调用子组件的地方需要添加一个属性<my-content test = "测试"/>
- 属性的值”测试”就是你要传递给子组件的值
- 在子组件定义的地方添加一个选项叫props:{}
- 在props里放父组件传递的属性名,也就是test就可以了,要注意的是,如果父组件传递给子组件的值是变量,Number或者布尔值就需要v-bind了!props内存放值有两种方式
- 第一种:数组:props:[‘test’],之后就可以在子组件中使用了
- 第二种:对象:props:{test:String},这是写法一用来验证传递数据的有效性,因为父子组件可能不是一个人写的,如果数据类型不对,就会警告,可以及时调整。
- Props:{test:{type:String,default:’默认值’}}这是第二种写法,既要验证数据类型也要设置默认值,如果默认值是对象或者函数,则默认值需要时一个有返回值的函数function () {return {}}
<body>
<div id="app">
<!-- <my-content test = "测试" :count="100" :flag="true" :tip="tip"/> -->
<my-content :count="100" :flag="true" :tip="tip"/>
</div>
</body>
<template id="content">
<div>
我这里是内容区域 --- {{ test }} -- {{ count }} --- {{ flag }} --- {{ tip }}
</div>
</template>
<script src="vue.js"></script>
<script>
// 组件的名称不能和模板的id同名
const Content = {
template: '#content',
// props: ['test', 'count', 'flag', 'tip']
// props: {
// test: String,
// count: Number,
// flag: Boolean,
// tip: String
// }
props: {
test: {
type: String,
default: '测试数据了' // 如果父组件有这个属性,那么就用父组件的值,没有这个属性,直接使用这个值
}
}
}
new Vue({
el: '#app',
data: {
tip: '提示'
},
components: {
'my-content': Content
}
})
</script>
2. 子组件给父组件传值
- 子组件给父组件传值时,需要在父组件调用子组件的地方,给它绑定一个自定义事件,事件后面不要加(),例:<my-content @myevent="getData"/>
- 在父组件选项methods中使用这个getData(val){},其中参数val是默认传递的,传递的就是子组件传递给父组件的值
- 而在子组件如何传递呢?如下!
- 在子组件种。你可以通过生命周期的钩子函数,也可以是组件自己的事件去触发父组件中的自定义事件myevent,使用固定语法emit来传递例:this.$emit('myevent', 10000),这样就把名字为myevent的参数名,参数为10000的整个值广播出去了,父组件只要接受myevent就可以了!
<body>
<div id="app">
<my-content @myevent="getData"/>
</div>
</body>
<template id="content">
<div>
我这里是内容区域
</div>
</template>
<script src="vue.js"></script>
<script>
/**
* 父组件调用子组件的地方,给他绑定一个自定义的事件, 事件不要加()
* <my-content @myevent="getData"/>
* 在父组件选项methods中实现此事件,默认参数为你将从子组件得到的值
* methods: {
getData (val) { // val为从子组件中获取到的值
console.log(val)
}
},
在子组件中,可以是生命周期钩子函数,也可以是组件自己的事件 去 触发 父组件中的自定义事件
this.$emit('myevent', 10000)
**/
const Content = {
template: '#content',
mounted () {
this.$emit('myevent', 10000)
}
}
new Vue({
el: '#app',
data: {},
methods: {
getData (val) { // val为从子组件中获取到的值
console.log(val)
}
},
components: {
'my-content': Content
}
})
</script>
3. 非父子组件间传值
- 中央事件总线传值const bus = new Vue()他就类似于一个快递员的身份,需要确保数据有人接受的情况下,就可以接受参数然后传递参数给需要的人!
- 第一步:给需要这个参数的组件,定义bus.$on(‘参数名’,(val)={对收到的val做手脚}),一般写在钩子函数mounted中。还要注意这里尽量使用箭头函数避免this指向出现问题
- 第二步:在确定了有接受的组件时,就可以给要发送的组件设置了!在发送参数的组建中的methods中添加一个自定义函数,在里面定义bus.emit(‘参数名’,参数),当触发了bus.emit时,像外广播了一个参数名,然后另一个组件通过bus.$on接收到了参数名相同的参数值,这样就形成了非父子组件之间的值传递
<body>
<div id="app">
<my-list></my-list>
<my-count></my-count>
</div>
</body>
<template id="list">
<ul>
<li>111<button @click="add">+1</button></li>
<li>222<button @click="add">+1</button></li>
<li>333<button @click="add">+1</button></li>
<li>444<button @click="add">+1</button></li>
<li>555<button @click="add">+1</button></li>
</ul>
</template>
<template id="count">
<div>
总量是:{{ num }}
</div>
</template>
<script src="vue.js"></script>
<script>
/**
* 非父子组件传值 ---- 兄弟组件传值 (邮差与信的故事)
* ------------------ 中央事件总线传值 1. const bus = new Vue()
*
* 先要确保 收信 的那个人是存在的
* 然后写信的人 写信 给邮差
* 邮差给送
*
* // 此处一定要注意this指向,可以使用 =>
* 2.在接收端通过 bus.$on('收信信号', function (val) {
*
* })
*
* 3.在发送端通过 bus.$emit('收信信号', val)
* */
const bus = new Vue()
const List = {
template: '#list',
methods: {
add () {
bus.$emit('count-event', 1)
}
}
}
const Count = {
template: '#count',
data () {
return {
num: 0
}
},
mounted () { // 一般情况下接收都使用 生命周期钩子函数
bus.$on('count-event', (val) => { // 此处一定要注意this指向,可以使用 =>
console.log(val)
this.num += val
})
}
}
new Vue({
el: '#app',
components: {
'my-list': List,
'my-count': Count
}
})
</script>
4. 动态组件
<component is="组件名称"></component>
概述:让当前画面在几个组件中来回切换,类似你的手机屏幕,同一个屏幕可以打开不同的app显示不同的内容。
使用:一般在页面只写一个类似于<component :is="tem"></component>的组件,页面有按钮操控tem在data中的值,一旦改变值,在components中注册名称为改变得值得组件,就可以在页面中显示出所对应的组件了。
但是随之的问题就出现了,每次切换回前一个组件时,上次的操作就会被清除,所以需要用keep-alive把components包裹起来
keep-alive:保留组件的状态,避免组件的重新渲染 --- 类似于手机软件使用中按了home键之后应用程序的状态
但是有些时候就是需要切换回页面数据清除,所以只需要给keep-alive添加一个include属性就可以了,后面的属性值是在组件注册时定义的名称name的值。添加上的组件就会保存之前的信息,而没有添加的组件name就会数据消失
动态组件生命周期钩子函数
每个组件都会有两个钩子函数activated()---正在用的,deactivated()---后台的,如果该组件在keep-alive的include内,那么该组件再被切换时,会触发deactivated()钩子函数类似于后台运行,在使用时会触发activated()钩子函数
<body>
<div id="app">
<button @click="tem='my-a'">AAA</button>
<button @click="tem='my-b'">BBB</button>
<button @click="tem='my-c'">CCC</button>
<keep-alive include="a,b">
<component :is="tem"></component>
</keep-alive>
</div>
</body>
<template id="acom">
<div>
<input type="text" placeholder="a组件">
</div>
</template>
<template id="bcom">
<div>
<input type="text" placeholder="b组件">
</div>
</template>
<template id="ccom">
<div>
<input type="text" placeholder="c组件">
</div>
</template>
<script src="vue.js"></script>
<script>
/**
* keep-alive
* 保留组件的状态,避免组件的重新渲染 --- 类似于手机软件使用中按了home键之后应用程序的状态
* 添加include 可以 只给部分组件保留状态,需要定义组件时添加name属性
*
* 每个组件都会有 两个生命周期钩子函数
* activated() 正在用的
* deactivated() 后台的
* */
const Acom = {
name: 'a',
template: '#acom',
activated () {
console.log(' a 正在被使用')
},
deactivated () {
console.log(' a 被雪藏了')
}
}
const Bcom = {
name: 'b',
template: '#bcom',
activated () {
console.log(' b 正在被使用')
},
deactivated () {
console.log(' b 被雪藏了')
}
}
const Ccom = {
template: '#ccom',
activated () {
console.log(' c 正在被使用')
},
deactivated () {
console.log(' c 被雪藏了')
}
}
new Vue({
el: '#app',
data: {
tem: 'my-a'
},
components: {
'my-a': Acom,
'my-b': Bcom,
'my-c': Ccom
}
})
</script>