vue是单项数据流,引用Vue的官网的话:父系 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父及组件的状态,从而导致你的应用的数据流向难以理解。

在父子组件通讯的时候,子组件都禁止直接修改父级传过来的prop 直接修改在控制台会报错。但VUE的两个语法糖能做到这一点,就是自定义组件上的 v-model指令 以及 .sync修饰符。

另外,还可以通过子组件触发父组件中方法的方式,通过父组件的方法,更改父组件的数据。

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>

setTimeOu之前的t效果
1s后修改成功:
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>
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐