vuex简单示例

一.vuex是什么,解决了什么问题?

官方解释是:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化.
个人理解是因为vue各个组件是相对独立的,要共享数据,就变的很麻烦.vuex就是为了解决各个组件传递数据与共享数据.

 

二.vuex的核心概念

vuex的核心概念是store,store中包括了state,mutation,action,getter

1.state:需要用到的状态变量
2.mutation:同步修改state
3.action:异步方法和commit mutation
4.getter:相当于computed,主要用作对state进行计算后,生成新的数据状态

一般流程是组件dispatch一个action,action再commit一个mutation,mutation对state做更改;需要计算后的state,则使用getter.

 

三.一个简单的示例

1.需求:
根据id来获取用户信息

2.安装vuex,安装axios(ajax需求)

3.在src下新建目录store,建立store.js文件,代码如下所示

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import qs from 'qs'

Vue.use(Vuex)
axios.defaults.baseURL = '/api'

const store = new Vuex.Store({
  state: {
    username: '暂无用户名,请获取数据'
  },
  // Vue 建议我们mutation 类型用大写常量表示
  mutations: {
    SET_USER_NAME (state, user) {
      state.username = user.name
    }
  },
  actions: {
    getData (context, id) {
      axios.post(
        'http://127.0.0.1:9000/mobile/info',
        qs.stringify({id: id})
      ).then(function (res) {
        context.commit('SET_USER_NAME', res.data)
      }).catch(function (error) {
        console.info(error)
      })
    }
  },
  getters: {
    username: (state) => state.username === '暂无用户名,请获取数据' ? state.username : '用户名:[' + state.username + ']'
  }
})

export default store

  

ps:
a.getters中的username方法并无实际作用,只是演示计算生成新的一个状态数据
b.username用了es6的箭头函数;等价于:
username(state){
return username: (state) => state.username === '暂无用户名,请获取数据' ? state.username : '用户名:[' + state.username + ']'
}

4.main.js中注入store;关键代码

import store from '@/store/store'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App }
})

  

5.在components中新建query.vue;代码如下:

<template>
  <div>
    <span>{{ this.$store.getters.username }}</span>
    <input type="text" v-model="id" />
    <button @click="$store.dispatch('getData', id)">获取数据</button>
  </div>
</template>

<script>
export default {
  data () {
    return {id: 0}
  }
}
</script>

  

6.在App.vue中:

<template>
  <div id="app">
    <img src="./assets/logo.png">
    <span>{{ $store.getters.username }}</span>
    <query></query>
  </div>
</template>

<script>
import query from '@/components/query'
export default {
  methods: {

  },
  components: {
    query
  }
}
</script>

  

至此完成了一个简单的示例

输入id,点击获取数据后

 

四.继续改进(引入mapState)

以上就是基本的用法,但还有些瑕疵,我们继续改进:

1.上面的示例中,在query.vue中我们常见的应该是用computed属性去访问state,因为它是依赖缓存的;代码改进如下:

<template>
  <div>
    <span>比较好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <input type="text" v-model="id" />
    <button @click="$store.dispatch('getData', id)">获取数据</button>
  </div>
</template>

<script>
export default {
  data () {
    return {id: 0}
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    username () {
      return this.$store.state.username
    }
  }
}
</script>

  

ps:可以看到我们定义了两个computed属性,humanUserName和username;前者从store的getters取数据,后者直接从state取数据.

2.我们在store.js中再增加一些状态:

const store = new Vuex.Store({
  state: {
    username: '暂无用户名,请获取数据',
    sex: '未知',
    age: '0'
  },
  ...........................
})

  

3.在query.vue中我们仍然打印这些状态:

<template>
  <div>
    <span>比较好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <span>性别: {{ sex }}</span>
    <br>
    <span>年龄: {{ age }}</span>
    <input type="text" v-model="id" />
    <button @click="$store.dispatch('getData', id)">获取数据</button>
  </div>
</template>

<script>
export default {
  data () {
    return {id: 0}
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    username () {
      return this.$store.state.username
    },
    age () {
      return this.$store.state.age
    },
    sex () {
      return this.$store.state.sex
    }
  }
}
</script>

  

你会发现现在的代码变的冗长了,原因在于我们在computed挨个获取state;改进这一点

 

4.使用Vuex的mapState来改进,改进部分代码如下

<script>
import {mapState} from 'vuex'
export default {
  data () {
    return {id: 0}
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    ...mapState({
      username: 'username', // 'username' 直接映射到state 对象中的username, 它相当于 this.$store.state.username,
      age: 'age',
      sex: 'sex'
    })
  }
}
</script>

  

ps:
在...mapState前面的...叫做扩展运算符

五.继续改进

当然<button @click="$store.dispatch('getData', id)">获取数据</button>这个也不是很好,应该将他放入组件的methods中

1.改进代码如下:

<template>
  <div>
    <span>比较好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <span>性别: {{ sex }}</span>
    <br>
    <span>年龄: {{ age }}</span>
    <input type="text" v-model="id" />
    <button @click="getRemoteData()">获取数据</button>
  </div>
</template>

<script>
import {mapState} from 'vuex'
export default {
  data () {
    return {id: 0}
  },
  methods: {
    getRemoteData () {
      this.$store.dispatch('getData', this.id)
    }
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    ...mapState({
      username: 'username', // 'username' 直接映射到state 对象中的username, 它相当于 this.$store.state.username,
      age: 'age',
      sex: 'sex'
    })
  }
}
</script>

  

2.如果有十个dispatch,this.$store.dispatch('XXX', XXX)这样的代码势必要写十遍;可以使用...mapActions,改进部分代码如下:

<template>
  <div>
    <span>比较好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <span>性别: {{ sex }}</span>
    <br>
    <span>年龄: {{ age }}</span>
    <input type="text" v-model="id" />
    <button @click="getRemoteData(id)">获取数据</button>
  </div>
</template>

<script>
import {mapState, mapActions} from 'vuex'
export default {
  data () {
    return {id: 0}
  },
  methods: {
    ...mapActions({getRemoteData: 'getData'})
    /*
    如果名称相同,可以直接写成,...mapActions(['getData'])
    */
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    ...mapState({
      username: 'username', // 'username' 直接映射到state 对象中的username, 它相当于 this.$store.state.username,
      age: 'age',
      sex: 'sex'
    })
  }
}
</script>

  

然还有个...mapGetters,用法和mapState,mapActions是一样的,在此不做介绍了.

五.增加一个loading提示

现在似乎是完善了,但忽略了一点是,我们的数据是从服务器获取的,所以为了好的用户体验,应该加个loading.在获取数据的时候显示,获取完了隐藏.

1.store.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import qs from 'qs'

Vue.use(Vuex)
axios.defaults.baseURL = '/api'

const store = new Vuex.Store({
  state: {
    username: '暂无用户名,请获取数据',
    sex: '未知',
    age: '0',
    waiting: false // loading状态
  },
  mutations: {
    SET_USER_NAME (state, user) {
      state.username = user.name
    },
    // 显示和隐藏waiting
    SHOW_WAITING_MESSAGE (state) {
      state.waiting = true
    },
    HIDE_WAITING_MESSAGE (state) {
      state.waiting = false
    }
  },
  actions: {
    getData ({commit}, id) {
      commit('SHOW_WAITING_MESSAGE')
      axios.post(
        'http://127.0.0.1:9000/mobile/info',
        qs.stringify({id: id})
      ).then(function (res) {
        commit('HIDE_WAITING_MESSAGE')
        commit('SET_USER_NAME', res.data)
      }).catch(function (error) {
        console.info(error)
      })
    }
  },
  getters: {
    username: (state) => state.username === '暂无用户名,请获取数据' ? state.username : '用户名:[' + state.username + ']'
  }
})

export default store

  

2.query.vue

<template>
  <div>
    <span v-if="show">正在加载....</span>
    <br>
    <span>比较好看的username:{{ humanUserName }}</span>
    <br>
    <span>普通的username:{{ username }}</span>
    <br>
    <span>性别: {{ sex }}</span>
    <br>
    <span>年龄: {{ age }}</span>
    <input type="text" v-model="id" />
    <button @click="getRemoteData(id)">获取数据</button>
  </div>
</template>

<script>
import {mapState, mapActions} from 'vuex'
export default {
  data () {
    return {id: 0}
  },
  methods: {
    ...mapActions({getRemoteData: 'getData'})
    /*
    如果名称相同,可以直接写成,...mapActions(['getData'])
    */
  },
  computed: {
    humanUserName () {
      return this.$store.getters.username
    },
    ...mapState({
      username: 'username', // 'username' 直接映射到state 对象中的username, 它相当于 this.$store.state.username,
      age: 'age',
      sex: 'sex',
      show: 'waiting'
    })
  }
}
</script>

  

ps:对于store中的actions中的方法

getData (context, id) {
......
}

  

会自动获得一个默认参数context,它是一个store 实例,通过它可以获取到store 实例的属性和方法,如 context.state 就会获取到 state 属性, context.commit 就会执行commit命令.其实actions 还可以简写一下, 因为函数的参数是一个对象,函数中用的是对象中一个方法,我们可以通过对象的解构赋值直接获取到该方法。可以修改如下

getData ({commit}, id) {
......
}

  

本文参考了:

http://www.cnblogs.com/SamWeb/p/6527240.html

https://segmentfault.com/a/1190000009404727

转载于:https://www.cnblogs.com/itfenqing/p/7401857.html

<think>好的,用户需要关于Vuex示例代码和使用教程。首先,我要回忆Vuex的基本概念和核心模块,比如state、mutations、actions、getters和modules。用户提到了几个引用,其中引用[3]提供了基本的store配置,可能可以从中提取示例。 用户可能需要一个简单示例来展示如何设置Vuex store,并在组件中使用它。我应该先展示如何创建store,包括state、mutations、actions和getters。然后,演示在组件中如何提交mutation或分发action,以及如何通过getters访问状态。 接下来,用户可能对模块化感兴趣,尤其是较大的项目。引用[3]中的settings模块可以作为例子,我需要说明如何将模块整合到主store中,并保持结构清晰。 另外,用户提到的严格模式问题在引用[2]中,当使用v-model直接绑定state时会出现问题。这需要解释为什么在严格模式下不能直接修改state,并提供解决方案,比如使用计算属性的getter和setter,或者在表单处理时显式提交mutation。 可能还需要提及vuex-along插件(引用[1]),用于状态持久化,这是一个实用的优化点,用户可能想知道如何保存和恢复Vuex状态。 最后,确保代码示例符合Vuex的最佳实践,比如使用actions处理异步操作,mutations处理同步状态变更。同时,提醒用户安装Vuex并正确配置store实例。 检查是否所有示例都正确使用$...$和$$...$$格式,但根据用户的问题,可能主要是代码块,所以需要正确使用Markdown代码语法。不过用户提供的引用中并没有数学公式,所以可能不需要处理LaTeX数学表达式。但根据系统级指令,如果有行内变量如变量名,可能需要用$包裹,比如$store。 现在需要组织这些内容,分步骤讲解,确保结构清晰,并回答相关问题,帮助用户深入理解Vuex的使用和常见问题。</think>### Vuex 核心用法示例 1. **基础Store创建**(基于引用[3]优化) ```javascript // store/index.js import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) const state = { count: 0, user: { name: 'Guest' } } const mutations = { INCREMENT(state) { state.count++ }, SET_USER(state, payload) { state.user = payload } } const actions = { async fetchUser({ commit }, userId) { const user = await api.getUser(userId) commit('SET_USER', user) } } const getters = { welcomeMessage: state => `欢迎, ${state.user.name}` } export default new Vuex.Store({ state, mutations, actions, getters }) ``` 2. **组件中使用**(配合严格模式解决方案[^2]) ```vue <template> <div> <p>{{ welcome }}</p> <input :value="userName" @input="updateName"> <button @click="addCount">计数: {{ count }}</button> </div> </template> <script> export default { computed: { count() { return this.$store.state.count }, welcome() { return this.$store.getters.welcomeMessage }, userName: { get() { return this.$store.state.user.name }, set(value) { this.$store.commit('SET_USER', { name: value }) } } }, methods: { addCount() { this.$store.commit('INCREMENT') }, updateName(e) { this.userName = e.target.value } } } </script> ``` 3. **模块化示例**(扩展引用[3]) ```javascript // store/modules/products.js export default { namespaced: true, state: { items: [] }, mutations: { SET_ITEMS(state, items) { state.items = items } } } // 主store配置 import products from './modules/products' export default new Vuex.Store({ modules: { products } }) ``` 4. **状态持久化**(结合引用[1]) ```bash npm install vuex-along ``` ```javascript import VuexAlong from 'vuex-along' export default new Vuex.Store({ // ...其他配置 plugins: [VuexAlong({ local: { list: ['products'] } // 持久化products模块 })] }) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值