vue组件间通信

父组件通过props传递数据给子组件

父组件通过props属性向子组件传递数据,子组件利用组件实例的props属性定义组件需要接收的参数,在使用组件时通过attribute的方式传入参数,如:

// 在子组件内定义组件接收一个参数 name
{
  props: ['name']
}
// 父组件使用组件时传递参数 name
<child :name="name"></child>

示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <parent></parent>
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
  //定义了组件 parent,在组件中使用 <child></child> 引用组件,并用 attribute 的方式将 name 传递给组件 child
  Vue.component('parent', {
    template: '<child :name="name"></child>',
    data() {
      return {
        name: '句号'
      }
    }
  })
  //定义了组件 child,并用 props 接收一个参数 name。
  Vue.component('child', {
    template: '<div>{{name}}</div>',
    props: ['name']
  })
  var vm = new Vue({
    el: '#app',
    data() {
      return {}
    }
  })
</script>
</html>

定义props的类型和默认值

上面props接收一个组件参数数组,实际上,props也可以接收一个对象,对象key为组件接收参数的参数名,其值是一个对象,属性type用来指定参数的类型,属性default用来指定参数默认值。

{
  props: {
    name: {
      type: String,
      default: '句号'
    }
  }
}

示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <parent></parent>
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
  //定义了组件 parent,在组件中使用 <child></child> 两次引用组件,<child :name="name" /> 的方式传递 name 值,<child/> 使用默认的 name 值。
  Vue.component('parent', {
    template: '<div><child :name="name" /><child/></div>',
    data() {
      return {
        name: '慕课网'
      }
    }
  })
  //定义了组件 child,并用 props 接收一个字符串类型的参数 name,其默认值是:句号。
  Vue.component('child', {
    template: '<div>{{name}}</div>',
    props: {
      name: {
        type: String,
        default: '句号'
      }
    }
  })
  var vm = new Vue({
    el: '#app',
    data() {
      return {}
    }
  })
</script>
</html>

组件parent,在组件中使用两次引用组件, 的方式传递 name 值, 使用默认的 name 值。

注意,给数组和对象类型的props设置默认值的时候,需要安装以下的写法:

props: {
  detail: {
    type: Object,
    default: () => {
      return {
        name: '句号'
      }
    }
  },
  loves: {
    type: Array,
    default: () => {
      return []
    }
  }
}

子组件通过$emit传递数据给父组件

子组件通过$emit传递事件给父组件,父组件通过$on监听事件:

// 子组件定义事件
this.$emit('事件名称', '传递的参数') //例: this.$emit('add', 111)

// 父组件监听事件的触发
<child  @事件名称="事件触发的方法"/>

示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <parent></parent>
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
  //定义了组件 parent,在组件中使用 <child :name="name" :age="age" @add="add"/> 引用组件,并绑定 add 事件,当事件 add 触发时调用 methods 中的 add 函数。
  Vue.component('parent', {
    template: '<div><child :name="name" :count="count" @add="add"/></div>',
    data() {
      return {
        name: '句号',
        count: 18
      }
    },
    methods: {
      // 父组件通过 @事件名 监听
      // count 表示事件触发传递的参数
      add(count) {
        this.count = count
      }
    }
  })
  //定义了组件 child,该组件接收两个参数:1. 字符串类型的 name,默认值为:句号。2. 数字类型的 age,默认值为 18。组件模版中,通过按钮点击事件触发 add 方法,该方法内部通过 $emit 触发事件 add,并将 age + 1 的值作为参数传递。
  Vue.component('child', {
    template: '<div>我是:{{name}}, 我今年 {{count}}岁。<button @click="add">加一岁</button></div>',
    props: {
      name: {
        type: String,
        default: '句号'
      },
      count: {
        type: Number,
        default: 18
      }
    },
    methods: {
      add(){
        // add -> 触发的事件名
        // this.count + 1 -> 触发事件时传递的参数
        this.$emit('add', this.count + 1)
      }
    }
  })
  var vm = new Vue({
    el: '#app',
    data() {
      return {}
    }
  })
</script>
</html>

非父子组件间数据传递

  • 对于兄弟组件的数据通信:它们有共同的父组件,我们可以通过父组件传递的方式实现数据通信。
  • 对于子孙组件的数据通信:可以通过 props 的方式向下逐层传递下去,也可以通过 $emit 将事件向上逐层传递。
  • 对于非关系组件的数据通信:通过使用一个空的Vue实例作为中央事件总线。

通过公有的父组件进行非父子组件间的通信

假设现在有三个组件分别是Parent、ChildA、ChildB,其中组件Parent是ChildA和ChildB的父组件,ChildA和ChildB为兄弟组件,ChildA和ChildB组件间的通信可以借助Parent来间接传递。它的流程大致是这样:
ChildA通过$emit将数据传递给Parent,Parent再通过props将数据传递给ChildB 。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <person @modify="modify"></person>
    // 将 name 和 age 传递给组件 detail。
    <detail :name="name" :count="count"/>
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
  //定义了组件 person,它通过 $emit 将组件内输入的 name 和 age 传递给父组件。
  Vue.component('person', {
    template: '<div><div>姓名:<input type="text" v-model="name"/></div><div>年龄:<input type="text" v-model="count"/></div><button @click="modify">修改</button></div>',
    data() {
      return {
        name: '句号',
        count: 18
      }
    },
    methods: {
      modify() {
        this.$emit('modify', {name: this.name, count: this.count})
      }
    }
  })
  //定义了组件 detail,它从父组件接收 name 和 age 两个参数。
  Vue.component('detail', {
    template: '<div>我是:{{name}}, 我今年 {{count}}岁。</div>',
    props: {
      name: {
        type: String,
        default: '句号'
      },
      count: {
        type: Number,
        default: 18
      }
    },
    methods: {
    }
  })
  //接收了组件 person 传递过来的事件,并修改 name 和 age。
  var vm = new Vue({
    el: '#app',
    data() {
      return {
        name: '句号',
        count: 18
      }
    },
    methods: {
      modify(detail) {
        this.name = detail.name
        this.count = parseInt(detail.count)
      }
    }
  })
</script>
</html>

通过使用一个空的 Vue 实例作为中央事件总线

在Vue中可以使用 EventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件。
首先我们需要做的是创建事件总线,并将它挂载到Vue原型上,在实例中通过this.bus.$emit发送事件,通过this.bus.$on接收事件。

// 定义事件总线
let bus = new Vue()
Vue.prototype.bus = bus

// 定义发送事件
this.bus.$emit('事件名称', data)

// 定义接收事件 并在回调中接收参数
this.bus.$on('事件名称', (data) => {      
})

示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <person></person>
    <detail />
  </div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script type="text/javascript">
  //通过 new Vue() 创建一个 vue 实例,并将它挂载在 Vue 的原型上。这样,在 vue 组件中可以通过 this.bus 访问到这个实例对象。
  let bus = new Vue()
  Vue.prototype.bus = bus

  //定义了组件 person,当点击修改按钮的时候通过 this.bus.$emit 发送一个名为 modify 的事件,并将组件内输入的 name 和 age 作为参数传递。
  Vue.component('person', {
    template: '<div><div>姓名:<input type="text" v-model="name"/></div><div>年龄:<input type="text" v-model="count"/></div><button @click="modify">修改</button></div>',
    data() {
      return {
        name: '句号',
        count: 18
      }
    },
    methods: {
      modify() {
        this.bus.$emit('modify', {name: this.name, count: this.count})
      }
    }
  })
  //定义组件 detail,在组件内部通过 this.bus.$on 监听名为 modify 的事件,当事件触发时执行修改操作。
  Vue.component('detail', {
    template: '<div>我是:{{name}}, 我今年 {{count}}岁。</div>',
    data() {
      return {
        name: '句号',
        count: 18
      }
    },
    mounted() {
      this.bus.$on('modify', (detail) => {
        this.name = detail.name
        this.count = detail.count
      })
    }
  })
  var vm = new Vue({
    el: '#app',
    methods: {
    }
  })
</script>
</html>
posted @ 2020-07-31 19:36  柒丶月  阅读(140)  评论(0编辑  收藏  举报