14

初探 Vue 3.0 的组装式 API(四)

 3 years ago
source link: http://blog.krimeshu.com/2020/11/22/vue-3-composition-api-introduction-4/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

这次再说一说父子组件之间的传值与通信场景。

(四)组件通信与跨级传值

1. emit 与 slots

Vue3 中从父级向子级传值与 Vue2 一样,就是在模板里创建子组件的标签时,通过 v-bind: / : 指令传值。

而父组件通过 v-on: / @ 绑定的事件监听器,需要在子组件触发事件时,需要通过 props 之后的第二个参数 context 调用:

// child.vue
export default {
    setup(props, context) {
        const onClick = () => context.emit('click-child');
        // ...
    },
};

同时, context 中还提供了我们操作子组件时经常需要用到的插槽 slots

// parent.vue
export default {
    setup(props, context) {
        const { slots } = context;
        const children = (slots.default ? slots.default() : []);
        // ...
    },
};

顺带一提,由于 context 不是响应式的,所以我们可以直接在参数表中,使用解构赋值取出 emitslots

// parent.vue
export default {
    setup(props, { emit, slots }) {
        // ...
    },
};

不过需要注意, slots 的属性值也可能随时发生变化,但它本身并非响应式数据。为了确保你的组件随时获得最新的插槽状态,建议在 onUpdated 中操作其属性值。

2. 跨级传值

我们有时会遇到类似这样的需求(比如:Tab 与 TabPane),所有子组件需要根据同一个父组件/祖先组件的状态调整自身的状态,做到跨级数据联动。

a) Vue2 方案

在 Vue2 中,是被打散在不同构造参数中的 provideinject 属性实现的:

// tab.vue
exports default {
    data() {
        return {
            tabState: {
                // ...
            };
        },
    },
    // ...
    provide() {
        // 向子孙组件提供 tabState
        const { tabState } = this;
        return {
            tabState,
        };
    },
};

// tab-pane.vue
exports default {
    // 告知可以注入来自祖先的 tabState
    inject: [ tabState ],
    // ...
    methods: {
        getTabState() {
            // 取用 provide 过来的数据
            const { tabState } = this;
            // ...
        },
    },
};

可以看到,又是被打散到不同 data / methods / computed 段落的零散数据,靠 this 强行绑定到一起。

b) Vue3 方案

在 Vue3 中,则是通过 provideinject 函数,更直观地组装出来:

// tab.vue
import { reactive, provide } from 'vue';
exports default {
    setup() {
        const tabState = reactive({
            // ...
        });
        provide('tabState', tabState);
        // ...
    },
};

// tab-pane.vue
import { inject } from 'vue';
exports default {
    setup() {
        const tabState = inject('tabState');
        // 还可以传入一个默认值: const tabState = inject('tabState', { });
        // ...
    },
};

传入响应式数据后,在子孙组件都可以方便地取到,以至于甚至可以替代很多 Vuex 的使用场景。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK