vue是单项数据流,引用Vue的官网的话:父系 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父及组件的状态,从而导致你的应用的数据流向难以理解。
在父子组件通讯的时候,子组件都禁止直接修改父级传过来的prop 直接修改在控制台会报错。但VUE的两个语法糖能做到这一点,就是自定义组件上的 v-model指令 以及 .sync修饰符。
另外,还可以通过子组件触发父组件中方法的方式,通过父组件的方法,更改父组件的数据。
VUE子组件更改父组件数据:
- 1.v-model
- 2. .sync
- 3. props 传递
- 4. this.$emit触发父组件方法实现
- 5.子组件通过this.$parent直接触发父组件
1.v-model
父组件代码:
<template>
<div>
<h2>父组件的值:{{num}}</h2>
<ChildA v-model="num" />
</div>
</template>
<script>
import ChildA from './ChildA.vue'
export default {
components: { ChildA },
data () {
return {
num: 1
}
},
methods: {
}
}
</script>
<style scoped>
</style>
子组件代码:
<template>
<div>
<h2>子组件的值:{{ childNum }}</h2>
</div>
</template>
<script>
export default {
name: "ChildA",
// 父组件使用v-model来传递
// 子组件使用model属性绑定props
model: {
prop: "number",//用来接收父组件传来的值
event: "number-event"//用来触发的事件
},
props: {
number: {
type: Number
}
},
data () {
return {
childNum: 2
}
},
//在子组件挂载完成的时候 进行触发自定义时间
mounted () {
setTimeout(() => {
this.$emit("number-event", this.childNum)
}, 1000)
}
}
</script>
<style scoped>
</style>
1s后修改成功:
官网这样解释的:
一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突:
**所以 prop 并不一定非要是 value,事件的名称也并不必须是input **
// 父组件使用v-model来传递
// 子组件使用model属性绑定props
model: {
prop: "number",//用来接收父组件传来的值
event: "number-event"//用来触发的事件
},
父组件里的 < ChildA v-model=“num” /> 的值将会传入子组件 的 prop。同时当子组件event 触发事件this.$emit(“number-event”,this.childNum);,父组件的值将会被更改
2. .sync
官网的介绍:
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以变更父组件,且在父组件和子组件都没有明显的变更来源。 这也是为什么我们推荐以 update:myPropName 的模式触发事件取而代之举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:
this.$emit(‘update:title’, newTitle) 然后父组件可以监听那个事件并根据需要更新一个本地的数据 property。例如:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
为了方便起见,我们为这种模式提供一个缩写,即 .sync 修饰符:
父组件代码:
<template>
<div>
<h2>父组件的值:{{number}}</h2>
<ChildA :number.sync="number" />
</div>
</template>
<script>
import ChildA from './ChildA.vue'
export default {
components: { ChildA },
data () {
return {
number: 1
}
}
}
</script>
<style scoped>
</style>
子组件代码:
<template>
<div>
<h2>子组件的值:{{ number }}</h2>
<button @click="num">更改父组件的值</button>
</div>
</template>
<script>
export default {
name: "ChildA",
props: {
number: {
type: Number
}
},
data () {
return {
number1: 2
}
},
methods: {
num () {
this.$emit('update:number', this.number1)
}
}
}
</script>
<style scoped>
</style>
3. props 传递
将父组件的方法通过 props 传递给子组件,子组件可以直接出发父组件的方法,从而实现子组件修改父组件数据,同时也可以将子组件的数据通过参数的形式发送给父组件。
父组件代码:
<template>
<div>
<h2>父组件</h2>
<ChildA :msgFromParent="msgFromParent"
:changeMsgFromParent="changeMsgFromParent" />
<!-- 父组件设置更改自己数据的方法,同时传递给子组件 -->
</div>
</template>
<script>
import ChildA from './ChildA.vue'
export default {
components: { ChildA },
data () {
return {
msgFromParent: "msg from parent"
}
},
methods: {
changeMsgFromParent (val) {
this.msgFromParent = val
}
}
}
</script>
<style scoped>
</style>
子组件数据:
<template>
<div>
<h2>{{ msgFromParent }}</h2>
<button @click="changeParentData">改变父组件的值</button>
</div>
</template>
<script>
export default {
name: "ChildA",
// 子组件通过Props接收父组件传递来的数据和方法,在组件实例上可以直接获取和触发
props: {
msgFromParent: String,
changeMsgFromParent: Function
},
methods: {
changeParentData () {
this.changeMsgFromParent("msg changed by childA")
}
}
}
</script>
<style scoped>
</style>
4. this.$emit触发父组件方法实现
在父组件中定义一个修改数据的方法,然后传递给子组件,子组件通过this,$emit直接触发父组件的方法,同时子组件可以传递参数给父组件,实现父子通信。
父组件代码:
<template>
<div>
<h2>父组件</h2>
<ChildA :msgFromParent="msgFromParent"
@changeMsgFromParent="changeMsgFromParent" />
<!-- 父组件将更改自己数据的方法传递给子组件 -->
</div>
</template>
<script>
import ChildA from './ChildA.vue'
export default {
components: { ChildA },
data () {
return {
msgFromParent: "msg from parent"
}
},
methods: {
changeMsgFromParent (val) {
this.msgFromParent = val
}
}
}
</script>
<style scoped>
</style>
子组件代码:
<template>
<div>
<h2>{{ msgFromParent }}</h2>
<button @click="changeParentData">改变父组件的值</button>
</div>
</template>
<script>
export default {
name: "ChildA",
props: {
msgFromParent: String,
},
methods: {
changeParentData () {
// 子组件通过this.$emit触发父组件的方法,同时可以进行数据传递
this.$emit("changeMsgFromParent", "msg changed by childA")
}
}
}
</script>
<style scoped>
</style>
5.子组件通过this.$parent直接触发父组件
子组件直接触发父组件的事件,无需进行方法的传递与接收。
父组件代码:
```javascript
<template>
<div>
<h2>父组件</h2>
<ChildA :msgFromParent="msgFromParent" />
</div>
</template>
<script>
import ChildA from './ChildA.vue'
export default {
components: { ChildA },
data () {
return {
msgFromParent: "msg from parent"
}
},
methods: {
// 父组件定义需要的方法
changeMsgFromParent (val) {
this.msgFromParent = val
}
}
}
</script>
<style scoped>
</style>
子组件代码:
<template>
<div>
<h2>{{ msgFromParent }}</h2>
<button @click="changeParentData">改变父组件的值</button>
</div>
</template>
<script>
export default {
name: "ChildA",
props: {
msgFromParent: String,
},
methods: {
changeParentData () {
// 子组件通过this.$parent直接触发父组件的方法,同时可以进行数据传递
this.$parent.changeMsgFromParent("msg changed by childA")
}
}
}
</script>
<style scoped>
</style>