为什么组件中的data必须是一个函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
// const myComponent = function() {}
// // 这个data在这里是一个对象
// myComponent.prototype.data = {
// a: 1,
// b: 2
// }
// const component1 = new myComponent()
// const component2 = new myComponent()
//
// component1.data.a = 5
//
// console.log(component2.data.a)
/*
* 如果是对象,不用function,返回每个组件的data都是内存中的同一个地址,一个数据改变了,其他的也会发生变化。
*
* 在JavaScript只有函数可以构成作用域,这就是data为什么是一个函数的原因,每个组件实例,都有自己的作用域,互相独立不会互相影响
*
* */
const myComponent = function() {
this.data = this.data()
}
myComponent.prototype.data = function() {
return {
a: 1,
b: 2
}
}
const component1 = new myComponent()
const component2 = new myComponent()
component1.data.b = 5
console.log(component2.data.b)
</script>
</body>
</html>
跨组件通信
是通过Vue空实例,作为连接$emit & $on,又称为中央通信
目前中央通信是解决兄弟间通信,祖父祖孙间通信的最佳方法,不仅限于此,也可以解决父组件子组件间的相互通信
- 各组件可自己定义好组件内接收外部组件的消息事件即可,不用理会是哪个组件发过来;而对于发送事件的组件,亦不用理会这个事件到底怎么发送给我需要发送的组件。
- Bus中央通信的方案各种情况下都可用,比较方便
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<Aaa></Aaa>
<Bbb></Bbb>
</div>
<script>
// Vue空实例 中央通信 用于连接$emit & $on
let bus = new Vue()
// 组件A
Vue.component('Aaa', {
template: `<div @click="aaa">我是A组件</div>`,
methods: {
aaa() {
bus.$emit('is-selected') // 广播
}
}
})
// 组件B
Vue.component('Bbb', {
template: `<div>我是B组件</div>`,
created() {
bus.$on('is-selected', function() { // 接收/监听
console.log('我是A组件传递过来的')
})
}
})
new Vue({
el: '#app'
})
</script>
</body>
</html>
单向数据流
数据从父组件传递给子组件,只能单向绑定。
在子组件内部不能直接修改父组件传递过来的数据。
注意:最新的Vue2.6版本,不会警告可以直接修改父组件传递过来的数据,简单查了一下没找到相关资料。按照2.0的理解去记就可以了,知道2.6这个特性即可。
不能直接改变父组件传递过来的数据
<div id="app">
<custom-com :count="count"></custom-com>
</div>
<script>
//子组件
Vue.component('customCom', {
props: ['count'],
template: `<div>
<h2>我是自定义的组件</h2>
<p>{{ count }}</p>
<input type="button" value="改变count的值" @click="changeCount">
</div>`,
methods: {
changeCount() {
this.count++
}
}
})
// 看做父组件
new Vue({
el: '#app',
data: {
count: 0
}
})
</script>
第一种修改方式:父组件传递过来的数据作为子组件局部的初始值
<div id="app">
<custom-com :count="count"></custom-com>
</div>
<script>
//子组件
Vue.component('customCom', {
props: ['count'],
data() {
return {
increment: this.count
}
},
template: `<div>
<h2>我是自定义的组件</h2>
<p>{{ increment }}</p>
<input type="button" value="改变count的值" @click="changeCount">
</div>`,
methods: {
changeCount() {
this.increment++
}
}
})
// 看做父组件
new Vue({
el: '#app',
data: {
count: 0
}
})
</script>
第二种:通过computed
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom-com :count="count"></custom-com>
</div>
<script>
//子组件
Vue.component('customCom', {
props: ['count'],
data() {
return {
increment: this.count
}
},
template: `<div>
<h2>我是自定义的组件</h2>
<p>{{ incrementCount }}</p>
<input type="button" value="改变count的值" @click="changeCount">
</div>`,
methods: {
changeCount() {
this.increment++
}
},
computed: {
incrementCount() {
return this.increment
}
}
})
// 看做父组件
new Vue({
el: '#app',
data: {
count: 0
}
})
</script>
</body>
</html>
Prop验证
我们可以为组件的 prop 指定验证要求
内置校验规则
String
Number
Boolean
Array
Object
Date
Function
Symbol
自定义校验规则
props: {
count: {
validator: function(value) {
return value < 10
}
}
},
示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<custom-com :count="count"></custom-com>
</div>
<script>
//子组件
Vue.component('customCom', {
// props: {
// count: {
// type: [Number, String],
// default: 100
// }
// },
props: {
count: {
validator: function(value) {
return value < 10
}
}
},
data() {
return {
increment: this.count
}
},
template: `<div>
<h2>我是自定义的组件</h2>
<p>{{ increment }}</p>
<input type="button" value="改变count的值" @click="changeCount">
</div>`,
methods: {
changeCount() {
this.increment++
}
}
})
// 看做父组件
new Vue({
el: '#app',
data: {
count: 11
}
})
</script>
</body>
</html>
动态组件
多个组件可以使用同一个挂载点,动态切换
Component
<div id="app">
<input type="button" value="切换到第1个组件" @click="tabComponent(1)">
<input type="button" value="切换到第2个组件" @click="tabComponent(2)">
<input type="button" value="切换到第3个组件" @click="tabComponent(3)">
<component :is="current"></component>
</div>
<script>
// 第一个组件
const custom1 = Vue.component(‘custom1’, {
template: <div>我是第1个组件</div>
})
// 第二个组件
const custom2 = Vue.component(‘custom2’, {
template: <div>我是第2个组件</div>
})
// 第三个组件
const custom3 = Vue.component(‘custom3’, {
template: <div>我是第3个组件</div>
})
new Vue({
el: ‘#app’,
data: {
current: custom1
},
methods: {
tabComponent(index) {
if (index === 1) {
this.current = custom1
} else if(index ===2) {
this.current = custom2
} else {
this.current = custom3
}
}
}
})
keep-alive
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
它自身不会渲染一个 DOM 元素,也不会出现在父组件链中
<div id="app">
<input type="button" value="切换到第1个组件" @click="tabComponent(1)">
<input type="button" value="切换到第2个组件" @click="tabComponent(2)">
<input type="button" value="切换到第3个组件" @click="tabComponent(3)">
<keep-alive>
<component :is="current"></component>
</keep-alive>
</div>
<script>
// 第一个组件
const custom1 = Vue.component(‘custom1’, {
template: <div @click="changeBg">我是第1个组件</div>
,
methods: {
changeBg(ev) {
ev.target.style.background = ‘orange’
}
}
})
// 第二个组件
const custom2 = Vue.component(‘custom2’, {
template: <div>我是第2个组件</div>
})
// 第三个组件
const custom3 = Vue.component(‘custom3’, {
template: <div>我是第3个组件</div>
})
new Vue({
el: ‘#app’,
data: {
current: custom1
},
methods: {
tabComponent(index) {
if (index === 1) {
this.current = custom1
} else if(index ===2) {
this.current = custom2
} else {
this.current = custom3
}
}
}
})
扩展
include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
max - 数字。最多可以缓存多少组件实例。