Vue 3.0 中provide常见使用场景

发布于:2025-05-28 ⋅ 阅读:(25) ⋅ 点赞:(0)

provide 和 inject 是 Vue 中用于跨组件传递数据的一对 API。provide 用于在祖先组件中提供数据,而 inject 用于在后代组件中注入这些数据。这种机制使得不需要通过一层一层的 props 传递数据,就可以在任何后代组件中获取祖先组件提供的数据。

在状态管理中,provide 和 inject 适用于一些全局或跨组件的数据共享场景,例如主题切换和语言切换。通过这对 API,可以在不依赖 Vuex 等状态管理工具的情况下,实现数据的全局共享和响应式更新。

1. 基本示例

父组件中:

<script setup>
import { ref, provide } from 'vue'
import { countSymbol } from './injectionSymbols'

// 提供静态值
provide('path', '/project/')

// 提供响应式的值
const count = ref(0)
provide('count', count)

// 提供时将 Symbol 作为 key
provide(countSymbol, count)
</script>

子组件中:

<script setup>
import { inject } from 'vue'
import { countSymbol } from './injectionSymbols'

// 注入不含默认值的静态值
const path = inject('path')

// 注入响应式的值
const count = inject('count')

// 通过 Symbol 类型的 key 注入
const count2 = inject(countSymbol)

// 注入一个值,若为空则使用提供的默认值
const bar = inject('path', '/default-path')

// 注入一个值,若为空则使用提供的函数类型的默认值
const fn = inject('function', () => {})

// 注入一个值,若为空则使用提供的工厂函数
const baz = inject('factory', () => new ExpensiveObject(), true)
</script>

2. 主题换肤示例

2.1. 提供主题

在祖先组件中使用 provide 提供主题数据:

// App.vue
<template>
    <div :class="currentTheme">
        <button @click="toggleTheme">Toggle Theme</button>
        <ChildComponent />
    </div>
</template>

<script>
export default {
    data() {
        return {
            theme: 'light' // 默认主题
        };
    },
    computed: {
        currentTheme() {
            return this.theme == 'light' ? 'theme-light' : 'theme-dark';
        }
    },
    methods: {
        toggleTheme() {
            this.theme = this.theme === 'light' ? 'dark' : 'light';
        }
    },
    provide() {
        return {
            theme: this.theme
        };
    }
};
</script>

<style>
.theme-light {
    background-color: white;
    color: black;
}

.theme-dark {
    background-color: black;
    color: white;
}
</style>

2.2. 使用主题

在后代组件中使用 inject 注入主题数据:

// ChildComponent.vue
<template>
    <div>
        <p>Current theme: {{ theme }}</p>
    </div>
</template>

<script>
export default {
    inject: ['theme']
};
</script>

2.3. 更新主题 

为了使主题数据响应式,可以使用 Vue 的响应式机制,如 reactive 或 ref。下面是一个使用 ref 的例子:

// App.vue
<template>
    <div :class="currentTheme">
        <button @click="toggleTheme">Toggle Theme</button>
        <childComponent />
    </div>
</template>

<script>
import { ref, provide, computed } from 'vue';

export default {
    setup() {
        const theme = ref('light');
        const toggleTheme = () => {
            theme.value = theme.value === 'light' ? 'dark' : 'light';
        };

        const currentTheme = computed(() => (theme.value === 'light' ? 'theme-light' : 'theme-dark'));

        provide('theme', theme);

        return {
            theme,
            toggleTheme,
            currentTheme
        };
    }
};
</script>

<style>
.theme-light {
    background-color: white;
    color: black;
}

.theme-dark {
    background-color: black;
    color: white;
}
</style>

在子组件中:

// ChildComponent.vue
<template>
    <div>
        <p>Current theme: {{ theme }}</p>
    </div>
</template>

<script>
import { inject } from 'vue';

export default {
    setup() {
        const theme = inject('theme');
        return {
            theme
        };
    }
};
</script>

3. 语言切换示例

3.1. 提供语言

在祖先组件中使用 provide 提供语言数据:

// App.vue
<template>
    <div>
        <button @click="toggleLanguage">Toggle Language</button>
        <childComponent />
    </div>
</template>

<script>
export default {
    data() {
        return {
            language: 'en' // 默认语言
        };
    },
    methods: {
        toggleLanguage() {
            this.language = this.language === 'en' ? 'fr' : 'en';
        }
    },
    provide() {
        return {
            language: this.language,
            translations: {
                en: {
                    greeting: 'Hello'
                },
                fr: {
                    greeting: 'Bonjour'
                }
            }
        };
    }
};
</script>

3.2. 使用语言

在后代组件中使用 inject 注入语言数据:

// ChildComponent.vue
<template>
    <div>
        <p>{{ translation.greeting }}</p>
    </div>
</template>

<script>
export default {
    inject: ['language', 'translations'],
    computed: {
        translation() {
            return this.translations[this.language];
        }
    }
};
</script>

3.3.  更新语言

为了使语言数据响应式,可以使用 Vue 的响应式机制,如 reactive 或 ref。下面是一个使用 ref 的例子:

// App.vue
<template>
    <div>
        <button @click="toggleLanguage">Toggle Language</button>
        <childComponent />
    </div>
</template>

<script>
import { ref, provide } from 'vue';

export default {
    setup() {
        const language = ref('en');
        
        const toggleLanguage = () => {
            language.value = language.value === 'en' ? 'fr' : 'en';
        };

        const translations = {
            en: {
                greeting: 'Hello'
            },
            fr: {
                greeting: 'Bonjour'
            }
        };

        provide('language', language);
        provide('translations', translations);

        return {
            language,
            toggleLanguage
        };
    }
};
</script>

在子组件中:

// ChildComponent.vue
<template>
    <div>
        <p>{{ translation.greeting }}</p>
    </div>
</template>

<script>
import { inject, computed } from 'vue';

export default {
    setup() {
        const language = inject('language');
        const translations = inject('translations');

        const translation = computed(() => translations[language.value]);

        return {
            translation
        };
    }
};
</script>

网站公告

今日签到

点亮在社区的每一天
去签到