父子组件通信问题

# 父子组件通信问题
  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>
1
2
3
4
5
6
7
8
9
10
11
12

// 子元素

<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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

子组件 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

子组件 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  1. 中央事件总线 Events Bus 新建一个 Vue 事件 bus 对象,然后通过 bus.$emit触发事件,bus.$on 监听触发的事件。
// event-bus.js

import Vue from 'vue'
export const EventBus = new Vue()
1
2
3
4
//子组件
<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 父组件 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  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' },
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 子组件 两种方法
  inject: ['theme'],
  inject: {
    theme: {
      //函数式组件取值不一样
      default: () => ({})
    }
  },

1
2
3
4
5
6
7
8
9
  1. $parent / $children 只单纯适用于父子组件,兄弟间的组件不适用, ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
  2. vuex 这是链接 (opens new window)
上次更新: 4/12/2021, 3:23:17 PM