返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
StarBlog前端开发-Vue

StarBlog Blog Development Notes: Frontend Development (8) - Vuex and State Management

State Management In many application scenarios, we need to share state between components. For example, our left sidebar navigation needs collapse and expand functionality. When collapsed, its width is very small, showing only menu icons. Because the navigation menu bar's width changes after collapsing, the main content area on the right needs to occupy the space freed up by the navigation bar's collapse, and the main content area's width also needs to change according to the navigation bar's collapse state. However, the navigation bar and the main content area are two different components, and state passing between non-parent-child components is not supported, so the problem of state sharing between components arises. Previously, when I was writing Flutter, responsive de

曦远 (DealiAxy)约 24 分钟
目录11 个章节

State Management

In many application scenarios, we need to share state between components. For example, our left navigation bar requires a collapse and expand functionality. When collapsed, its width becomes very small, displaying only menu icons. Because the navigation menu's width changes upon collapse, the main content area on the right needs to occupy the space released by the navigation bar's collapse. Consequently, the main content area's width must also adjust according to the navigation bar's state. Since the navigation bar and the main content area are two different components, and state cannot be passed between non-parent-child components, the problem of state sharing between components arises.

Previously, when I was writing Flutter, the state management for responsive design left a deep impression on me. At that time, I used the provider library to manage global state. Then, in the Vue ecosystem, there is Vuex, which is said to draw inspiration from Flux, Redux, and The Elm Architecture. Unlike other patterns, Vuex is a state management library specifically designed for Vue.js to leverage Vue.js's fine-grained data reactivity system for efficient state updates.

Vuex is a state management pattern + library (状态管理模式 + 库) specifically designed for Vue.js applications. It uses centralized storage to manage the state of all components in the application and ensures that state changes occur in a predictable manner following specific rules.

Vuex official website: https://vuex.vuejs.org/zh/

Installing Vuex

Just install it without overthinking.

yarn add vuex@3.6.2

Note: Use the 3.x version of Vuex, as version 4.x is for Vue 3. Our project is currently still based on Vue 2.

Add store

Create a new store directory under the src directory to manage the application state specifically.

The directory structure is as follows:

store
├── modules
│   └── app.js
└── index.js

index.js

Import Vuex and organize the import and management of submodules uniformly in index.js.

The code is as follows:

import Vue from 'vue'
import vuex from 'vuex'

Vue.use(vuex);

// Import submodules
import app from './modules/app'

const store = new vuex.Store({
  modules: {
    app: app
  }
})

export default store

modules/app.js

app.js is a global configuration for the application, such as the theme color, navigation bar collapse state (导航栏收缩状态), etc. See the comments for details.

The code is as follows:

export default {
  state: {
    appName: "StarBlog",  // Application name
    themeColor: "#14889A",  // Theme color
    oldThemeColor: "#14889A",   // Previous theme color
    collapse: false,  // Navigation bar collapse state
    menuRouteLoaded: false    // Whether the menu and routes have been loaded
  },
  getters: {
    collapse(state) {// Corresponds to the state above
      return state.collapse
    }
  },
  mutations: {
    onCollapse(state) {  // Change collapse state
      state.collapse = !state.collapse
    },
    setThemeColor(state, themeColor) {  // Change theme color
      state.oldThemeColor = state.themeColor
      state.themeColor = themeColor
    },
    menuRouteLoaded(state, menuRouteLoaded) {  // Change menu and routes load status
      state.menuRouteLoaded = menuRouteLoaded;
    }
  },
  actions: {}
}

Introducing and Using the store

Introduce the store in src/main.js.

The code is as follows:

import store from './store'

new Vue({
  el: '#app',
  router,
  store, // Pass in the store
  components: {App},
  template: '<App/>'
})

Here, we'll use the sidebar collapse functionality as an example.

First, add a button to the top bar to control the sidebar collapse.

Adding a Collapse Component

Create a new components directory under src, and create a navigation bar collapse/expand component Hamburger inside it.

The directory structure is as follows:

src
└── components
    └── Hamburger
        └── index.vue

The component is drawn using SVG, which determines whether to rotate based on the isActive state and displays different graphics for collapsed and expanded states.

The code is as follows:

<template>
  <svg t="1492500959545" @click="onClick == null ? emptyClick : onClick" class="hamburger" fill="#fff"
       fill-opacity="0.8" :class="{'is-active':isActive}" viewBox="0 0 1024 1024"
       version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1691" xmlns:xlink="http://www.w3.org/1999/xlink"
       width="64" height="64">
    <path
      d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
      p-id="1692"></path>
    <path
      d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
      p-id="1693"></path>
    <path
      d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
      p-id="1694"></path>
  </svg>
</template>

<script>
export default {
  name: 'hamburger',
  props: {
    isActive: {
      type: Boolean,
      default: false
    },
    onClick: {
      type: Function,
      default: null
    }
  },
  methods: {
    emptyClick() {

    }
  }
}
</script>

<style scoped>
.hamburger {
  display: inline-block;
  cursor: pointer;
  width: 20px;
  height: 20px;
  transform: rotate(90deg);
  transition: .38s;
  transform-origin: 50% 50%;
}

.hamburger.is-active {
  transform: rotate(0deg);
}
</style>

HeaderBar Page References Collapse Component

Edit HeaderBar.vue to import the hamburger component in the header area HeadBar, and bind its isActive state to the collapse state.

The layout code is as follows:

<template>
  <div class="header" style="background:#14889A"
       :class="collapse?'position-collapse-left':'position-left'">
    <!-- Navigation Collapse -->
    <span class="hamburg">
      <el-menu class="el-menu-demo" background-color="#14889A" text-color="#fff" active-text-color="#14889A"
               mode="horizontal">
        <el-menu-item index="1" @click="onCollapse"><hamburger :isActive="collapse"></hamburger></el-menu-item>
      </el-menu>
    </span>
    <!-- Toolbar -->
    <!-- Old code omitted -->
</template>

Use computed properties to import store properties so you can directly reference the collapse state value in the page. (Of course, if you don't mind the length, you can also reference it directly in the page via $store.state.app.collapse without using computed properties.)

Add the following JavaScript code:

// First, import
import {mapState} from 'vuex'
import Hamburger from "@/components/Hamburger"

export default {
  name: "HeaderBar",
  components: {
    Hamburger
  },
  methods: {
    // Collapse the navigation bar
    onCollapse: function () {
      this.$store.commit('onCollapse')
    },
  },
  computed: {
    ...mapState({
      collapse: state => state.app.collapse
    })
  }
}

Add the following SCSS code:

.hamburg, .navbar {
  float: left;
}
.position-collapse-left {
  left: 65px;
}

Modify Navbar.vue

Layout code modifications

<template>
  <div class="menu-bar-container">
    <!-- logo -->
    <div class="logo" style="background:#14889A" :class="collapse?'menu-bar-collapse-width':'menu-bar-width'"
         @click="$router.push('/')">
      <img v-if="collapse" src="@/assets/codelab.jpg"/>
      <div>{{ collapse ? '' : appName }}</div>
    </div>
  </div>
</template>

JavaScript code modifications

import {mapState} from 'vuex'
export default {
  computed: {
    ...mapState({
      appName: state => state.app.appName,
      collapse: state => state.app.collapse,
    })
  },
}

SCSS code addition

.menu-bar-collapse-width {
    width: 65px;
}

Main Content Page Modifications

Modify the layout code

<template>
  <div id="main-container" class="main-container"
       :class="$store.state.app.collapse?'position-collapse-left':'position-left'">
    <!-- Tab Pages -->
    <div class="tab-container"></div>
    <!-- Main Content Area -->
    <div class="main-content">
      <keep-alive>
        <transition name="fade" mode="out-in">
          <router-view></router-view>
        </transition>
      </keep-alive>
    </div>
  </div>
</template>

Add SCSS code

.position-collapse-left {
  left: 65px;
}

Test Results

Without collapsing the sidebar

image-20220220173448183

Click the button to collapse the sidebar

image-20220220173506251

Done and dusted~

_EOF_

StarBlog Blog Development Notes: Frontend Development (8) - Vuex and State Management

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

StarBlog博客开发笔记:前端开发之导航守卫

路由对象router给我们提供了beforeEach方法,可以在每次路由之前进行一些相关处理,也叫导航守卫,我们这里就通过导航守卫实现一些类似身份认证的辅助功能。 修改router/index.js文件,添加导航守卫,在每次路由时判断用户会话是否过期。如果登录有效且跳转的是登录界面,就直接路由到主页;如果是非登录页面且会话过期,就跳到登录页面要求登录。 代码如下 router.beforeEach

2023-07-14 · StarBlog前端开发-Vue · 约 1 分钟

StarBlog博客开发笔记:前端开发(7)之主页面

界面设计 按照ElementUI提供的布局来 左边是导航栏,右边上方是标签页,然后是主内容区 如图 二级类目 开始写代码 主页面的内容已经比较复杂了,全部写在一个文件内不现实 我们来分解一下 根据这个布局,页面可以分为头部、主体、左侧导航栏三部分 所以我来新建三个vue页面 HeaderBar.vue Navbar.vue MainContent.vue 完成之后目录结构如下 views ├──

2023-07-14 · StarBlog前端开发-Vue · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…

StarBlog Blog Development Notes: Frontend Development (8) - Vuex and State Management · StarBlog