Vue组件通信

269 阅读2分钟
父子组件通信问题
  1. 只有父元素和子元素 父元素通过 props 给子元素传递数据,子元素通过$emit 方法通过事件的方法向父元素传递数据 // 父元素
<Tab :currentTab="currentTab" :tablist="tablist" @change-tab="tabChange"></Tab>
<script>
import Tab from '../../../components/Tab1'
export default {
  components: { Tab },
  methods: {
    tabChange(index) {
      this.currentTab = index
    }
  }
}
</script>

// 子元素

<template>
  <div class="head">
    <div class="tab" :currentTab="currentTab" v-for="(item, index) in tablist" :key="index" :class="[currentTab === index ? 'active' : '']" @click="tabChange(index)">
      <span>{{item.name}}</span>
      <span :class="item.theme" v-if="item.count && item.showCount"></span>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    tablist: {
      type: Array
    },
    currentTab: Number
  },
  methods: {
    tabChange(index) {
      this.$emit('change-tab', index)
    }
  }
}
</script>
  1. 多级组件嵌套 通过特性绑定attrs和listeners,父组件 A 下面有子组件 B,子组件 B 下面有子组件 C 父组件 A
<attrOne :one="one" :two="two" :three="three" :four="four" title="父组件" v-on="$listeners" @sendMsg="sendMsg"></attrOne>
<script>
import attrOne from '../../components/attrOne'
import Vue from 'vue'
export default {
  data() {
    return {
      one: 'html',
      two: 'css',
      three: 'javaScript',
      four: 'vue',
      color: 'blue'
    }
  },
  components: { attrOne },
  provide() {
    return {
      theme: this
    }
  },
  methods: {
    test(color) {
      console.log('123')
      if (color) {
        this.color = this.color
      }
      this.color = this.color === 'blue' ? 'red' : 'blue'
    },
    sendMsg(val) {
      console.log('子传第二层父元素', val)
    }
  }
}
</script>

子组件 B

<template>
  <div>
    <p>我是第一个子组件 {{ one }}</p>
    <p>第一个子组件的$attr {{ $attrs }} </p>
    <attrThree v-bind="$attrs" v-on="$listeners" @sendMsg="sendMsg"></attrThree>
  </div>
</template>
<script>
import attrTwo from '../components/attrTwo'
import attrThree from '../components/attrThree'

export default {
  props: {
    one: {
      type: String
    }
  },
  components: { attrTwo, attrThree },
  inheritAttrs: false,
  created() {
    console.log('第一个', this.$attrs)
    console.log('第一个', this.$listeners)
    // console.log('inject', this.name)
  },
  mounted() {
  },
  methods: {
    sendMsg(val) {
      console.log('子传第一个父元素', val)
    }
  }
}
</script>

子组件 C

<template>
  <div>
    <p>我是第二个子组件 {{ three }}</p>
    <p @click="send">第二个子组件的$attr {{ $attrs }} </p>
  </div>
</template>
<script>

export default {
  props: {
    three: {
      type: String
    },
    four: {
      type: String
    }
  },
  created() {
    console.log('第二个', this.$attrs)
    console.log('第二个', this.$listeners)
  },
  methods: {
    send() {
      this.$emit('sendMsg', '我是子组件信息')
    }
  }
}
</script>

  1. 中央事件总线 Events Bus 新建一个 Vue 事件 bus 对象,然后通过 bus.emit触发事件,bus.on 监听触发的事件。
// event-bus.js

import Vue from 'vue'
export const EventBus = new Vue()

//子组件
<template>
  <button @click="decrease()">-</button>
</template>

<script>
import { EventBus } from '../event-bus.js'
export default {
  name: 'DecreaseCount',
  data() {
    return {
      num: 1,
      deg: 180
    }
  },
  methods: {
    decrease() {
      EventBus.$emit('decreased', {
        num: this.num,
        deg: this.deg
      })
    }
  }
}
</script>
// 父组件
<!-- App.vue -->
<template>
  <div id="app">
    <div class="container">
      <div class="front">
        <div class="increment">
          <IncrementCount />
        </div>
        <div class="show-front">{{ fontCount }}</div>
        <div class="decrement">
          <DecreaseCount />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import IncrementCount from '../../components/incrementCount'
import DecreaseCount from '../../components/decreaseCount'
import { EventBus } from '../../event-bus'
export default {
  name: 'App',
  components: {
    IncrementCount,
    DecreaseCount
  },
  data() {
    return {
      degValue: 0,
      fontCount: 0,
      backCount: 0
    }
  },
  mounted() {
    EventBus.$on('incremented', ({ num, deg }) => {
      // 修改数据
      this.fontCount += num
      // DOM还没更新
      // $nextTick,将回调延迟到下次 DOM 更新循环之后执行。
      this.$nextTick(() => {
        // DOM已经更新
        this.backCount += num
        this.degValue += deg
      })
    })
    EventBus.$on('decreased', ({ num, deg }) => {
      this.fontCount -= num
      this.$nextTick(() => {
        this.backCount -= num
        this.degValue -= deg
      })
    })
  }
}
</script>

  1. provide / inject 允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。 provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性。 inject 可以是:一个字符串数组或者一个对象,对象的 key 是本地的绑定名。
<attrOne
      :one="one"
      :two="two"
      :three="three"
      :four="four"
      title="父组件"
      v-on="$listeners"
      @sendMsg="sendMsg"
      @changeParent="changeParent"
    ></attrOne>
// 父组件
  provide() {
    // 让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象,返回的对象可以直接用于渲染函数和计算属性内,并且会在发生改变时触发相应的更新。也可以作为最小化的跨组件状态存储器.
    this.theme = Vue.observable({
      color: 'blue'
    })
    return {
      theme: this.theme
    }
  },
  test(color) {
      this.color = this.color === 'blue' ? 'red' : 'blue'
      // 子组件响应式更新
      this.theme.color = this.theme.color === 'blue' ? 'red' : 'blue'
    },
// 子组件 两种方法
  inject: ['theme'],
  inject: {
    theme: {
      //函数式组件取值不一样
      default: () => ({})
    }
  },

  1. parent /children 只单纯适用于父子组件,兄弟间的组件不适用, ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
  2. vuex 这是链接