vue的状态管理你知道吗?

68 阅读4分钟

当我们对 Vue 的基础和进阶知识有了较为扎实的掌握后,便可以深入探索 Vue 的高阶世界,进一步挖掘其强大的功能与灵活的应用技巧,以应对更为复杂和多样化的开发需求。本高阶篇教程将为你开启这扇深入学习 Vue 的大门。

一、Vuex 状态管理

(一)为什么需要 Vuex 在 Vue 应用不断发展壮大的过程中,组件之间的数据共享和状态管理变得愈发复杂。多个组件可能需要共享同一数据,并且对数据的操作可能会引发一系列连锁反应,影响到多个相关组件的显示和行为。传统的父子组件通信方式在这种复杂场景下会显得力不从心,而 Vuex 就是专门为解决这类大规模状态管理问题而生的。

(二)核心概念 State:Vuex 使用单一状态树,即所有应用层级的状态都集中存储在一个对象中。例如,在一个电商应用中,商品列表、购物车信息、用户登录状态等都可以作为 state 的一部分。

const state = {
  products: [],
  cart: [],
  isLoggedIn: false
};

Mutations:Mutations 是更改 Vuex 中 state 的唯一推荐方式。它们是同步函数,接收 state 作为第一个参数,并且可以接收额外的参数。这样可以保证状态的变更可追溯且易于调试。

const mutations = {
  ADD_PRODUCT_TO_CART(state, product) {
    state.cart.push(product);
  },
  SET_LOGIN_STATUS(state, status) {
    state.isLoggedIn = status;
  }
};

Actions:Actions 类似于 Mutations,但它们可以包含异步操作,如网络请求。Actions 提交 Mutations 来间接改变 state。

const actions = {
  async fetchProducts({ commit }) {
    const response = await axios.get('/api/products');
    commit('SET_PRODUCTS', response.data);
  },
  login({ commit }, userCredentials) {
    return new Promise((resolve, reject) => {
      // 模拟登录请求
      setTimeout(() => {
        if (userCredentials.username === 'validUser' && userCredentials.password === 'validPassword') {
          commit('SET_LOGIN_STATUS', true);
          resolve();
        } else {
          reject('Invalid credentials');
        }
      }, 1000);
    });
  }
};

Getters:Getters 用于从 state 中派生出一些新的数据,类似于计算属性。它们可以对 state 进行过滤、排序等操作后返回给组件使用。

const getters = {
  cartTotal(state) {
    return state.cart.reduce((total, item) => total + item.price, 0);
  },
  filteredProducts(state, getters) {
    return state.products.filter(product => product.price < getters.cartTotal);
  }
};

(三)在 Vue 组件中使用 Vuex 在 Vue 组件中,可以通过 this.$store访问 Vuex 实例。例如,在一个组件中获取购物车总金额:

<template>
  <div>
    <p>购物车总金额: {{ cartTotal }}</p>
  </div>
</template>

<script>
export default {
  computed: {
    cartTotal() {
      return this.$store.getters.cartTotal;
    }
  }
};
</script>

要触发一个 action,比如登录操作:

<template>
  <form @submit.prevent="login">
    <input type="text" v-model="username" placeholder="Username">
    <input type="password" v-model="password" placeholder="Password">
    <button type="submit">Login</button>
  </form>
</template>

<script>
export default {
  data() {
    return {
      username: '',
      password: ''
    };
  },
  methods: {
    login() {
      this.$store.dispatch('login', { username: this.username, password: this.password })
      .then(() => {
          // 登录成功后的操作
        })
      .catch((error) => {
          console.log(error);
        });
    }
  }
};
</script>

二、Vue 路由高级用法

(一)路由导航守卫 路由导航守卫可以在路由跳转前、跳转后等不同阶段进行一些操作,如权限验证、页面加载前的数据获取等。

全局前置守卫:在所有路由跳转前执行。
import Vue from 'vue';
import Router from 'vue-router';

Vue.use(Router);

const router = new Router({
  routes: [
    // 路由配置
  ]
});

router.beforeEach((to, from, next) => {
  // 检查用户是否登录,如果未登录且要跳转到需要登录的页面,则跳转到登录页面
  const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
  const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true';

  if (requiresAuth &&!isLoggedIn) {
    next('/login');
  } else {
    next();
  }
});

export default router;

路由独享守卫:只在特定路由跳转前执行。]

const router = new Router({
  routes: [
    {
      path: '/admin',
      component: AdminPage,
      meta: { requiresAuth: true },
      beforeEnter: (to, from, next) => {
        // 可以在这里进行特定于 /admin 路由的权限验证或其他操作
        if (localStorage.getItem('isAdmin') === 'true') {
          next();
        } else {
          next('/');
        }
      }
    }
  ]
});

全局后置守卫:在路由跳转完成后执行,可以用于页面标题的设置等操作。

router.afterEach((to, from) => {
  document.title = to.meta.title || 'Default Title';
});

(二)动态路由匹配与参数传递 在路由配置中可以定义动态路由参数,例如:

const router = new Router({
  routes: [
    {
      path: '/product/:id',
      component: ProductPage,
      props: true // 启用 props 传递参数
    }
  ]
});

在组件中接收参数:

<template>
  <div>
    <p>产品 ID: {{ productId }}</p>
  </div>
</template>

<script>
export default {
  props: ['productId']
};
</script>

当访问 /product/123 时,组件中的 productId 就会被设置为 123。

(三)路由懒加载 随着应用规模的增大,打包后的 JavaScript 文件可能会变得很大,影响页面加载速度。路由懒加载可以将每个路由对应的组件分割成独立的代码块,只有在访问该路由时才加载对应的组件。

const router = new Router({
  routes: [
    {
      path: '/about',
      component: () => import(/* webpackChunkName: "about" */ '@/views/About.vue')
    },
    {
      path: '/contact',
      component: () => import(/* webpackChunkName: "contact" */ '@/views/Contact.vue')
    }
  ]
});

在本 Vue 学习教程之高阶篇的第一部分,我们深入学习了 Vuex 状态管理和 Vue 路由的高级用法。这些知识将极大地提升我们构建大型、复杂 Vue 应用的能力,让我们能够更好地组织代码、管理应用状态和处理路由逻辑。后续教程将继续探索 Vue 的其他高阶特性,如自定义指令、插件开发等,帮助大家成为 Vue 开发的高手。