基于vue-cli实现各种关系组件间的通信

根据组件关系划分

  1. 父子

    1. props/$emit,$on
    2. $parent/$children
    3. $refs
  2. 兄弟

    1. Bus
    2. Vuex
  3. 跨级

    1. Bus
    2. Vuex
    3. provide / inject
    4. $attrs/$listeners

父子

props/$emit,$on

<template>
  <div>
    <test3-a :value="value"
             @input="handleChange"></test3-a>
  </div>
</template>
<script>
import test3A from '../components/test3-a.vue'

export default {
  components: { test3A },
  data () {
    return {
      value: 1
    }
  },
  methods: {
    handleChange (val) {
      this.value = parseInt(val)
    }
  }
}
</script>

<template>
  <div>
    <button @click="increase(-1)">减1</button>
    <span> {{currentValue}} </span>
    <button @click="increase(1)">加1</button>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: Number
    }
  },
  data () {
    return {
      currentValue: this.value
    }
  },
  methods: {
    increase (val) {
      this.currentValue = this.value + val
      this.$emit('input', this.currentValue)
    }
  }
}
</script>

props/$emit,$on(v-model写法)

v-model 是一个语法糖,可以拆解为 props: value 和 events: input。就是说组件必须提供一个名为 value 的 prop,以及名为 input 的自定义事件

<template>
  <div>
    <test3-a v-model="value"></test3-a>
  </div>
</template>
<script>
import test3A from '../components/test3-a.vue'

export default {
  components: { test3A },
  data () {
    return {
      value: 1
    }
  }
}
</script>

子(不用修改)

<template>
  <div>
    <button @click="increase(-1)">减1</button>
    <span> {{currentValue}} </span>
    <button @click="increase(1)">加1</button>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: Number
    }
  },
  data () {
    return {
      currentValue: this.value
    }
  },
  methods: {
    increase (val) {
      this.currentValue = this.value + val
      this.$emit('input', this.currentValue)
    }
  }
}
</script>

props/$emit,$on(.sync写法)

.sync 不是真正的双向绑定,而是一个语法糖,修改数据还是在父组件完成的,并非在子组件

<template>
  <div>
    <test3-a :value.sync="value"></test3-a>
  </div>
</template>
<script>
import test3A from '../components/test3-a.vue'

export default {
  components: { test3A },
  data () {
    return {
      value: 1
    }
  }
}
</script>

<template>
  <div>
    <button @click="increase(-1)">减1</button>
    <span> {{value}} </span>
    <button @click="increase(1)">加1</button>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: Number
    }
  },
  methods: {
    increase (val) {
      this.$emit('update:value', this.value + val)
    }
  }
}
</script>

$refs/$parent,$children

<template>
  <div>
    <button @click="handleRef">handleRef</button>
    <test2-a ref="test2a"
             :value="value"></test2-a>
  </div>
</template>
<script>
import test2A from '../components/test2-a.vue'
export default {
  components: { test2A },
  data () {
    return {
      value: 1
    }
  },
  methods: {
    handleRef () {
      this.$children[0].currentValue = 2
      // this.$refs.test2a.currentValue = 2
    }
  }
}
</script>

<template>
  <div>
    <p>{{currentValue}}</p>
    <button @click="handleChange">handleChange</button>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: Number
    }
  },
  data () {
    return {
      currentValue: this.value
    }
  },
  methods: {
    handleChange () {
      this.$parent.value = 2
      this.currentValue = this.$parent.value
    }
  }
}
</script>

兄弟

bus

/tools/bus.js

import Vue from 'vue'
export default new Vue()

<template>
  <div>
    <p>bus通信</p>
    <test4-a></test4-a>
    <test4-b></test4-b>
  </div>
</template>

<script>

import test4A from '../components/test4-a.vue'
import test4B from '../components/test4-b.vue'
export default {
  components: {
    test4A,
    test4B
  }
}
</script>

子 test4-a

<template>
  <div>
    组件test4-a
    <button @click="sendMsg">发个消息级兄弟组件b</button>
  </div>
</template>

<script>
import bus from '../tools/bus'
export default {
  methods: {
    sendMsg () {
      bus.$emit('send', 'hello b')
    }
  }
}
</script>

子 test4-b

<template>
  <div>
    <p>组件tes4-b:{{ msg }}</p>
  </div>
</template>
<script>
import bus from '../tools/bus'
export default {
  data () {
    return {
      msg: 'i am message'
    }
  },
  created () {
    bus.$on('send', data => {
      this.msg = data
    })
  }
}
</script>

跨级

provide / inject(父级与后代)

//app.vue

<script>
  export default {
    provide () {
      return {
        app: this
      }
    },
    data () {
      return {
        adminUser : null
      }
    },
    methods: {
        setAdminUser () {
          this.adminUser = 'admin'
        },
    },
    mounted () {
      this.setAdminUser ();
    }
  }
</script>

任何页面组件

<template>
  <div>
    {{ app.adminUser }}
  </div>
</template>
<script>
  export default {
    inject: ['app']
  }
</script>

$attrs/$listeners

<template>
  <div>
    <test1-a :value="value"
             @sendToUp="handleOn">
    </test1-a>
  </div>
</template>
<script>
import test1A from '@/components/test1-a.vue'
export default {
  data () {
    return {
      value: 'Hello, world'
    }
  },
  components: { test1A },
  methods: {
    handleOn (val) {
      this.value = val
    }
  }
}
</script>

<template>
  <div>
    <p>attrs:{{$attrs}}</p>
    <test1-a-children v-bind="$attrs"
                      v-on="$listeners"></test1-a-children>
  </div>
</template>
<script>
import test1AChildren from './test1-a-children'
export default {
  components: {
    test1AChildren
  }
}
</script>

<template>
  <div>
    <p>value:{{value}}</p>
    <button @click="handleSend">我要发射火箭</button>
  </div>
</template>
<script>
export default {
  props: ['value'],
  methods: {
    handleSend () {
      this.$emit('sendToUp', 'test1-a-children')
    }
  }
}
</script>
    原文作者:渣渣辉
    原文地址: https://segmentfault.com/a/1190000019624613
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞