面试题答案
一键面试Vuex和Pinia插件扩展机制的不同
- Vuex
- 插件定义:Vuex插件是一个函数,它接收
store
作为参数。通过在插件函数内部监听store
的各种生命周期钩子,如mutation
触发等,来实现对store
功能的扩展。例如,记录所有mutation
的日志插件:
- 插件定义:Vuex插件是一个函数,它接收
const logger = store => {
store.subscribe((mutation, state) => {
console.log(`mutation type: ${mutation.type}`);
console.log(`mutation payload: ${mutation.payload}`);
console.log('new state:', state);
});
};
- 插件注册:在创建
store
时,通过plugins
选项进行注册。
import Vue from 'vue';
import Vuex from 'vuex';
import logger from './logger';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
plugins: [logger]
});
- Pinia
- 插件定义:Pinia插件也是一个函数,它接收
context
对象,context
包含pinia
实例、正在安装插件的store
以及app
(如果在Vue应用中使用)。例如,一个简单的Pinia插件用于记录所有修改store
状态的操作:
- 插件定义:Pinia插件也是一个函数,它接收
const logger = ({ store }) => {
const unsubscribe = store.$subscribe((mutation, state) => {
console.log(`mutation type: ${mutation.type}`);
console.log('new state:', state);
});
return () => {
unsubscribe();
};
};
- 插件注册:通过
pinia.use()
方法全局注册插件。
import { createPinia } from 'pinia';
import logger from './logger';
const pinia = createPinia();
pinia.use(logger);
与Vue生态系统其他工具的融合
- 与路由融合
- Vuex:在Vuex中,可以通过
mutation
或action
来响应路由变化。例如,在用户访问特定路由时,加载相应的数据。假设应用有一个用户详情页,路由为/user/:id
。
- Vuex:在Vuex中,可以通过
// router.js
import Vue from 'vue';
import Router from 'vue-router';
import UserDetail from './components/UserDetail.vue';
Vue.use(Router);
const router = new Router({
routes: [
{
path: '/user/:id',
name: 'UserDetail',
component: UserDetail
}
]
});
// store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
user: null
},
mutations: {
setUser(state, user) {
state.user = user;
}
},
actions: {
async loadUser({ commit }, id) {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
commit('setUser', user);
}
}
});
router.beforeEach((to, from, next) => {
if (to.name === 'UserDetail') {
store.dispatch('loadUser', to.params.id);
}
next();
});
- Pinia:同样可以在Pinia中实现类似功能。假设我们有一个
userStore
。
// userStore.js
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
user: null
}),
actions: {
async loadUser(id) {
const response = await fetch(`/api/users/${id}`);
this.user = await response.json();
}
}
});
// router.js
import Vue from 'vue';
import Router from 'vue-router';
import UserDetail from './components/UserDetail.vue';
import { useUserStore } from './userStore';
Vue.use(Router);
const router = new Router({
routes: [
{
path: '/user/:id',
name: 'UserDetail',
component: UserDetail
}
]
});
router.beforeEach((to, from, next) => {
if (to.name === 'UserDetail') {
const userStore = useUserStore();
userStore.loadUser(to.params.id);
}
next();
});
- 与组件库融合
- Vuex:以Element - UI为例,假设组件库中的按钮点击需要更新Vuex中的状态。例如,有一个按钮用于增加计数器。
<template>
<el - button @click="increment">Increment</el - button>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
methods: {
...mapMutations(['increment'])
}
};
</script>
- Pinia:同样以Element - UI为例,在组件中使用Pinia更新状态。假设
counterStore
有一个增加计数器的方法。
<template>
<el - button @click="increment">Increment</el - button>
</template>
<script>
import { useCounterStore } from './counterStore';
export default {
setup() {
const counterStore = useCounterStore();
return {
increment: counterStore.increment
};
}
};
</script>
定制化扩展满足复杂业务场景
- Vuex:在一个电商项目中,需要实现购物车的复杂业务逻辑,如合并相同商品、计算总价等。可以创建一个购物车相关的插件来扩展Vuex的功能。
const cartPlugin = store => {
// 监听mutation,处理购物车商品合并逻辑
store.subscribe((mutation, state) => {
if (mutation.type === 'addProductToCart') {
const { product } = mutation.payload;
const existingProduct = state.cart.find(p => p.id === product.id);
if (existingProduct) {
existingProduct.quantity++;
} else {
product.quantity = 1;
state.cart.push(product);
}
}
});
// 添加一个计算购物车总价的getter
Object.defineProperty(store.getters, 'cartTotalPrice', {
get() {
return store.state.cart.reduce((total, product) => {
return total + product.price * product.quantity;
}, 0);
}
});
};
然后在创建store
时注册该插件。
const store = new Vuex.Store({
state: {
cart: []
},
mutations: {
addProductToCart(state, payload) {
// 这里简单触发,实际逻辑在插件中处理
}
},
plugins: [cartPlugin]
});
- Pinia:在一个多语言项目中,需要动态切换语言并保存状态。可以创建一个语言切换的Pinia插件。
const i18nPlugin = ({ pinia, app }) => {
const languageStore = defineStore('language', {
state: () => ({
currentLanguage: 'en'
}),
actions: {
setLanguage(lang) {
this.currentLanguage = lang;
// 在这里可以调用i18n库的方法切换语言
}
}
});
// 全局注入语言切换方法
app.config.globalProperties.$setLanguage = (lang) => {
const store = languageStore();
store.setLanguage(lang);
};
return () => {
// 插件卸载时的清理逻辑,这里暂时没有
};
};
const pinia = createPinia();
pinia.use(i18nPlugin);
这样在组件中就可以通过this.$setLanguage('zh')
来切换语言,满足多语言切换的复杂业务场景。