菜单快捷导航

  1. Vuex是什么东东,有什么应用场景?localStorage和sessionStorage能否替代它?
  2. Vuex知识点State、Getter、Mutaion、Action
  3. Vuex模块化(Module)

1、Vuex概念和应用场景

  首先,Vuex是什么,官网介绍说Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。我的理解就是Vuex就是类似于sessionStorage这样管理数据(本地存和取)的一种技术方案。

  既然vuex类似于sessionStorage,那为何我们还要学习vuex,直接用sessionStorage和localStorage不就好了?这个问得好,我来描述一种场景:多个视图(view)组件都要用到某一条数据(状态),当这条数据发生变化的时候,依赖于该数据(状态)的相关视图(view)都要跟着即时更新。这种场景在工作中非常常见,我说一个自己碰到的例子,以前有一个react项目,其中有个功能是在pc页面自定义小程序页面,然后整个PC页面有三个组件组成,在三个组件中还有其他的很多子组件。然后一开始的做法就是通过事件和组件间传值来进行整个页面数据同步更新,后面随着组件越来越多,功能越来越复杂,麻烦和问题也就越来越多。然后每一个后面来接手的同事看代码都要看好一阵,长痛不如短痛...

  对的,在工作中这种常见的多个组件依赖于同一条数据(状态),需要即时响应更新的情况,vuex的价值就体现出来了。这种情况下,vuex相比其他实现手段,就要简单干脆方便多了!先看一个小例子,看看vuex和localStorage、sessionStorage的区别,上图:

  如图,vuexPageA页面中引用了三个组件,每个组件都分别从localStorage、sessionStorage、vuex中取了一个值。点击按钮加1的时候,vuex的值是及时更新了,其他需要刷新才能更新。总结一下:

  • localStorage存储的值能够永久的存储在浏览器上。不管是重新打开新窗口还是重启,同一个浏览器上的相同域名下,localStorage的值一直在。
  • sessionStorage存储的值依赖于当前窗口(当前会话), 只要当前窗口不关闭,它存储的数据就一直在。一旦关闭窗口或者打开新窗口,sessionStorage之前存储的数据就会消失。
  • 相比localStorage和sessionStorage,vuex存储的数据可以即时更新到,当前项目下的所有引用了该数据的组件。但是如果刷新页面的话,vuex存储的值会重置,而localStorage和sessionStorage存储的值不会重置。

  相关代码见:https://github.com/xiaotanit/tan_vue/blob/master/src/views/vuex/VuexPageA.vue

2、Vuex知识点State、Getter、Mutaion、Action

2.1 Vuex之State和mapState

  每一个Vuex应用的核心就是store(仓库),“store"基本上就是一个容器。Vuex使用单一状态树,相当于用一个对象(store)就包含了全部的应用层级状态,也就是说每个应用也只包含一个store实例。因此Vuex的使用从new一个Vuex.Store实例(store实例)开始。store实例中的State属性就是用来存放Vue应用的所有的状态。先来看要给最简单的包含State属性的store实例:

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex) export default new Vuex.Store({
state: {
count: 0,
},
})

后面的mutations、getters、actions再慢慢往里面加入代码。

  store实例创建,如何应用?Vue实例创建时,提供了一个store选项,可以让Vuex通过store选项,将store实例对象从根组件”注入“到每一个子组件中:

import Vue from 'vue'
import App from './App.vue'
import router from './router.js' //vuex 之 store实例对象
import store from './api/store/index' new Vue({
router,
store, // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件
render: h => h(App)
}).$mount('#app')

  store实例注入根组件后,应用中的每个组件中通过this.$store指的就是该store实例对象。那么现在如何在Vue组件中展示store中的state状态(数据)呢?由于Vuex的状态存储是即时响应的,从store实例中读取状态最简单的方法就是在Vue组件中”计算属性“computed中返回某个状态。每当store.state中某个状态变化的时候,都会重新求取计算属性,并且触发更新相关联的DOM。

  mapState是一个辅助函数,当我们应用中一个组件需要获取store中多个状态的时候,使用mapState辅助函数可以帮助我们更加方便生成计算属性。看看下面的应用测试代码:

import { mapState } from 'vuex';

    export default {
data(){
return {
localCount: 88
}
},
mounted(){
console.log("...store对象:", this.$store);
},
computed:{
localStorage_count(){
return localStorage.getItem('localStorage_count')
},
//使用对象展开符"...",可以将对象目标对象混入到外部对象中
...mapState({
sessionStorage_count(){
return sessionStorage.getItem('sessionStorage_count')
},
vuex_count: state => state.count, //箭头函数可以使代码更简练
vuex_count_alias: 'count', //传字符串参数'count'等同于 state => state.count
// 为了能够使用 `this` 获取局部状态,必须使用常规函数
countPlusLocalState (state) {
return state.count + this.localCount
}
}),
},
}

2.2 Vuex之Getter和mapGetters

  有时我们需要从store中的state种派生出一些状态,比如对store中的某一个状态(数据)进行筛选过滤,然后特别是当有多个组件需要用到这种状态(数据)时,“getter"就出场了!Vuex允许我们在store中定义”getter"(可以认为是store对象的计算属性)。就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。Getter接受state作为其第一个参数:

export default new Vuex.Store({
state: {
count: 0,
todos: [
{ id: 1, text: '金戈铁马,气吞万里如虎', done: true },
{ id: 2, text: '老骥伏枥,志在千里', done: false },
{ id: 3, text: '周公吐哺,天下归心', done: true },
{ id: 4, text: '但使龙城飞将在,不教胡马度阴山', done: false },
]
},
//Vuex允许我们再store中定义"getter"(可以认为是store的计算属性)。
// 就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
getters: {
doneTodos: state => {
console.log('...state.getters.donwTodos...')
return state.todos.filter(todo => todo.done)
},
//Getter也可以接受其他getter作为第二个参数
//getter在通过属性访问时是作为Vue的响应式系统的一部分缓存其中的
doneTodosCount: (state, getters) => {
console.log('...state.getters.doneTodosLength...', getters.doneTodos)
return getters.doneTodos.length;
},
//通过方法访问:通过让getter返回一个函数,来实现给getter传参。
//getter在通过方法访问时,每次都会去进行调用,而不会缓存结果。
getTodoById: (state) => (id) => {
console.log('...state.getters.getTodoById...: ', id);
return state.todos.find(todo => todo.id === id);
}
}, })

  Getter应用:Getter会暴露为 store.getters 对象,然后在组件中,我们可以通过this.$store.getters来得到getter。getter里面的属性,可以返回属性,也可以返回方法。如果getter通过属性访问时是作为Vue的响应式系统的一部分缓存,首次调用后再次调用时就会调用缓存,只有该属性的依赖值变化时,再次调用该属性才会重新调用重新缓存。如果getter通过方法访问时,每次都会去进行调用,而不会缓存结果。组件中应用测试代码:

methods:{
//state.getters调用
stateGettersProperty(){ //getters属性调用, 属性调用会被缓存
console.log(this.$store.getters.doneTodos);
console.log(this.$store.getters.doneTodosCount);
},
stateGettersMethod(){ //方法调用,每次都会去进行调用,而不会缓存结果。
console.log(this.$store.getters.getTodoById(2).text);
console.log(this.$store.getters.getTodoById(3).text);
},
addTodo(){ //增加数据
let count = this.$store.state.todos.length;
let obj = {
id: count + 1,
text: (count+1) + '***' + (count+1),
done: count % 2
}
this.$store.commit('addTodos', obj);
}, }

  mapGetters也是一个辅助函数,可以将store对象中的getter映射到局部计算属性:

import { mapGetters } from 'vuex'

export default {
// ...
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters([
'doneTodosCount',
'anotherGetter',
// ...
])
}
}

  如果你想将一个 getter 属性另取一个名字,使用对象形式:

mapGetters({
// 把 `this.doneCount` 映射为 `this.$store.getters.doneTodosCount`
doneCount: 'doneTodosCount'
})

2.3 Vuex之Mutation和mapMutations

  上面说的mapState、getters、mapGetters都是对store对象中的状态(state)进行应用,如果想更改Vuex的store对象中的状态(state),必须要用mutation。Vuex中的mutation非常类似于事件:每个mutation都有一个字符串的事件类型(type)和一个回调函数(handler) 。这个回调函数就是我们实际进行状态更改的地方,并且它会接受state作为第一个参数:

const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 变更状态
state.count++
}
}
})

  mutation里面handler调用通过store.commit来调用,调用方式有“载荷(payload)"和“对象风格”两种方式:

  • 载荷提交方式:

    // ...
    mutations: {
    increment (state, n) {
    state.count += n
    }
    }
    store.commit('increment', 10)
  • 对象风格提交方式:
    mutations: {
    increment (state, payload) {
    state.count += payload.amount
    }
    }
    store.commit({
    type: 'increment',
    amount: 10
    })

    一条重要的原则:mutation必须是同步函数。在组件中使用this.$store.commit('***')提交mutation,或者使用mapMutations辅助函数将组件中的methods映射为store.commit调用。

2.4 Vuex之Action和mapActions

  Action类似于mutation,但是Action提交的是mutation,不能直接变更状态;另外Action可以包含任意异步操作。在组件中使用this.$store.dispatch('***')调用action,或者使用mapActions辅助函数将组件中的methods映射为store.dispatch调用。

State、Getter、Mutation、Action的一些应用测试代码见:https://github.com/xiaotanit/tan_vue/blob/master/src/views/vuex/VuexPageB.vue

3、Vuex之模块化(Module)

   由于使用单一状态树,应用的所有状态(数据)会集中到一个比较大的对象。当应用变得非常复杂时,store对象就有可能变得相当臃肿。为了解决这种问题,Vuex允许我们将store分隔成模块(module)。每个模块都有自己的state、mutation、action、getter、甚至是嵌套子模块。

  默认情况下,模块内容的action、mutation和getter是注册在全局命名空间的,这样使得多个模块能够对同一mutation或action作出响应。因此为了让模块具有更高的封装度和复用性,我们可以在每个子模块中添加namespaced: true属性,这样表示该模块成为了带命名空间的模块。这样后面再调用该模块的getter、action和mutation时需要带上该模块名称+调用的属性或方法。下面写一个示例代码:

  新建三个js文件moduleA.js、moduleB.js、moduleStore.js,其中moduleA和moduleB分别为子模块。

moduleA.js:

const state = {
countA: 99
} const mutations = {
increment(state){
state.countA++
},
decrement(state){
state.countA--
}
} const getters = {
doubleCount(state){
return state.countA * 2
}
} const actions = {
add({ commit }){
setTimeout(function(){
commit('increment')
}, 50)
},
minus({ commit }){
setTimeout(()=>{
commit('decrement')
}, 500)
}
} export default {
namespaced: true, //表示设置命名空间
state,
mutations,
getters,
actions
}

moduleB.js:

const state = {
countB: 11
} const mutations = {
increment(state){
state.countB++;
},
decrement(state){
state.countB--;
}
} //getters类似state里面属性的计算属性
const getters = {
doubleCount(state){
return state.countB * 2;
}
} const actions = {
add({ commit }){
commit('increment')
},
minus({ commit }){
commit('decrement')
}
} export default {
namespaced: true,
state,
getters,
mutations,
actions
}

moduleStore.js:

/*
* 当项目大了后,为了责任清晰,目标明确,更易管理,将store拆成多个module形式
* */
import moduleCountA from './moduleA'
import moduleCountB from './moduleB'
import vuex from 'vuex'
import vue from 'vue'
vue.use(vuex) export default new vuex.Store({
modules: {
moduleCountA,
moduleCountB
}
})

  再新建一个VuexPageC.vue页面,测试调用,js代码如下:

import { mapGetters, mapActions, mapMutations } from 'vuex'

    export default {
computed:{
...mapGetters({
doubleCountA: 'moduleCountA/doubleCount',
doubleConunB: 'moduleCountB/doubleCount'
})
},
methods: {
...mapActions({
//moduleA模块的actions
addCountA: 'moduleCountA/add',
minusCountA: 'moduleCountA/minus',
//moduleB模块的actions
addCountB: 'moduleCountB/add',
minusCountB: 'moduleCountB/minus'
}),
...mapMutations({
//moduleA模块的mutions
incrementA: 'moduleCountA/increment',
decrementA: 'moduleCountA/decrement',
//moduleB模块的mutions
incrementB: 'moduleCountB/increment',
decrementB: 'moduleCountB/decrement'
}),
}
}

页面效果如图:

完整VuexPageC.vue页面代码见:https://github.com/xiaotanit/tan_vue/blob/master/src/views/vuex/VuexPageC.vue

vuex知识笔记,及与localStorage和sessionStorage的区别的更多相关文章

  1. vuex存储和本地存储(localstorage、sessionstorage)的区别

    1.最重要的区别:vuex存储在内存,localstorage则以文件的方式存储在本地 2.应用场景:vuex用于组件之间的传值,localstorage则主要用于不同页面之间的传值. 3.永久性:当 ...

  2. localStorage和sessionStorage的区别

    //在chrome测试的结果; 知识点1:localStorage和sessionStorage的区别; localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除local ...

  3. cookie、session、localStorage、sessionStorage的区别

    cookie的机制 cookie是存储在用户本地终端上的数据.有时也用cookies,指某些网站为了辨别用户身份,进行session跟踪而存储在本地终端上的数据,通常经过加密. Cookie是服务器发 ...

  4. localStorage与sessionStorage 的区别

    通过一枚页面计数器来区别localStorage与sessionStorage. 通过一个计数变量pageconut,每刷新页面,增加的是localStorage的数量,而sessionStorage ...

  5. 13.localStorage和sessionStorage的区别

    HTMl5的sessionStorage和localStorage html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage. sessionSt ...

  6. Cookie、LocalStorage 与 SessionStorage的区别在哪里?

    基本概念 Cookie Cookie 是小甜饼的意思.顾名思义,cookie 确实非常小,它的大小限制为4KB左右.它的主要用途有保存登录信息,比如你登录某个网站市场可以看到“记住密码”,这通常就是通 ...

  7. cookie、LocalStorage、sessionStorage三者区别以及使用方式

    cookie用来保存客户浏览器请求服务器页面的请求信息 HTML5的WebStorage提供了两种API:localStorage(本地存储)和sessionStorage(会话存储) WebStor ...

  8. cookie、localStorage、sessionStorage的区别

    localStorage - 没有时间限制的数据存储 sessionStorage - 针对一个 session 的数据存储 共同点:sessionStorage.localStorage和cooki ...

  9. localStorage 和 sessionStorage的区别

    存储对象: 在主流浏览器中,添加了html5  Web Storage API 的接口,storage是一个存储对象,它包括会话存储(session storage)或本地存储(local stora ...

随机推荐

  1. linux入门系列8--shell编程

    本文将结合前面介绍的Linux命令.管道符等知识,通过VI编辑器编写Shell脚本,实现能自动化工作的脚本文件. 在讲解Linux常用命令"linux入门系列5--新手必会的linux命令& ...

  2. git工作中总结2

    目的:在远程分支上添加新文件(代码) 1.clone分支 git clone -b 分支 url cd到文件夹,添加文件到改目录下 2.创建新的分支并切换 git checkout -b dev(本地 ...

  3. 【红外DDE算法】聊聊红外图像增强算法的历史进程(第一回)

    宽动态红外图像增强算法综述回顾过去带你回顾宽动态红外图像增强算法的历史进程,历来学者的一步步革命(新的算法框架提出),一步步改革(改进优化),从简单粗暴到细致全面.正所谓是:改革没有完成时,只有进行时 ...

  4. 学习 lind UML 资源 十月 第二弹

    step one 来分析一下  UML 资源 管理

  5. ASP.NET MVC4 使用UEditor富文本

    原帖:http://user.qzone.qq.com/369175376/infocenter?ptlang=2052     第一步:先到http://ueditor.baidu.com/webs ...

  6. Mysql梳理-关于索引/引擎与锁

    前言 最近突发新型肺炎,本来只有七天的春节假期也因为各种封锁延长到了正月十五,在家实在闲的蛋疼便重新研究了一下Mysql数据库的相关知识,特此总结梳理一下.本文主要围绕以下几点进行: 1.Mysql的 ...

  7. 使用ob缓存简单实现页面静态化

    <?php //接收新闻id,传统的方法查询数据库并显示数据 $id=intval($_GET['id']); //先判断该新闻对于的静态页面是否存在,如果有,则直接返回,如果 //没有,则查询 ...

  8. CTF--HTTP服务--路径遍历(拿到www-data用户权限)

    开门见山 1. 扫描靶机ip,发现PCS 172.18.4.20 2. 用nmap扫描靶机开放服务及版本 3. 再扫描靶机的全部信息 4. 用nikto工具探测http服务敏感信息 5. 用dirb工 ...

  9. python(从放弃到从头开始)

    本节内容 Python介绍 发展史 Python 2 or 3? Hello World程序 变量 用户输入 .pyc是个什么鬼? 数据类型初识 数据运算 表达式if ...else语句 表达式for ...

  10. Maven 项目无法在Ecplise加进tomcat server

    当把用Maven项目 加进 tomcat server 时,出现 "There are no resources that can be added or removed from the ...