vue面试题:Vue组件通讯有几种方式,尽量全面

35 阅读1分钟

分类

  • props和$emit
  • 自定义事件
  • $attrs
  • $parent
  • $refs
  • provide/inject
  • Vuex

不同场景

  • 父子组件
  • 上下级组件(跨多级)通讯
  • 全局组件

代码演示

1. props $emit

父组件:

image.png

image.png

子组件:

image.png

2. 自定义事件方式(适合不相关的组件通讯)

父组件:

image.png image.png

子组件1 :CustomEvent1

image.png

子组件2 :CustomEvent2

image.png

event.js:

image.png

3. $attrs (props和emit的候补)

vue3 移除了 listeners(listeners (把 listeners 合并到了 $attrs)

level1:

<template>
  <p>level1</p>
  <Level2
    :a="a"
    :b="b"
    :c="c"
    @getA="getA"
    @getB="getB"
    @getC="getC"
  ></Level2>
</template>

<script>
import Level2 from './Level2.vue'
export default {
  name: 'Level1',
  components: {
    Level2,
  },
  data() {
    return {
      a: 'aaa',
      b: 'bbb',
      c: 'ccc',
    }
  },
  methods: {
    getA() {
      return this.a
    },
    getB() {
      return this.b
    },
    getC() {
      return this.c
    },
  },
}
</script>

level2:

<template>
  <p>level2</p>
  <Level3 :x="x" :y="y" :z="z" @getX="getX" @getY="getY" @getZ="getZ" v-bind="$attrs"></Level3>
</template>

<script>
import Level3 from './Level3.vue'
export default {
  name: 'Level2',
  components: {
    Level3,
  },
  props: ['a'], // vue2.x $attrs
  emits: ['getA'], // vue2.x $listeners  vue3 中 合并到attrs中
  data() {
    return {
      x: 'xxx',
      y: 'yyy',
      z: 'zzz',
    }
  },
  methods: {
    getX() {
      return this.x
    },
    getY() {
      return this.y
    },
    getZ() {
      return this.z
    },
  },
  created() {
    console.log('level2:',Object.keys(this.$attrs)) // 是 props 和 emits 的候补
  },
}
</script>

level3:

<template>
  <p>level3</p>
</template>

<script>
export default {
  name: 'level3',
  props: ['x'],
  emits: ['getX'],
  inheritAttrs:false,
  data() {
    return {}
  },
  created() {
    console.log('level3:', Object.keys(this.$attrs))
  },
}
</script>

打印的结果:

image.png

4. $parent 直接获取父组件

level3:

<template>
  <p>level3</p>
</template>

<script>
export default {
  name: 'level3',
  props: ['x'],
  emits: ['getX'],
  inheritAttrs:false,
  data() {
    return {}
  },
  created() {
    // console.log('level3:', Object.keys(this.$attrs))
  },
  mounted() { 
    console.log('level3的parent level2:',this.$parent);
  }
}
</script>

结果:拥有level2中所有的属性和方法

image.png

5. refs 直接获取子组件

level3组件:

<template>
  <p>level3</p>
  <HelloWorld msg="hello jackson" ref="hello1"></HelloWorld>
</template>

<script>
import HelloWorld from './HelloWorld.vue'
export default {
  components: {
    HelloWorld
  },
  name: 'level3',
  props: ['x'],
  emits: ['getX'],
  inheritAttrs:false,
  data() {
    return {}
  },
  created() {
    // console.log('level3:', Object.keys(this.$attrs))
  },
  mounted() { 
    // console.log('level3的parent level2:', this.$parent);
    console.log(this.$refs.hello1.name); // 只能在mounted中获取,不能在created中获取,因为created组件树还没完全渲染完成
  }
}
</script>

HelloWorld组件:

<template>
  <div>
    <h1 @click="clickHandler">{{ msg }}</h1>

  </div>
</template>

<script>
export default {
  name: 'hello world',
  props: {
    msg: String,
  },
  emits: ['showMsg'],
  data() { 
    return {
      name:'hello-world'
    }
  },
  methods: {
    clickHandler() { 
      this.$emit('showMsg','hello world')
    }
  }
}
</script>

结果:

image.png

6. provide inject 完美的多层级透传

level1组件:

<template>
  <p>level1: <input v-model="name"></p>
  <Level2></Level2>
</template>
<script>
import Level2 from './Level2.vue'
import { computed} from 'vue'
export default {
  name: 'Level1',
  components: {
    Level2
  },
  data() { 
    return {
      name:'jackson'
    }
  },
  // provide: {
  //   info:'aaa' //静态数据传输方法
  // }
  provide() { 
    return {
      info:computed(()=>this.name) // 响应式数据
    }
  }
}
</script>

level2组件:

<template>
  <p>level2 {{ info }}</p>
  <Level3></Level3>
</template>
<script>
import Level3 from './Level3.vue'

export default {
  name: 'Level2',
  components: {
    Level3
  },
  inject:['info'],
  data() { 
    return {}
  }
}
</script>

level3组件:

<template>
  <p>level3: {{ info }}</p>
</template>
<script>
export default {
  name: 'Level3',
  components: {
    
  },
  inject:['info'],
  data() { 
    return {}
  }
}
</script>

结果:

image.png