Vuex是一个专为Vue.js应用程序开发的状态管理模式.它采用集中式储存管理应用的所有组件的转台并以相应的规则保证装填以一中可预测的方式发生变化.

Vuex可以将组件中的某些属性、值或者方法拿出来统一去声明、统一去定义,在Vuex中去声明,设置一些方法以及一些逻辑运算,来修改这些组件用到的相同的值.

一、Vuex入门

1.1 初始化 Vuex 工程

1.1.1 新建项目命名 vuex-demo

vue create vuex-demo //vue创建项目

1.1.2 安装依赖和运行

进入工程目录

cd vuex-demo

安装依赖

npm i vuex -s

运行项目

npm run serve

1.2 读取状态值 state

每一个 Vuex 项目的核心就是 store(仓库, store 就是一个对象,它包含着你的项目中大部分的状态(state)

state 是 store 对象中的一个选项,是 Vuex 管理的状态对象(共享的数据属性)

1.2.1  在 src 目录下创建 store 目录,store 下创建 index.js 文件

编码如下:

import Vue from "vue";
import Vuex from "vuex"// 引入 Vuex 插件Vue.use(Vuex);const store = new Vuex.Store({// 注意V 和 S都是大写字母// 存放状态(共享属性)state: {count: 1}
})export default store

1.2.2 修改 main.js,导入和注册 store

编码如下:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store"Vue.config.productionTip = false;new Vue({router,store,//注册render: (h) => h(App),
}).$mount("#app");

1.2.3 组件中读取 state 状态数据,修改 src\views\Home.vue

编码如下:

<template><div class="home"><h1>count:{{$store.state.count}}</h1></div>
</template>

1.2.4 测试效果

关于Object(...) is not a function的报错 :

第一次重构项目的时候,莫名其妙的报了这个错,上网看别的文章说是因为vue,vuex版本的问题,之后就按他们说的降低版本,但是结果无济于事,依然报这个错.之后索性又重构了一次项目,安装依赖的时候,发现npm i vuex -s的方式安装不上,安装界面一跳就过去了,package.json中没有反应,就强行把"vuex": "^3.4.0"写进去,用npm i的方式安装的,这次运行项目就没有报错,上网找也没搞清楚我的这个情况,有大佬望告知.

1.3 改变状态值 mutation

在 store 的 mutations 选项中定义方法,才可以改变状态值

通过 $store.commit('mutationName') 触发状态值的改变.

1.3.1 修改 store/index.js , 在 store 中添加 mutations 选项

代码如下:

mutations: {add(state) {state.count++},subtraction(state) {state.count--}}

1.3.2 修改 src\views\Home.vue ,调用 mutations 中add、subtraction方法

<template><div class="home"><h1>count:{{$store.state.count}}</h1><button @click="add">加1</button><button @click="subtraction">减1</button></div>
</template><script>
// @ is an alias to /srcexport default {name: "Home",components: {},methods: {add() {this.$store.commit('add')},subtraction() {this.$store.commit('subtraction')}}
};
</script>

点击 加/减法 按钮,控制台和页面显示数字变化.

修改state,其他组件拿到的也是修改过的,比组件间通信方便很多.

但是,mutations只能添加同步的方法.

1.4  提交载荷 payload

可以向 $store.commit 传入额外的参数,即 mutation 的 载荷(**payload**)

1.4.1 修改 src\store 下的 index.js

mutations: {add(state, n) {//n 为荷载state.count += n},subtraction(state, n) {state.count -= n}}

1.4.2 修改 views\Home.vue 组件

methods: {add() {this.$store.commit('add', 10)//提交荷载},subtraction() {this.$store.commit('subtraction', 10)}}

1.5 分发Action

Action 类似于 mutation,不同在于:

Action 提交的是 mutation,而不是在组件中直接变更状态, 通过它间接更新 state

在组件中通过 this.$store.dispatch('actionName') 触发状态值间接改变

Action 也支持载荷

Action 可以包含任意异步操作

1.5.1 修改 store/index.js ,增加 actions 选项

actions: {add1(context, n) {// 触发 mutations 中的 increment 改变 statecontext.commit('add', n)},subtraction1(context, n) {//按需传值context.commit('subtraction', n)}}

1.5.2 修改 views/Home.vue, 触发 action 改变值

methods: {add() {// this.$store.commit('add', 10)//提交荷载// 触发 actions 中的 add 改变状态值this.$store.dispatch('add1', 10)},subtraction() {// this.$store.commit('subtraction', 10)this.$store.dispatch('subtraction1',10)}}

1.6 派生属性 getter

有时候需要从 store 中的 state 中派生出一些状态。

例如:基于上面代码,增加一个 desc 属性,当 count 值小于 50,则 desc 值为 吃饭 ; 大于等于 50 小于100,则 desc 值为 睡觉 ; 大于 100 , 则 desc 值为 打豆豆 。这时就需要用到 getter 解决。

getter 其实就类似于计算属性(get)的对象.组件中读取 $store.getters.xxx

1.6.1 修改 store/index.js ,增加 getters 选项

注意:getters 中接受 state 作为其第一个参数,也可以接受其他 getter 作为第二个参数

getters: {desc(state) {if (state.count < 50) {return '吃饭'} else if (state.count < 100) {return '睡觉'} else {return '打豆豆'}}}

1.6.2 修改 views/Home.vue, 显示派生属性的值

<div class="home"><h1>count:{{$store.state.count}}</h1><button @click="add">加1</button><button @click="subtraction">减1</button>派生属性:{{$store.getters.desc}}</div>

1.6.3 测试效果

点击 Home 页面的 触发改变 按钮,当 count 新增到 60 , desc 会显示为 睡觉

1.7 Module 模块化项目结构

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter 等.

1.7.1 工程模块化进行改造,在 store 下创建 modules 目录,该目录下创建 home.js

代码如下:

const state = {count: 0
}
const mutations = {add(state, n) {//n 为荷载state.count += n},subtraction(state, n) {state.count -= n}
}
const actions = {add1(context, n) {// 触发 mutations 中的 increment 改变 statecontext.commit('add', n)},subtraction1(context, n) {//按需传值context.commit('subtraction', n)}
}
const getters = {desc(state) {if (state.count < 50) {return '吃饭'} else if (state.count < 100) {return '睡觉'} else {return '打豆豆'}}
}export default {//将整体变为一个对象作为默认成员导出// 存放状态(共享属性)state,//派生属性getters,// 改变 state 状态mutations,actions,
}

1.7.2 修改 store\index.js, 导入 ./modules/home.js

const store = new Vuex.Store({modules: {home}
})

1.7.3 修改 Home.vue,About.vue

<template><div class="home"><!-- 模块化之后需要.home.count获取数据 --><h1>count:{{$store.state.home.count}}</h1><button @click="add">加10</button><button @click="subtraction">减10</button>派生属性:{{$store.getters.desc}}</div>
</template>
<template><div class="about"><h1>This is an about page</h1><h1>count:{{$store.state.home.count}}</h1></div>
</template>

正常访问, 与重构前一样


二、会员管理系统-Vuex 版

只对登录,获取用户信息,退出等功能采用Vuex状态管理的方式

2.1 初始化项目

2.1.1 复制 mms 工程为 mms-vuex

2.1.2 安装 Vuex

npm i vuex -s

2.2 登录

使用Vuex的时候,需要配合localStorage使用,防止刷新页面的时候,数据丢失.

2.2.1 登录与 token 状态管理

在 src\utils\ 目录下创建 auth.js, 封装 token 和 用户信息工具模块

const TOKEN_KEY = 'stu-token'
const USER_KEY = 'stu-user'//?获取token
export function getToken() {return localStorage.getItem(TOKEN_KEY)
}//?保存token
export function setToken(token) {return localStorage.setItem(TOKEN_KEY, token)
}//?获取用户信息
export function getUser() {//getItem 拿到的是字符串,而用户信息需要一个对象return JSON.parse(localStorage.getItem(USER_KEY))
}//?保存用户信息
export function setUser(user) {//user 是一个对象return localStorage.setItem(USER_KEY, JSON.stringify(user))
}//?移除用户信息
export function removeToken() {localStorage.removeItem(TOKEN_KEY);localStorage.removeItem(USER_KEY);
}

在 src 目录下新建 store\modules 目录,modules 下创建 user.js

//* 引入封装的方法
import { getToken } from "../../utils/auth";
import { setToken } from "../../utils/auth";
import { getUser } from "../../utils/auth";
import { setUser } from "../../utils/auth";
import { removeToken } from "../../utils/auth";
//* 引入 API login 中的方法
import { login, getUserInfo, logout } from "@/api/login.js"const user = {state: {token: null,user: null},mutations: {SET_TOKEN(state, token) {state.token = tokensetToken(token)//配合localStorage使用},SET_USER(state, user) {state.user = user;//setUser(user);},},actions: {//登录获取tokenLogin({ commit }, form) {//替换登录的login方法 form是登录页面的表单return new Promise((resolve, reject) => {// 提交表单给后台进行验证是否正确// resolve 触发成功处理,reject 触发异常处理login(form.username, form.password).then(response => {const resp = response.dataif (resp.flag) {//通过调用mutations中的方法修改statecommit('SET_TOKEN', resp.data.token)// 方法名称,载荷resolve(resp)//成功返回 resp}}).catch(err => {reject(err)})})}}
}export default user

在 src\store 目录下创建 index.js

import Vue from 'vue';
import Vuex from 'vuex';
import User from './modules/user.js'Vue.use(Vuex)export default new Vuex.Store({modules: {User}
})

修改 src 下的 main.js,导入和注册 store

//! 生成vue实例 相当于项目整个的入口
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import ElementUi from 'element-ui';//引入element-ui
import 'element-ui/lib/theme-chalk/index.css';//引入element-ui必需的css文件
import './premission.js';
import store from './store'Vue.config.productionTip = false;
Vue.use(ElementUi);//使用element-uinew Vue({router,store,render: (h) => h(App),
}).$mount("#app");

重构登录组件 views\login\index.vue

submitForm(formName) {this.$refs[formName].validate((valid) => {if (valid) {this.$store.dispatch('Login', this.form).then(response => {if (response.flag) {//response已经是response.data了 所以直接可以拿到flagthis.$router.push('/')//信息存储在promise对象中做了,这里只需要做路由跳转就可以了//并且之前的message提示,也做了统一异常处理.}})} else {console.log('error submit');return false;}})},

测试登录是否正常进入,并观察浏览器中 localStorage 是否有值

报错原因:

这个部分Vuex还没有做权限管理,浏览器没有token值的时候,我访问了首页,显示获取不到token,不加载首页,在token获取方法的位置找了半天,没找到错误= =,后来想起来浏览器如果本身就没有token值,不会跳转登录界面,重新登录解决.

2.2.2 解决刷新页面回到登录页面

当前在 permission.js 路由拦截中是通过浏览器 localStorage 获取 token 值,但现在使用的 Vuex 状态管理,需要通过 store 来获取 token 状态值.

在 src\permission.js 中将获取 token 方式替换为从 store 状态中获取,

如下:注意要 import 导入 store

...
import store from './store'//导入storerouter.beforeEach((to, from, next) => {// const token = localStorage.getItem('stu-token');const token = store.state.user.token//权限管理的token不在本地获取,需要在Vuex中获取
...

重新访问登录 http://localhost:8888/loginhttp://localhost:8888/loginhttp://localhost:8888/login ,登录后一样可以进入首页,刷新首页,发现会回到登录页面。因为刷新 后 token 状态值还原初始值 null, 所以又会要求 重新登录.

解决刷新页面重新登录的问题,在 src\store\modules\user.js 中 token 初始值为 getToken()

state: {token: getToken(),// getToken() 作为token初始值,解决刷新页面之后token为nulluser: null},

2.3 获取用户信息

之前获取用户信息是在登录中一起获取的,其实可以在权限拦截器( permission.js )中进行获取

2.3.1 修改 src\store\modules\user.js, 在 actions 中添加 GetUserInfo 方法

//通过token获取用户信息GetUserInfo({ commit, state }) {return new Promise((resolve, reject) => {getUserInfo(state.token).then(response => {const respUser = response.datacommit('SET_USER', respUser.data)resolve(respUser)}).catch(err => {reject(err)})})}

2.3.2 修改 src\permission.js , 从 store 中获取用户数据

router.beforeEach((to, from, next) => {// const token = localStorage.getItem('stu-token');const token = store.state.user.token//权限管理的token不在本地获取,需要在Vuex中获取if (!token) {//没拿到token,证明没有登录if (to.path === '/login' || to.path === '/register') {//如果当前路径在登录或者注册界面,只需要调用next方法来结束这个钩子函数next();} else {next({ path: '/login' })//其它路径就跳转到 /login}} else {if (to.path === '/login') {next();} else if (to.path === '/register') {next();} else {store.dispatch('GetUserInfo').then(response => {if (response.flag) {next()} else {//获取用户信息失败,跳转登录界面next({ path: '/login' })}})}}
})

2.3.3 修改 src\components\AppHeader\index.vue 中data 选项中的 user 属性值

            // user: JSON.parse(localStorage.getItem('stu-user')),//获取本身为字符串,通过.parse()将字符串转换为对象.这样上面才能获取到nicknameuser: this.$store.state.user.user,//前一个user代表组件化名称

重新登录后,本地存储中只有token,没有user.

token需要进行本地化 ,防止刷新页面的时候,路由变化的时候,token被删除,权限管理中,每次都通过token去获取user信息,即使Vuex被刷新,每次都会重新获取user信息,不会影响user信息的显示.

本地化之后,还需要用Vuex,user信息存在Vuex里进行状态管理,token也存在Vuex里,但token决定了权限管理,所以token要进行本地化,

2.4 退出

2.4.1 修改 src\store\modules\user.js, 在 actions 中添加 Logout 方法

//?退出登录Logout({ commit, state }) {return new Promise((resolve, reject) => {logout(state.token).then(response => {//将state置空,state中数据删掉,本地存储中的数据删掉const resp = response.datacommit('SET_TOKEN', '')commit('SER_USER', {})removeToken();//将localStorage的内容删掉resolve(resp)}).catch(err => {reject(err)})})}

2.4.2 修改 methods 选项中的 handleCommand 方法

handleCommand(command) {// this.$message('click on item ' + command);switch (command) {case 'a'://修改密码this.handlepwd();break;case 'b'://退出登录this.$store.dispatch('Logout').then(response => {this.$router.push('login')})break;}}

退出系统之后,token信息删除.

Vue项目 成员管理系统 Vuex状态管理(10)相关推荐

  1. 在vue项目中引用vuex状态管理工具

    在vue项目中引用vuex状态管理工具 一.vuex是什么? 二.使用步骤 1.引入库 2.在main.js文件引入配置 3.配置store/index.js文件 4.获取state数据 5.获取ge ...

  2. vue从入门到进阶:Vuex状态管理(十)

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 在 Vue 之后引入 vuex 会进行自动 ...

  3. vue2项目复习01-关闭elint检校,src文件别名,路由传参的对象写法,代理解决跨域问题,nprogress,vuex状态管理库,store的模块式开发,节流与防抖,编程式导航+事件委托路由跳转

    1.关闭elint语法校验 创建vue.config.js //关闭elint语法校验 {lintOnSave:false; } 2.src文件夹配置别名 jsconfig.json配置别名 @代表s ...

  4. vuex状态管理,用最朴实的话讲解最难懂的技术,

    一.案例演示 引入vuex 1.利用npm包管理工具,进行安装 vuex.在控制命令行中输入下边的命令就可以了. npm n install vuex --save 需要注意的是这里一定要加上 –sa ...

  5. [vuex]状态管理vuex

    vuex 状态管理vuex,之前一般都是通过一个全局js文件实现全局设置,在vue中通过vuex进行管理 简介 vuex是专为vue.js应用程序开发的状态管理模式.它采用集中存储管理应用的所有组件的 ...

  6. Vuex 状态管理的工作原理

    Vuex 状态管理的工作原理 为什么要使用 Vuex 当我们使用 Vue.js 来开发一个单页应用时,经常会遇到一些组件间共享的数据或状态,或是需要通过 props 深层传递的一些数据.在应用规模较小 ...

  7. 【vuex状态管理案例mutations和actions区别】

    目录 vuex 状态管理 传统组件传值的缺点 案例 加减 效果 现在我们希望它是两个计数器的数同时加加减~ 先来看一下减的 父组件 子组件 加的是一样的逻辑哦 虽然这样可以实现我们想要的效果但是,还是 ...

  8. Vuex---在 Vue 组件中获得 Vuex 状态state

    Vuex使用单一状态树(一个对象就包含了全部的应用层级状态),它作为唯一数据源存在,每个应用仅仅有一个store实例. 单一状态树使得我们能够直接定位任一特定的状态片段,在调试过程中也能轻易地取得整个 ...

  9. 【3D商城】使用Vuex状态管理完成购物车模块

    [3D商城]使用Vuex状态管理完成购物车模块 创建购物车的全局数据 添加产品到购物车 导航栏的购物车模块 结果 常见问题总结 创建购物车的全局数据 在store的index.js中 ,创建购物车变量 ...

最新文章

  1. 设计模式学习(一)——策略模式
  2. get方式请求接受参数的方法
  3. integer加1_利用Abaqus UEL开发自定义单元1
  4. c++整理程序 dev_C编程从入门到实践:C语言开发工具详解(2)
  5. 【数据库学习】——windows、MySQL构建新闻管理系统(控制台版)
  6. 长尾关键词seo_为什么您不应该忘记长尾SEO
  7. 50行以上c语言程序代码,C语言非常简单的字符统计程序50行
  8. concurrenthashmap_ConcurrentHashMap核心原理,这次彻底给整明白了
  9. gdi作图与系统不兼容_技术作图:技能准备amp;物理装备
  10. 从零开始学习makefile(7) makefile的filter的作用
  11. 小程序之跨平台黑魔法
  12. 史上最详细Excel制作生命游戏,体验生命演化。
  13. 学计算机的用hd620,hd620显卡能学C4D吗
  14. Java+Selenium实现网页截图
  15. Wireshark The capture session could not be initiated on interface报错解决
  16. 设计模式之禅【组合模式】
  17. Android手机上,利用bat脚本模拟用户操作
  18. 如何解决java中的安全问题_如何解决java中“使用了未经检查或不安全的操作 请使用 -Xlint:unchecked 重新编译 ”的问题...
  19. leetcode 2188 归约后线性dp
  20. mysql的password()函数和md5函数

热门文章

  1. 博客开篇 -- 每个程序员都是一位肆意江湖的游侠少年
  2. 产品经理-商业思维2商业模式
  3. 关于计算机的伟大名言
  4. 微软技术在金融行业的应用
  5. c#画平行线和垂线的代码
  6. 水晶报表二维码如何打印
  7. ecshop手机端订单城市插件(基于gps定位)
  8. 如何写出让领导刮目相看的工作汇报?
  9. vue下载模板时报 vue-cli · Failed to download repo vuejs-templates/webpack: read ECONNRESET
  10. 长假余额为零!我用Python做了个中秋国庆双节拼图游戏