一.父传子和字传父
<template>
<div>
<aa :num=" number" />
</div>
</template>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
number: 123
}
},
methods: {
}
}
</script>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
number: 123
}
},
methods: {
}
}
</script>
<style scoped>
</style>
<template>
<div>
{
{ num }}
</div>
</template>
<script>
export default {
name: '',
props: {
num: {
type: Number,
default: 20
}
},
methods: {
}
}
</script>
<style scoped>
</style>
过程在父组上通过定义一个属性然后将数据传递过去。
我们这里绑定的是
收的是:
如果传递的是一个复杂的数据类型呢?
代码:
<template>
<div>
<aa :num="obj" />
</div>
</template>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
obj: {
name: '张三'
}
}
},
methods: {
}
}
</script>
<style scoped>
</style>
<template>
<div>
{
{ num.name }}
</div>
</template>
<script>
export default {
name: '',
props: {
num: {
type: Object,
default: () => {}
}
},
methods: {
}
}
</script>
<style scoped>
</style>
简单数据类型的修改
<template>
<div>
<aa :num=" number" />
</div>
</template>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
number: 123
}
},
methods: {
}
}
</script>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
number: 123
}
},
methods: {
}
}
</script>
<style scoped>
</style>
<template>
<div>
<div>
{
{ num }}
</div>
<button @click="fn">
点击</button>
</div>
</template>
<script>
export default {
name: '',
props: {
num: {
type: Number,
default: 20
}
},
methods: {
fn() {
this.num = 456
}
}
}
</script>
<style scoped>
</style>
vue给予了警告
通过this.$emit修改过后呢?
<template>
<div>
<aa :num="number" @input="show" />
</div>
</template>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
number: 123
}
},
methods: {
show(val) {
console.log(val)
}
}
}
</script>
<style scoped>
</style>
<template>
<div>
<div>
{
{ num }}
</div>
<button @click="fn">
点击</button>
</div>
</template>
<script>
export default {
name: '',
props: {
num: {
type: Number,
default: 20
}
},
methods: {
fn() {
this.$emit('input', 456)
}
}
}
</script>
<style scoped>
</style>
可以看到代码并没有发生任何的报错。
为什么官方不建议直接修改呢?
我们来模拟一下这个场景
父组件的代码:
<template>
<div>
<aa :num="number" />
<button @click="fn">父组件的修改</button>
</div>
</template>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
number: 10
}
},
methods: {
fn() {
this.number = 30
}
}
}
</script>
<style scoped>
</style>
<template>
<div>
<div>
{
{ num }}
</div>
<button @click="fn">
子组件的修改</button>
</div>
</template>
<script>
export default {
name: '',
props: {
num: {
type: Number,
default: 20
}
},
methods: {
fn() {
this.num = 20
}
}
}
</script>
<style scoped>
</style>
刚开始的值:
子组件修改变量后:
父组件修改变量后:
通过this.$emit看下:
<template>
<div>
<aa :num="number" @input="show" />
<button @click="fn">父组件的修改</button>
</div>
</template>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
number: 10
}
},
methods: {
show(val) {
this.number = val
},
fn() {
this.number = 30
}
}
}
</script>
<style scoped>
</style>
<template>
<div>
<div>
{
{ num }}
</div>
<button @click="fn">
子组件的修改</button>
</div>
</template>
<script>
export default {
name: '',
props: {
num: {
type: Number,
default: 20
}
},
methods: {
fn() {
this.$emit('input', 20)
}
}
}
</script>
<style scoped>
</style>
初始值:
需要子组件:
修改父组件:
通过这两次对比:
vue.runtime.esm.js?2b0e:619 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "num"
found in
---> <Aa> at aa.vue
<App> at src/App.vue
<Root>
很好地说明了一点:
我在子组件里面修改了值为20,直接修改。
下次我在父组件里面在去修改相同的值此时的值被覆盖。
通过this.$emit修改没有实现覆盖而是实现同步。
如果是一个复杂的数据类型呢?
父组件:
<template>
<div>
<aa :num="obj" />
</div>
</template>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
obj: {
name: '张三'
}
}
},
methods: {
}
}
</script>
<style scoped>
</style>
<template>
<div>
{
{ num.name }}
</div>
</template>
<script>
export default {
name: '',
props: {
num: {
type: Object,
default: () => {}
}
},
methods: {
}
}
</script>
<style scoped>
</style>
只修改堆
可以看出实现了同步的更新
也就是他们指向了同一个地址。
子组件如何修改自己的内容 不影响父组件呢?
重新赋值,在生成一个新的对象。
fn() {
this.num = {
name: '李四'
}
}
如果不做修改,赋值组件也是呈现一个双选绑定的状态。
结论:
修改值的话,最好是通过this.$emit去通知父组件进行修改,要不可能会造成覆盖。
有什么好的替代方案呢?
在实际的开发中我们通常是通过ref去进行修改。
代码:
<template>
<div>
<aa ref="aa" :num="obj" />
<button @click="fn">修改子组件里面的值</button>
</div>
</template>
<script>
import aa from '../aa.vue'
export default {
name: '',
components: { aa },
data() {
return {
obj: {
name: '张三'
}
}
},
methods: {
fn() {
this.$refs.aa.falg = true
console.log(this.$refs.aa)
}
}
}
</script>
<style scoped>
</style>
<template>
<div>
<div>
{
{ num.name }}
</div>
<button @click="fn">点击</button>
</div>
</template>
<script>
export default {
name: '',
props: {
num: {
type: Object,
default: () => {}
}
},
data() {
return {
falg: false
}
},
methods: {
fn() {
this.num = {
name: '李四'
}
}
}
}
</script>
<style scoped>
</style>
二.兄弟传值
在vue的原型链上一个实例化对象
Vue.prototype.$vus = new Vue()
触发:
this.$emit(事件名,值)
接收:
this.$on(事件名,变量)
销毁:
this.$off(事件名)
代码:
<template>
<div>
<aa />
<cc />
</div>
</template>
<script>
import aa from '../aa.vue'
import cc from '../cc.vue'
export default {
name: '',
components: { aa, cc }
}
</script>
<style scoped>
</style>
<template>
<div class="">
子组件2
</div>
</template>
<script>
export default {
name: '',
mounted() {
this.$bus.$emit('aa', 123)
},
methods: {
}
}
</script>
<style scoped>
</style>
<template>
<div class="">
子组件1
</div>
</template>
<script>
export default {
name: '',
mounted() {
this.$bus.$on('aa', (val) => {
alert(val)
})
},
methods: {
}
}
</script>
<style scoped>
</style>
关闭
<template>
<div class="">
子组件1
</div>
</template>
<script>
export default {
name: '',
mounted() {
this.$bus.$on('aa', (val) => {
alert(val)
})
this.$bus.$off('aa')
},
methods: {
}
}
</script>
<style scoped>
</style>