Vuex精选面试大全

108 阅读4分钟

什么是状态管理模式?它主要解决的是什么问题?推荐在哪些场景用?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理插件。它采用集中式存储管理应用的所有组件的状态

状态管理模式是一种用于集中管理和维护应用数据(状态)的设计模式,它通过明确的规则确保状态变化的可预测性可维护性,尤其在复杂应用中至关重要。

💡 核心思想(以 Vuex 为例):

  1. 集中存储

    • 所有组件的共享状态(如用户信息、全局配置)存放在一个中央仓库(store)中。
    • 替代组件间层层传递数据的繁琐方式。
  2. 单向数据流

    • View(视图) :组件展示数据。

    • Action(动作) :组件触发动作(如点击按钮发起异步请求)。

    • Mutation(变更) :唯一修改状态的方式(同步操作)。

    • State(状态) :变更后更新视图。

    组件 → Action → Mutation → State → 组件更新
    
  3. 严格规则

    • 禁止直接修改 state,必须通过 mutation 提交变更。
    • 异步操作放在 action 中处理,保持变更记录的清晰。

🛠️ 解决的问题:

  1. 多组件共享状态
    多层嵌套的组件的传参将会非常繁琐,并且对于兄弟组件间的状态传递无能为力
    (例如:用户登录后,头部、侧边栏、内容区均需显示用户名)
  2. 跨层级通信
    来自不同组件的行为需要变更同一状态(购物车)
    (如父→子→孙→曾孙...)
  3. 状态变更追踪
    通过 Devtools 记录每次状态变化,便于调试和回溯问题。

🔍 常见实现方案:

  • Vue 生态:Vuex(官方)、Pinia(新一代)
  • React 生态:Redux、MobX、Context API
  • 通用方案:RxJS(响应式编程)

状态管理模式让复杂应用的数据流动清晰可控,是构建中大型前端应用的基石。

vuex的store、state、getter、mutation、action、module特性分别是什么?

在 Vuex 里,store 是一个核心概念,它是一个包含应用所有组件共享状态的容器,还提供了修改和管理这些状态的方法。它的存在使得状态能够在多个组件间共享,避免了组件间传递状态的复杂性。在 Vue 应用中,所有组件都可以访问 store 中的状态。它包括state、getter、mutation、action组成部分。

核心概念对比表

概念职责调用方式同步/异步设计目的典型场景
State存储全局状态数据直接访问, 禁止直接修改,必须通过 Mutation-数据源中心存储用户信息、配置数据
Getter派生/计算状态通过函数计算同步处理复杂状态逻辑(二次处理)过滤列表、计算总数
Mutation修改 State 的唯一方式commit()同步确保状态变更可追踪更新用户信息、计数器增减
Action处理异步或复杂逻辑dispatch()可异步协调业务逻辑并提交 Mutation调用 API、组合多个 Mutation
Module分模块管理状态模块化注册-解决大型应用状态臃肿按功能拆分(用户、订单模块)

总结

  • State 是数据源,Getter 是计算器,Mutation 是记账员,Action 是业务经理,Module 是分部门。
  • 通过严格的职责划分,Vuex 确保了大型应用状态的可维护性和可预测性。

你有使用过vuex的module吗?主要是在什么场景下使用?

由于使用单个状态树会导致应用的所有状态都集中到一个store对象上,当应用变得非常复杂时,store对象就有可能变得相当臃肿,非常难以维护。为了解决这个问题,Vuex允许我们将store分割成模块(Module)。每个模块都拥有自己的state、mutation、action、getters,甚至有自己的嵌套子模块。状态树延伸多个分支,模块的状态内聚,主枝干放全局共享状态

用过Vuex模块的命名空间吗?为什么使用,怎么使用?

默认情况下,模块内部的action、mutation和getter是注册在全局命名空间,如果多个模块中action、mutation的命名是一样的,那么提交mutation、action时,将会触发所有模块中命名相同的mutation、action。

这样有太多的耦合,如果要使你的模块具有更高的封装度和复用性,你可以通过添加namespaced: true 的方式使其成为带命名空间的模块。

export default{
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}

怎么在带命名空间的模块内注册全局的action?

actions: {
    actionA: {
        root: true,
        handler (context, data) { ... }
    }
  }

vuex的action和mutation的特性是什么?有什么区别?

mutations可以直接修改state,但只能包含同步操作,同时,只能通过提交commit调用(尽量通过Action或mapMutation调用而非直接在组件中通过this.$store.commit()提交) 。mutation可以直接变更状态。actions是用来触发mutations的,它无法直接改变state,action提交的是 mutation,它可以包含异步操作,它只能通过store.dispatch触发

接收参数不同,mutation第一个参数是state,而action第一个参数是context,其包含了

    {
        state,      // 等同于 `store.state`,若在模块中则为局部状态
        rootState,  // 等同于 `store.state`,只存在于模块中
        commit,     // 等同于 `store.commit`
        dispatch,   // 等同于 `store.dispatch`
        getters,    // 等同于 `store.getters`
        rootGetters // 等同于 `store.getters`,只存在于模块中
    }

一、核心特性对比

特性MutationAction
作用直接修改 state 的唯一途径处理异步/复杂逻辑后提交 Mutation
同步/异步必须同步可包含异步操作
触发方式commit('mutationName', payload)dispatch('actionName', payload)
参数接收 state 和 payload接收 context(包含 commitstate 等)和 payload
可追踪性Devtools 记录每次修改Devtools 仅记录 Action 的触发,不跟踪内部异步步骤

二、设计哲学与使用场景

Mutation:原子性状态修改
  • 设计目的:确保状态变更的可追踪性可预测性

  • 适用场景

    • 直接修改 state 的简单赋值操作 Mutation 只做简单赋值
    • 同步操作(如计数器增减、表单字段更新)
  • 示例

    mutations: {
      SET_USER(state, user) {
        state.user = user; // 直接同步修改
      }
    }
    
Action:复杂业务逻辑处理
  • 设计目的:处理异步任务(如 API 调用)或组合多个 Mutation

  • 适用场景

    • 异步操作(接口请求、定时器)
    • 需要多个 Mutation 协作的任务
    • 需要业务逻辑判断后修改状态(如权限校验)
  • 示例

    actions: {
      async fetchUser({ commit }, userId) {
        const user = await api.getUser(userId); // 异步请求
        if (user) {
          commit('SET_USER', user); // 提交 Mutation
        }
      }
    }
    

总结: 明确分工:Mutation 专注状态变更,Action 处理业务逻辑

vuex的值是怎么修改的?

Vuex 通过 严格模式 + 响应式劫持 + 内部状态锁 的机制,确保状态的修改只能通过 Mutation 完成。这种设计保障了:

  1. 可预测性:所有状态变更集中管理。
  2. 可追溯性:Devtools 可记录每次 Mutation 的修改历史。
  3. 数据安全:避免组件随意修改全局状态导致的数据混乱。

怎么监听vuex数据的变化?

在 Vuex 中监听数据变化是响应式开发的核心需求。以下是 监听 Vuex 状态变化的实用方法,涵盖不同场景下的最佳实践:

一、组件内监听:计算属性(自动响应)

场景:在模板或组件逻辑中直接使用状态,自动更新视图
原理:利用 Vue 的响应式系统,将 Vuex 状态映射为组件的计算属性
示例

// 组件中
computed: {
  // 监听单一状态
  count() {
    return this.$store.state.count;
  },
  // 监听多个状态(mapState 辅助函数)
  ...mapState(['user', 'cartItems'])
}

优点:简洁高效,自动依赖追踪
缺点:无法直接执行副作用(如调用 API)

二、组件内监听:watch 选项

场景:状态变化时执行异步操作或复杂逻辑
示例

watch: {
  // 监听 Vuex 状态变化
  '$store.state.user': {
    handler(newUser, oldUser) {
      if (newUser.id !== oldUser.id) {
        this.fetchUserOrders(newUser.id); // 用户变更时拉取订单
      }
    },
    deep: true // 深度监听对象内部变化
  }
}

注意:对于对象/数组,需设置 deep: true 才能监听到嵌套属性变化

三、全局监听:store.subscribe

场景:监听所有 mutations,用于日志、埋点或持久化
示例

// 在 store 初始化后
const unsubscribe = store.subscribe((mutation, state) => {
  console.log('触发的 mutation:', mutation.type);
  console.log('携带的参数:', mutation.payload);
  // 示例:用户登录后持久化 token
  if (mutation.type === 'user/SET_TOKEN') {
    localStorage.setItem('token', state.user.token);
  }
});

// 取消监听
unsubscribe(); 

适用场景

  • 开发调试时打印 mutation 日志
  • 自动同步部分状态到 localStorage
  • 第三方插件开发

四、精准监听:store.watch

场景:监听特定状态或 getter 的变化,执行全局逻辑
示例

// 监听 state.count 的变化
const unwatch = store.watch(
  (state) => state.count, // 返回要监听的值
  (newCount, oldCount) => {
    console.log(`Count 从 ${oldCount} 变为 ${newCount}`);
  }
);

// 取消监听
unwatch();

高级用法:监听派生数据(通过 getter)

store.watch(
  (state, getters) => getters.filteredList, // 监听 getter
  (newList) => {
    console.log('过滤后的列表更新:', newList);
  }
);

五、组合式 API 监听(Vue 3)

场景:在 Composition API 中响应式监听 Vuex 状态
示例

import { computed, watch } from 'vue';
import { useStore } from 'vuex';

export default {
  setup() {
    const store = useStore();

    // 计算属性映射
    const count = computed(() => store.state.count);

    // 监听特定状态
    watch(
      () => store.state.user,
      (newUser) => {
        console.log('用户信息变更:', newUser);
      },
      { deep: true }
    );

    return { count };
  }
};

🔥 最佳实践总结

方法适用场景是否全局能否取消监听
计算属性模板渲染 / 数据派生组件级自动
watch 选项组件内副作用逻辑组件级自动
store.subscribe全局监听所有 mutations全局手动取消
store.watch精准监听特定 state/getter全局手动取消
Composition APIVue 3 项目中的响应式监听组件级自动

⚠️ 常见陷阱与解决方案

  1. 对象/数组变化未被检测
    问题:直接修改对象属性 (state.obj.key = newVal) 或数组元素 (state.arr[0] = item) 不会触发响应
    解决

    • 使用 Vue.set(state.obj, 'key', newVal)
    • 返回新对象:state.obj = { ...state.obj, key: newVal }
  2. 异步监听中的过期状态
    问题:在异步回调中访问的 state 可能已过期

    actions: {
      async fetchData({ commit }) {
        const oldCount = this.state.count; // ❌ 可能过期
        const data = await api.fetch();
        // 正确:在 commit 时传递所需数据
        commit('SET_DATA', { data, oldCount }); 
      }
    }
    
  3. 性能优化

    • 避免深度监听大型对象(使用特定路径代替 deep: true
    • 及时清理无用的监听器(如组件销毁时调用 unwatch()

🌰 实战案例:购物车数量监听

// 组件内监听购物车商品数量
export default {
  computed: {
    cartItemCount() {
      return this.$store.getters.cartItemCount;
    }
  },
  watch: {
    cartItemCount(newCount) {
      // 显示浮动提示
      this.$notify({
        message: `购物车商品数量已更新:${newCount} 件`,
        type: 'success'
      });
    }
  }
}

通过合理选择监听方式,可以高效管理 Vuex 状态变化,构建响应式且可维护的 Vue 应用!

vuex使用actions时不支持多参数传递怎么办?

原理:将多个参数合并成一个对象传递

// 组件中调用
this.$store.dispatch('fetchData', {
  id: 123,
  page: 2,
  filter: { name: 'vue' }
});

// Action 接收
actions: {
  fetchData({ commit }, payload) {
    const { id, page, filter } = payload;
    console.log(id, page, filter); // 123 2 {name: 'vue'}
  }
}

vuex中context是什么?

在 Vuex 里,context 是一个传入到 action 函数中的参数对象,它是一个上下文对象,它在处理异步操作和修改状态时发挥着重要作用。下面为你详细介绍其相关信息。

作用

在 Vuex 中,mutations 用于同步修改状态,而 actions 用于处理异步操作。context 提供了一系列属性和方法,让 actions 可以和 store 进行交互,从而间接地修改状态。

属性和方法

context 对象具有以下常用的属性和方法:

  • state:可访问当前模块的状态。若在根模块,访问的就是根状态;若在子模块,访问的就是子模块状态。
  • getters:获取当前模块的 getters
  • commit:用来提交 mutations,是修改状态的唯一途径。通过它可以触发 mutations 中的方法来改变 state
  • dispatch:用于分发 actions,可以在一个 action 中调用其他 action,适合处理多个异步操作的组合。
  • rootState:获取根模块的状态,无论当前处于哪个子模块。
  • rootGetters:获取根模块的 getters

解构赋值简化代码

为了让代码更加简洁易读,可使用解构赋值从 context 中提取所需的属性和方法,示例如下:

actions: {
  incrementAsync({ commit }) {
    setTimeout(() => {
      commit('increment');
    }, 1000);
  }
}

context 的设计意义

  1. 模块隔离性

    • 在命名空间模块中,所有操作默认限定在本模块内,避免命名冲突。
  2. 全局访问能力

    • 通过 rootState 和 rootGetters,可在模块内安全访问全局状态。
  3. 灵活通信机制

    • 通过 { root: true } 选项,实现跨模块的 Action 和 Mutation 调用。

Vuex中状态是对象时,使用时要注意什么?

因为对象是引用类型,复制后改变属性还是会影响原始数据,这样会改变state里面的状态,是不允许,所以先用深度克隆复制对象,再修改。

Vuex中要从state派生一些状态出来,且多个组件使用它,该怎么做?

使用getter属性,相当Vue中的计算属性computed,只有原状态改变派生状态才会改变。 getter接收两个参数,第一个是state,第二个是getters(可以用来访问其他getter)。

const store = new Vuex.Store({
    state: {
        price: 10,
        number: 10,
        discount: 0.7,
    },
    getters: {
        total: state => {
            return state.price * state.number
        },
        discountTotal: (state, getters) => {
            return state.discount * getters.total
        }
    },
});

怎么通过getter来实现在组件内可以通过特定条件来获取state的状态?

通过让getter返回一个函数,来实现给getter传参。然后通过参数来进行判断从而获取state中满足要求的状态。

const store = new Vuex.Store({
    state: {
        todos: [
            { id: 1, text: '...', done: true },
            { id: 2, text: '...', done: false }
        ]
    },
    getters: {
        getTodoById: (state) => (id) =>{
            return state.todos.find(todo => todo.id === id)
        }
    },
});

然后在组件中可以用计算属性computed通过this.$store.getters.getTodoById(2)这样来访问这些派生转态。

computed: {
    getTodoById() {
        return this.$store.getters.getTodoById
    },
}
mounted(){
    console.log(this.getTodoById(2).done)//false
}

怎么在组件中批量给Vuex的getter属性取别名并使用

使用mapGetters辅助函数, 利用对象展开运算符将getter混入computed 对象中

import {mapGetters} from 'vuex'
export default{
    computed:{
        ...mapGetters({
            myTotal:'total',
            myDiscountTotal:'discountTotal',
        })
    }
}

在组件中多次提交同一个mutation,怎么写使用更方便

使用mapMutations辅助函数,在组件中这么使用

import { mapMutations } from 'vuex'
methods:{
    ...mapMutations({
        setNumber:'SET_NUMBER',
    })
}

然后调用this.setNumber(10)相当调用this.$store.commit('SET_NUMBER',10)

Vuex中action通常是异步的,那么如何知道action什么时候结束呢?

在action函数中返回Promise,然后再提交时候用then处理

actions:{
    SET_NUMBER_A({commit},data){
        return new Promise((resolve,reject) =>{
            setTimeout(() =>{
                commit('SET_NUMBER',10);
                resolve();
            },2000)
        })
    }
}
this.$store.dispatch('SET_NUMBER_A').then(() => {
  // ...
})

Vuex中有两个action,分别是actionA和actionB,其内都是异步操作,在actionB要提交actionA,需在actionA处理结束再处理其它操作,怎么实现?

利用ES6的asyncawait来实现。

actions:{
    async actionA({commit}){
        //...
    },
    async actionB({dispatch}){//对context进行结构 出 dispatch
        await dispatch ('actionA')//等待actionA完成
        // ... 
    }
}

在模块中getter和mutation和action中怎么访问全局的state和getter?

  • 在getter中可以通过第三个参数rootState访问到全局的state,可以通过第四个参数rootGetters访问到全局的getter。
  • 在mutation中不可以访问全局的state和getter,只能访问到局部的state。
  • 在action中第一个参数context中的context.rootState访问到全局的state,context.rootGetters访问到全局的getter。

Vuex插件有用过吗?怎么用简单介绍一下?你有写过vuex中store的插件吗(自定义插件)?

Vuex 插件(Plugins)是用于扩展 Vuex 功能的工具,通过插件可以实现 状态持久化、日志记录、数据同步 等能力。以下是常见插件的使用方法和自定义插件的实现思路:

一、常用 Vuex 插件示例

1. 状态持久化插件:vuex-persistedstate

作用:将 Vuex 状态自动保存到 localStoragesessionStorage,解决页面刷新后数据丢失问题。

使用步骤

  1. 安装插件

    npm install vuex-persistedstate
    
  2. 在 Vuex Store 中配置

    import createPersistedState from 'vuex-persistedstate';
    
    export default new Vuex.Store({
      state: {
        user: null,
        cart: []
      },
      plugins: [
        createPersistedState({
          storage: window.sessionStorage, // 默认用 localStorage
          paths: ['user'] // 仅持久化 user 字段
        })
      ]
    });
    
2. 日志插件:vuex-logger

作用:在控制台输出状态变更日志,方便调试。

使用步骤

  1. 安装插件

    npm install vuex-logger
    
  2. 在 Vuex Store 中配置

    import createLogger from 'vuex-logger';
    
    const logger = createLogger({
      collapsed: true // 折叠日志条目
    });
    
    export default new Vuex.Store({
      plugins: [logger]
    });
    
3. 路由同步插件:vuex-router-sync

作用:将 Vue Router 的路由状态同步到 Vuex Store。

使用步骤

  1. 安装插件

    npm install vuex-router-sync
    
  2. 同步路由状态

    import { sync } from 'vuex-router-sync';
    import store from './store';
    import router from './router';
    
    // 将路由状态同步到 store.state.route
    sync(store, router);
    

二、自定义 Vuex 插件

Vuex 插件本质是一个函数,通过监听 Store 初始化状态变更 实现自定义逻辑。

示例:实现一个简易日志插件
const myLoggerPlugin = (store) => {
  // 初始化时输出日志
  console.log('Store initialized:', store.state);

  // 监听所有 mutations
  store.subscribe((mutation, state) => {
    console.log(`Mutation: ${mutation.type}`, {
      payload: mutation.payload,
      state: state
    });
  });

  // 监听所有 actions
  store.subscribeAction((action, state) => {
    console.log(`Action: ${action.type}`, action.payload);
  });
};

// 在 Store 中加载插件
export default new Vuex.Store({
  plugins: [myLoggerPlugin]
});

三、插件核心机制

  1. store.subscribe
    监听所有 mutations 的提交,在每次 mutation 完成后触发。

    store.subscribe((mutation, state) => {
      // mutation 格式:{ type: 'mutationName', payload: ... }
    });
    
  2. store.subscribeAction
    监听所有 actions 的提交,支持在 action 执行前或执行后触发。

    store.subscribeAction({
      before: (action, state) => { /* action 执行前 */ },
      after: (action, state) => { /* action 执行后 */ }
    });
    
  3. replaceState
    动态替换整个 Store 的状态(常用于初始化或插件中恢复数据)。

    store.replaceState(newState);
    

四、插件适用场景

场景推荐插件或方法
持久化状态vuex-persistedstate
调试状态变更vuex-logger 或自定义日志
路由状态同步vuex-router-sync
接口请求统一管理自定义插件(拦截请求/响应)
状态变更历史记录自定义插件(实现时间旅行)

五、注意事项

  1. 性能优化:避免在插件中频繁操作大数据(如全量存储到 localStorage)。
  2. 安全敏感数据:避免明文存储 token 等敏感信息,需结合加密。
  3. 插件加载顺序:插件按数组顺序执行,需注意依赖关系。

通过插件机制,Vuex 可以灵活扩展功能,快速满足复杂业务需求。

在Vuex插件中怎么监听组件中提交mutation和action?

  • 用Vuex.Store的实例方法subscribe监听组件中提交mutation
  • 用Vuex.Store的实例方法subscribeAction监听组件中提交action 在store/plugin.js文件中写入
export default function createPlugin(param) {
    return store => {
        store.subscribe((mutation, state) => {
            console.log(mutation.type)//是那个mutation
            console.log(mutation.payload)
            console.log(state)
        })
        // store.subscribeAction((action, state) => {
        //     console.log(action.type)//是那个action
        //     console.log(action.payload)//提交action的参数
        // })
        store.subscribeAction({
            before: (action, state) => {//提交action之前
                console.log(`before action ${action.type}`)
            },
            after: (action, state) => {//提交action之后
                console.log(`after action ${action.type}`)
            }
        })
    }
}

然后在store/index.js文件中写入

import createPlugin from './plugin.js'
const myPlugin = createPlugin()
const store = new Vuex.Store({
  // ...
  plugins: [myPlugin]
})

在v-model上怎么用Vuex中state的值?

需要通过computed计算属性来转换。

<input v-model="message">
// ...
computed: {
    message: {
        get () {
            return this.$store.state.message
        },
        set (value) {
            this.$store.commit('updateMessage', value)
        }
    }
}

Vuex的严格模式是什么,有什么作用,怎么开启?

在严格模式下,无论何时发生了状态变更且不是由 mutation函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。

在Vuex.Store 构造器选项中开启,如下

const store = new Vuex.Store({
    strict:true,
})

页面刷新后vuex的state数据丢失怎么解决?

就是放在localStorage 或者就是sessionStorage ,或者借用辅助插vuex-persistedstate

通常情况state里的初始数据是空,通过mutation或者action的方法获取实际数据后存放在state中。这些方法往往是在某个组件(组件A)的生命周期或者事件中调用。如果在刷新页面的时候这些方法没有被调用(例如此时页面中没有组件A,或组件A的对应事件没有被触发),那么就没有获取实际数据,state的数据就是初始的空。

对症下药,就是要确保刷新页面以后调用对应的获取数据方法。 最万金油的解决是在App.vue的mounted生命周期中去调用这些方法。不管在哪个路由下刷新页面,总会执行。

解决方案

  1. 使用浏览器存储(如localStoragesessionStorage
    将Vuex的状态数据同步到浏览器本地存储中,并在页面加载时恢复数据。
  2. 推荐使用插件vuex-persistedstate
    该插件自动将Vuex状态保存到选择的存储中(默认localStorage),减少手动操作。

为了解决页面刷新后Vuex的state数据丢失问题,可以通过以下步骤实现数据的持久化存储:

实现步骤

方法1:使用vuex-persistedstate插件
  1. 安装插件

    npm install vuex-persistedstate
    
  2. 在Vuex Store中配置插件

    import Vue from 'vue';
    import Vuex from 'vuex';
    import createPersistedState from 'vuex-persistedstate';
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      state: {
        user: null,
        cart: [],
      },
      mutations: {
        setUser(state, user) {
          state.user = user;
        },
      },
      plugins: [createPersistedState()]
    });
    

上述代码中,通过 createPersistedState() 创建一个插件实例,并将其添加到 store 的 plugins 数组中,这样 vuex-persistedstate 会自动将 state 数据存储到 localStorage 中,并在页面加载时恢复数据。

方法2:手动实现持久化
  1. 初始化时从localStorage读取数据
    在创建Vuex Store时,检查本地存储并合并状态:

    const store = new Vuex.Store({
      state: {
        user: JSON.parse(localStorage.getItem('user')) || null,
      },
      mutations: {
        setUser(state, user) {
          state.user = user;
          localStorage.setItem('user', JSON.stringify(user)); // 每次更新后保存
        },
        logout(state) {
          state.user = null;
          localStorage.removeItem('user'); // 退出时清除
        }
      }
    });
    
  2. 监听Vuex变化自动保存(可选)
    通过store.subscribe监听所有mutations:

    在插件中采用store.subscribe方法就可以监测到该store下所有的mutation调用。每当我们调用mutation中的方法时就会进入store.subscribe方法,方法中的第一个参数mutation是当前调用的mutation内容,type是调用方法的名字,payload是方法的参数;第二个参数是当前state的内容。

    store.subscribe((mutation, state) => {
    //mutation {type,payload}
      localStorage.setItem('vuex_state', JSON.stringify(state));
    });
    
    // 初始化时加载
    const savedState = localStorage.getItem('vuex_state');
    if (savedState) {
      store.replaceState(JSON.parse(savedState));
    }
    

注意事项

  • 安全敏感数据:避免在本地存储敏感信息(如token),如需存储,应结合加密或使用HttpOnly Cookie。
  • 性能优化:频繁保存大数据可能影响性能,可结合防抖(debounce)或只持久化关键数据。
  • SSR兼容性:服务端渲染(如Nuxt.js)需使用cookie或适配服务端存储。

总结

  • 简单场景:推荐使用vuex-persistedstate插件,快速实现持久化。
  • 定制需求:手动操作localStorage,灵活控制存储逻辑。
  • 安全存储:敏感信息应结合后端加密或安全措施。

通过上述方法,Vuex的状态在页面刷新后仍能保留,提升用户体验。

你觉得vuex有什么缺点?

1. 模板代码冗余,不适合小型项目

问题
Vuex 要求通过 statemutationsactionsgetters 分层管理状态,即使是简单的状态变更,也需要编写重复的代码(例如定义 mutation 和 action),增加了开发成本。

解决方案

  • 使用 Pinia:Vue 官方推荐的新一代状态管理库,简化了 API(无需 mutations),直接通过 actions 修改状态,代码更简洁。
  • Composition API:对于小型项目,可以直接用 reactive 或 ref 管理状态,避免引入 Vuex。

2. 学习曲线陡峭

问题
Vuex 的概念较多(如 mutations 的同步性、actions 的异步性、模块化等),新手需要花费时间理解其设计哲学和最佳实践。

3. 对 TypeScript 支持有限

问题
Vuex 4 虽然支持 TypeScript,但类型推断和类型安全仍不够直观,尤其是在模块化和动态场景中需要手动声明类型。

使用vuex的优势是什么?

使用 Vuex 的优势主要体现在对 复杂应用状态管理 的规范化支持上,尤其在多人协作的中大型 Vue 项目中,它能显著提升代码的可维护性和可预测性。以下是 Vuex 的核心优势及适用场景:

1. 集中式状态管理

优势

  • 单一数据源:所有组件的共享状态(如用户登录信息、全局配置)集中存储在 Vuex Store 中,避免数据分散和重复,降低维护成本。
  • 数据一致性:任何组件都通过统一接口(state/mutations/actions)操作数据,确保状态变更的透明性和可追溯性。

适用场景

  • 多个组件依赖同一份数据(如购物车、用户权限)。
  • 需要跨层级组件通信(如祖先组件与深层嵌套子组件共享状态)。

2. 严格的数据变更流程

优势

  • 强制通过 mutations 修改状态:确保状态变更的同步性和原子性,避免竞态条件。
  • 异步操作通过 actions 处理:将业务逻辑(如 API 请求)与状态变更分离,提升代码可测试性。

示例流程

graph LR
  A[组件] -->|dispatch| B[Action]
  B -->|异步操作| C[API 请求]
  B -->|commit| D[Mutation]
  D -->|修改| E[State]
  E -->|响应式更新| A

适用场景

  • 需要严格跟踪状态变更来源(如日志记录、调试)。
  • 异步操作与状态变更解耦(如请求失败时回滚状态)。

3. 强大的调试工具支持

优势

  • Vue Devtools 集成:实时查看状态变化、回溯历史记录(Time Travel Debugging),快速定位问题。
  • 状态快照与重放:可导出/导入 Store 快照,方便测试和重现 Bug。

4. 模块化与可扩展性

优势

  • 模块化拆分:通过 modules 将大型 Store 拆分为独立模块,支持命名空间隔离,避免命名冲突。
  • 插件机制:可自定义插件(如日志插件、持久化插件)扩展 Vuex 功能。

模块化示例

// user.module.js
export default {
  namespaced: true,
  state: () => ({ user: null }),
  mutations: { setUser(state, user) { state.user = user; } },
  actions: { fetchUser({ commit }) { /* API 请求 */ } }
};

// store.js
import userModule from './user.module';
const store = new Vuex.Store({
  modules: { user: userModule }
});

适用场景

  • 大型项目需要分团队维护不同业务模块。
  • 需要动态注册/卸载模块(如微前端架构)。

5. 社区与生态成熟

优势

  • 官方维护:作为 Vue 生态的官方库,长期支持稳定,文档齐全。
  • 丰富插件:如 vuex-persistedstate(状态持久化)、vuex-router-sync(路由同步)等,覆盖常见需求。

6. 与 Vue 深度集成

优势

  • 响应式状态:Vuex Store 的状态变更自动触发组件更新,无需手动监听。
  • 语法糖支持mapStatemapActions 等工具函数简化组件与 Store 的交互。

组件中使用示例

<template>
  <div>{{ username }}</div>
  <button @click="fetchUser">获取用户</button>
</template>

<script>
import { mapState, mapActions } from 'vuex';

export default {
  computed: {
    ...mapState('user', ['user']),
    username() { return this.user?.name; }
  },
  methods: {
    ...mapActions('user', ['fetchUser'])
  }
};
</script>

何时选择 Vuex?

  1. 中大型项目:需要多人协作、长期维护,且状态逻辑复杂。
  2. 严格的数据流规范:团队要求状态变更可追踪、可调试。
  3. 遗留项目维护:已有基于 Vuex 的代码库,无需重构迁移。

替代方案对比

场景推荐工具理由
新项目(Vue 3)Pinia更简洁的 API,更好的 TypeScript 支持。
小型应用/简单状态共享Composition API轻量级,无需引入额外库。
需要极致性能优化原生响应式 API减少抽象层开销。

总结

Vuex 的核心价值在于 为复杂应用提供可预测的状态管理架构。尽管其学习成本和模板代码在简单场景下显得冗余,但在需要严格规范、团队协作和长期维护的项目中,它依然是 Vue 生态中值得信赖的选择。对于新项目,可优先评估 Pinia 是否更符合需求。

怎么使用mapState,mapGetters,mapActions和mapMutations这些函数来绑定带命名空间的模块?

在组件中,通过 路径前缀 或 createNamespacedHelpers 绑定模块。

方法 1:手动指定命名空间路径

直接在辅助函数中传入模块路径字符串(如 'user')。

export default {
  computed: {
    // 映射 user 模块的 state 和 getters
    ...mapState('user', ['name', 'age']),
    ...mapGetters('user', ['isAdult'])
  },
  methods: {
    // 映射 user 模块的 mutations 和 actions
    ...mapMutations('user', {
      setAge: 'SET_AGE' // 别名映射
    }),
    ...mapActions('user', ['fetchProfile'])
  }
};
方法 2:使用 createNamespacedHelpers 简化

通过 createNamespacedHelpers 生成已绑定命名空间的辅助函数。

<script>
import { createNamespacedHelpers } from 'vuex';

// 创建绑定到 user 模块的辅助函数
const { mapState, mapGetters, mapMutations, mapActions } = 
  createNamespacedHelpers('user');

export default {
  computed: {
    // 直接使用已绑定命名空间的辅助函数
    ...mapState(['name', 'age']),
    ...mapGetters(['isAdult'])
  },
  methods: {
    ...mapMutations({
      setAge: 'SET_AGE'
    }),
    ...mapActions(['fetchProfile'])
  }
};
</script>
注意事项
  1. 路径一致性:确保模块路径与注册时的路径完全一致(区分大小写)。
  2. 模块未启用命名空间:如果模块未设置 namespaced: true,直接使用 mapState 等函数会映射到全局 Store。
  3. 代码可读性:对复杂项目,建议使用 createNamespacedHelpers 减少重复代码。

VueX中的用户信息是什么时候放进去的?什么时候会使用?

实例dispatch派发acitons然后从后端获取到数据后调用mutations对state中的用户信息进行更新。一般回用于用户路由权限,和判断一些功能的使用权限,展示用户信息

vuex储存的实例化是存放在哪的

储存在vue根根实例,因为这样才能保证从全局能调用到,保证多个视图共享同一个数据

vuex与pinia之间的区别

Vuex 和 Pinia 是 Vue.js 生态中两个主要的状态管理库,以下是它们的核心区别:

1. pinia简化了概念,废弃了 mutations, 同步和异步操作统一在 actions 中处理

2.TypeScript 支持

  • Vuex

    • 早期对 TypeScript 支持较弱(需额外类型声明)。
    • Vuex 4 对 TS 有所改进,但仍需较多配置。
  • Pinia

    • 完全基于 TypeScript 设计,提供自动类型推断。
    • 定义 Store 时可直接获得类型提示,无需额外配置。

3. 模块化设计

  • Vuex
    使用 嵌套模块(modules)组织代码,通过命名空间区分模块。

    • 大型项目中模块过多时,可能产生命名冲突或复杂度上升。
  • Pinia
    采用 扁平化模块,每个 Store 独立定义,通过文件组织逻辑。

    • 支持 Store 间的交叉组合,更灵活。
    • 天然支持按需加载,无需动态注册模块。

4. 体积与性能

  • Vuex
    体积较大(约 10KB+),功能全面但可能包含未使用的代码。

  • Pinia
    更轻量(约 5KB),按需设计,适合对体积敏感的项目。

5. 开发体验

  • Vuex

    • 严格的流程控制(如必须通过 mutations 修改状态),适合大型项目规范代码。
    • 学习曲线较陡,需理解多个概念。
  • Pinia

    • 更自由的编码风格,减少概念负担。
    • Devtools 支持完善,可追踪状态变化和 Actions 调用。

6. 兼容性

  • Vuex

    • Vuex 3 用于 Vue 2,Vuex 4 支持 Vue 3。
    • 未来 Vuex 5 计划简化 API(类似 Pinia)。
  • Pinia

    • 同时支持 Vue 2 和 Vue 3,推荐作为新项目的默认选择。
    • 被官方列为 Vue 3 的推荐状态管理库。

总结:如何选择?

  • Vuex:适合已使用 Vuex 的大型项目或需要严格流程控制的场景。
  • Pinia:新项目首选,尤其是 Vue 3 + TypeScript 项目,追求简洁、灵活和轻量。

Pinia 可视为 Vuex 的现代化替代品,其设计吸取了 Vuex 的经验,更贴合 Vue 3 的开发模式。

为什么要使用vuex|pinia状态管理,而不建一个全局变量

在 Vue 开发中,使用 Vuex 或 Pinia 这样的状态管理库与直接使用全局变量看似类似(都是共享数据),但它们在**响应式、可预测性、模块化与代码组织、调试能力,**等方面有本质区别。以下从 7 个关键角度对比说明:

1. 响应式数据流

  • 全局变量
    直接修改全局变量不会触发 Vue 的响应式更新,需要手动调用 Vue.set 或使用 reactive/ref 包裹对象,容易遗漏导致视图不更新。

    // 全局变量(非响应式)
    window.globalState = { count: 0 };
    // 修改后视图不会自动更新!
    window.globalState.count++;
    
  • Vuex/Pinia
    内部深度集成 Vue 的响应式系统,状态变更自动触发视图更新。

    // Pinia Store
    useStore().count++; // 自动触发响应式更新
    

2. 数据流可预测性

  • 全局变量
    任何组件、方法、甚至异步回调都可以直接修改全局变量,导致:

    • 数据流向混乱,难以追踪变更来源。
    • 出现 Bug 时调试困难(需全局搜索哪里修改了变量)。
  • Vuex/Pinia
    通过明确的规则管理状态变更:

    • Vuex:必须通过 mutations(同步)或 actions(异步)修改状态。
    • Pinia:统一通过 actions 修改状态(同步/异步均可)。
    // 明确的修改入口(Pinia)
    const store = useStore();
    store.increment(); // 只能通过 action 修改
    

3. 调试能力

  • 全局变量
    无内置调试工具支持,需手动添加 console.log 或断点,大型项目中效率极低。

  • Vuex/Pinia
    Vue Devtools 深度集成,提供:

    • 时间旅行调试(Time Travel)
    • 状态变更记录(State Diff)
    • Action/Mutation 调用追踪

4. 模块化与代码组织

  • 全局变量
    所有状态堆砌在全局,容易导致命名冲突,难以维护。

    // 全局变量臃肿
    window.userData = { ... };
    window.cartData = { ... };
    window.settings = { ... };
    
  • Vuex/Pinia
    通过模块化(Vuex)或独立 Store(Pinia)组织代码:

    // Pinia 模块化示例
    // stores/user.js
    export const useUserStore = defineStore('user', {
      state: () => ({ name: 'John' }),
      actions: { /* ... */ }
    });
    
    // stores/cart.js
    export const useCartStore = defineStore('cart', {
      state: () => ({ items: [] }),
      actions: { /* ... */ }
    });
    

5. TypeScript 支持

  • 全局变量
    需要手动维护类型定义,易出错:

    // global.d.ts
    declare global {
      interface Window {
        globalState: { count?: number }; // 类型容易过时
      }
    }
    
  • Pinia
    天生支持 TypeScript,自动推断类型:

    const store = useStore();
    store.count++; // 类型安全(若 count 不存在会报错)
    

6. 服务端渲染 (SSR) 支持

  • 全局变量
    在服务端渲染时,全局变量会污染 Node.js 的全局作用域,导致内存泄漏或数据冲突。

  • Vuex/Pinia
    提供 SSR 友好设计,支持在服务端和客户端之间安全地同步状态。

7. 性能优化

  • 全局变量
    频繁修改全局状态可能触发不必要的组件重新渲染(缺乏细粒度控制)。

  • Vuex/Pinia
    基于 Vue 的响应式系统,自动优化渲染:

    • 只有依赖特定状态的组件才会更新。
    • 支持计算属性(getters)缓存和按需更新。

何时可以使用全局变量?

仅适合极其简单的场景,例如:

  • 跨组件共享静态常量(如配置信息)。
  • 小型原型项目(快速验证想法)。

总结:为什么需要状态管理库?

场景全局变量Vuex/Pinia
响应式更新❌ 手动✅ 自动
数据流可追溯性❌ 混乱✅ 明确
调试能力❌ 困难✅ 强大工具链
大型项目维护性❌ 差✅ 模块化
TypeScript 支持❌ 繁琐✅ 开箱即用
SSR 支持❌ 危险✅ 安全

结论:Vuex/Pinia 通过约束数据流、提供响应式保证和强大工具链,解决了全局变量在复杂应用中的根本缺陷,是构建可维护、可扩展 Vue 应用的最佳实践。

vuex 与 localStorage 的区别

vuex(状态管理库
localStorage(浏览器本地存储 API

  1. 存储位置不一样

    • vuex存储在内存中,刷新的话就会清除。
    • localStorage存储在硬盘中,除非手动清除,否则一直存在。
  2. 响应式

    • vuex存储具有响应式,localStorage没有
  3. 安全

    • 内存中(相对安全), 硬盘中(易被 XSS 攻击读取)

pinia 有什么缺点?

1. 对超大型项目的模块化要求更高

  • 问题描述
    Pinia 采用 扁平化 Store 设计,每个 Store 独立存在,不提供类似 Vuex 的嵌套模块机制。在超大型项目中,若缺乏规范,可能导致 Store 文件分散,依赖关系复杂。

2. 生态系统相对较新,插件较少

  • 问题描述
    相比 Vuex,Pinia 的第三方插件生态尚不成熟。虽然核心功能完善,但针对特定需求(如复杂持久化、状态加密)的插件选择有限。

3. 迁移 Vuex 项目存在适应成本

  • 问题描述
    从 Vuex 迁移到 Pinia 需重构代码逻辑(如移除 mutations、合并 actions),对于复杂项目可能耗时较长。

Vuex 的时间旅行调试是什么?

Vue Devtools 可以查看和回放 State 的变化历史,便于调试。

Vuex 的 时间旅行调试(Time Travel Debugging) 是一种通过 Vue DevTools 提供的强大调试功能,允许开发者 回溯和重放应用状态的变化历史,直观地观察状态如何随时间演变。它特别适用于调试复杂的状态管理问题。

核心机制

  1. 状态快照
    Vuex 每次提交(commit)一个 mutation 时,会记录当前状态的快照。
  2. 历史记录
    所有 mutation 的执行顺序和对应的状态快照会被保存为一个“历史记录链”。
  3. 自由跳转
    开发者可通过 DevTools 选择任意历史节点,将应用状态 实时回滚 到该时刻的状态,如同“时间旅行”。

操作演示(通过 Vue DevTools)

  1. 打开 DevTools
    在浏览器中打开 Vue DevTools,切换到 Vuex 选项卡。
  2. 查看历史记录
    • 所有已提交的 mutation 按顺序列出,包含名称、时间和参数。
  3. 时间旅行
    • 点击任意一条 mutation 记录,应用状态会 立即回退 到该 mutation 执行后的状态。
    • 组件界面也会同步更新,仿佛回到了那个时间点。
  4. 重放操作
    • 可重新触发后续的 mutation,观察状态如何再次演变。

实际应用场景

1. 调试状态突变问题
  • 问题:某个操作导致状态异常,但不确定是哪一步 mutation 引发的。
  • 解决:逐步回退历史记录,定位到具体的 mutation,观察状态变化前后的差异。
2. 复现用户操作路径
  • 问题:用户报告某个 Bug,但无法在本地复现。
  • 解决:记录用户操作序列,通过时间旅行在本地重放,精准复现问题。
3. 验证状态恢复逻辑
  • 问题:撤销/重做功能是否正常?
  • 解决:手动回退到历史状态,检查界面和功能是否按预期恢复。

代码示例

假设有一个计数器 Store:

// Vuex Store
const store = new Vuex.Store({
  state: { count: 0 },
  mutations: {
    increment(state) {
      state.count++;
    },
    reset(state) {
      state.count = 0;
    }
  }
});
  1. 连续执行 increment 三次,状态变为 count: 3
  2. 执行 reset,状态变为 count: 0

时间旅行调试操作

  • 在 DevTools 中点击 reset 之前的记录,状态回退到 count: 3
  • 界面显示计数器的值为 3,仿佛 reset 从未执行过。

优势与限制

优势限制
直观追溯状态变化根源仅记录通过 mutation 的变更
无需手动添加 console.log大型项目历史记录可能占用较多内存
支持实时状态回滚和重放无法直接修改历史记录(只读)

总结

Vuex 的时间旅行调试通过 状态快照历史回溯,极大提升了复杂状态流问题的调试效率。它让开发者能够:

  1. 精准定位问题 mutation。
  2. 直观理解状态变化的全流程。
  3. 快速验证修复方案。

对于需要精细管理状态的 Vue 应用,这是 Vuex 生态中不可替代的调试利器。

Vuex 和 Pinia 如何选择?

根据项目规模和需求选择,Vuex 适合中大型项目

Pinia 适合中小型项目,尤其是 Vue 3 项目

Pinia 为什么去掉了 mutations?

Pinia 认为 mutations 只是 actions 的一个 额外步骤,没必要单独存在。因此 直接使用 actions 处理状态修改,简化代码。

Vuex 和 Pinia 如何管理多个 store?

Vuex:
手动使用 modules

const store = new Vuex.Store({
  modules: { user: userModule, cart: cartModule },
});

Pinia:
每个 store 自动模块化

export const useUserStore = defineStore('user', { state: () => ({ name: '' }) });
export const useCartStore = defineStore('cart', { state: () => ({ items: [] }) });

Pinia 如何持久化存储?

使用 pinia-plugin-persistedstate

import { createPinia } from 'pinia';
import persist from 'pinia-plugin-persistedstate';

const pinia = createPinia();
pinia.use(persist);

Pinia 是否支持 Vue DevTools?

是的,Pinia 原生支持 Vue DevTools,相比 Vuex 更直观,支持时间旅行调试。

Vuex的核心源码解析:

详细介绍文章:
juejin.cn/post/684490…

目标:

  • 作为插件一定有install方法,可以在其中进行混入,当Vue实例化后挂载前拿到给其配置的store实例,把store放在原型上,以便全局可用;
  • 持有基本的state,保存实例化router时配置的mutations,actions对象;
  • 实现commit及dispatch等方法,可对state进行一定的修改

以下是基于 Vuex 源码的详细分析,结合其核心机制与实现原理,涵盖安装过程、Store 架构、模块系统、响应式实现等关键部分:

一、Vuex 的安装机制

Vuex 通过 Vue.use(Vuex) 安装,其核心是通过 install 方法将 Store 注入所有 Vue 组件。实现步骤如下:

  1. 避免重复安装:通过全局变量 Vue 检测是否已安装,防止重复调用。
  2. 注入 Store:利用 Vue 的 mixin 机制,在 Vue 2.x 的 beforeCreate 生命周期钩子中执行 vuexInit 方法,将 store 实例挂载到组件的 $store 属性上。
    function vuexInit() {
      if (this.$options.store) {
        this.$store = this.$options.store;
      } else if (this.$options.parent?.$store) {
        this.$store = this.$options.parent.$store; // 子组件继承父组件的 store
      }
    }
    
  3. 版本适配:针对 Vue 1.x,通过重写 _init 方法实现兼容。

二、Store 的构造函数

Store 是 Vuex 的核心类,其构造函数主要完成以下任务:

  1. 环境校验:确保已安装 Vue 且支持 Promise(用于异步 Action)。
  2. 初始化内部状态
    • _actions_mutations:存储用户定义的 Action 和 Mutation 函数。
    • _wrappedGetters:存储包装后的 Getter 函数。
    • _modules:通过 ModuleCollection 处理模块树。
  3. 绑定上下文:将 dispatchcommit 方法的 this 绑定到 Store 实例,防止在组件中调用时丢失上下文。
    this.dispatch = function boundDispatch(type, payload) {
      return dispatch.call(store, type, payload);
    };
    

三、模块系统与状态树

Vuex 通过模块(Module)组织复杂的状态树,核心类包括 ModuleCollectionModule

  1. 模块注册
    • ModuleCollection 递归解析用户传入的 modules 配置,构建模块树。
    • 每个 Module 实例封装了模块的 statemutationsactionsgetters,并提供 forEachChild 等方法遍历子模块。
  2. 命名空间:通过 getNamespace 方法生成模块的命名空间路径(如 user/profile),避免命名冲突。
  3. 状态合并:子模块的 state 通过 Vue.set 动态挂载到父模块的 state 上,实现响应式更新。

四、响应式状态与 Getter 实现

Vuex 利用 Vue 的响应式系统实现状态变化自动触发视图更新:

  1. resetStoreVM
    • 创建一个 Vue 实例 _vm,将 state 存入其 data$$state 属性,使状态变为响应式。
    • getters 转换为 _vm 的计算属性,依赖 state 自动更新。
    store._vm = new Vue({
      data: { $$state: state },
      computed: wrappedGetters
    });
    
  2. 严格模式:通过 _committing 标志位检测是否通过 Mutation 修改状态,非法修改会抛出错误。

五、核心 API 的实现

  1. commit
    • 通过 _mutations 查找对应的 Mutation 函数,执行时开启 _committing 标志位。
    • 支持对象风格调用({ type, payload })。
    commit(type, payload) {
      const entry = this._mutations[type];
      this._withCommit(() => entry.forEach(fn => fn(payload)));
    }
    
  2. dispatch
    • 处理异步操作,返回 Promise 链以支持链式调用。
    • 通过 _actions 查找 Action 函数,并传入 { commit, state } 上下文。
  3. 订阅机制:通过 _subscribers 存储订阅函数,每次 Mutation 执行后触发通知。

六、插件系统与开发工具

  1. 插件机制:插件接收 Store 实例,可监听 Mutation(如日志插件)或提交额外的 Mutation。
    plugins.forEach(plugin => plugin(this));
    
  2. DevTools 集成:通过 devtoolPlugin 将状态变化同步到 Vue DevTools,支持时间旅行调试。

七、流程图解

Component
   │ dispatch(action)
   ▼
Store._actions → 执行异步逻辑 → commit(mutation)
                           │
                           ▼
Store._mutations → 修改 State → 触发 Vue 响应式更新 → 组件重新渲染

总结

Vuex 的设计巧妙结合了 Vue 的响应式系统与模块化架构,核心在于:

  1. 单向数据流:通过 Action → Mutation → State 的流程确保状态变更可追踪。
  2. 模块化:支持大型应用的状态树拆分。
  3. 响应式绑定:借助 Vue 实例实现高效的状态监听。

如需深入源码细节,可参考 Vuex 官方仓库及上述分析中引用的技术博客。

Vuex的核心源码简版:

let Vue;
class Store {
    // 持有state,并使其响应化
    constructor(options){
        this.state = new Vue({
            data:options.state
        })
        this.mutations = options.mutations;// mutations 是对象
        this.actions = options.actions;// mutations 是对象
        // 绑定this
        this.commit=this.commit.bind(this);
        this.dispatch=this.dispatch.bind(this);
    }
    // 实现commit和dispatch方法
    commit(type,arg){
        this.mutations[type](this.state,arg);
    }
    dispatch(type,arg){
        console.log(this.actions[type])
        return this.actions[type](this,arg)
    }
}
function install(_vue){
    Vue = _vue;
    Vue.mixin({// 为什么用混入?use是先执行,而this指向的是vue实例,是在main.js中后创建的,使用混入才能在vue实例的指定周期里拿到store实例并做些事情
        beforeCreate(){
            if (this.$options.store) {
                Vue.prototype.$store=this.$options.store;
            }
        }
    })
}
export default {
    Store,
    install
}