Version: Next
Vuex
组件之间共享数据,抽离共享数据
存储全局数据
项目中的
store
目录index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 放置全局状态
state: {
},
// 计算属性
getters:{
},
// 修改数据/状态的方法methods
// payload就是commit调用时候的第二个参数
mutations: { // 相当于methods
},
// 异步修改数据,放ajax请求
actions: {
},
// vuex细分模块,额外的全局状态
modules: {
}
})
设置一个全局用户
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 放置全局状态
state: {
username: "bb",
age: 18
},
// 计算属性
getters:{
},
// 修改数据/状态的方法methods
// payload就是commit调用时候的第二个参数
mutations: { // 相当于methods
},
// 异步修改数据,放ajax请求
actions: {
},
// vuex细分模块,额外的全局状态
modules: {
}
})
读取全局数据
在页面中显示这个全局用户
- 配置一个路由
{
path: '/user',
name: 'user',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/user.vue')
}
- 页面组件
- 可以查看
this.$store.state
其中有全局参数
- 可以查看
<template>
<div>
<h1>姓名:{ {$store.state.username} }</h1>
<h2>年龄:{ {$store.state.age} }</h2>
</div>
</template>
<script>
export default {
mounted() {
console.log(this)
}
}
</script>
修改全局数据
写一个按钮,触发事件增加年龄
这个事件的方法不能写在组件的methods里,应当写到vuex,即store目录的index.js中的mutations
中
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 放置全局状态
state: {
username: "bb",
age: 18
},
// 计算属性
getters:{
},
// 修改数据/状态的方法methods
// payload就是commit调用时候的第二个参数
mutations: { // 相当于methods
addAge(state, payload){
// console.log(state)
state.age += payload
}
},
// 异步修改数据,放ajax请求
actions: {
},
// vuex细分模块,额外的全局状态
modules: {
}
})
- 页面触发vuex中的方法
- 使用
this.$store.commit("vuex中方法名", payload)
触发vuex中的mutations
方法
- 使用
<template>
<div>
<h1>姓名:{ {$store.state.username} }</h1>
<h2>年龄:{ {$store.state.age} }</h2>
<button @click="addAge">点我增加年龄</button>
</div>
</template>
<script>
export default {
mounted() {
console.log(this)
},
methods: {
addAge:function(){
this.$store.commit('addAge',10)
}
}
}
</script>
vuex计算属性
利用
getters
,计算当前用户的虚岁
getters:{
xuAge:function(state){
return state.age + 1
}
}
- 页面
- 从
$store.getters
中拿数据,而不是state
中
- 从
<template>
<div>
<h1>姓名:{ {$store.state.username} }</h1>
<h2>年龄:{ {$store.state.age} }</h2>
<h2>虚岁:{ {$store.getters.xuAge} }</h2>
<button @click="addAge">点我增加年龄</button>
</div>
</template>
<script>
export default {
mounted() {
console.log(this)
},
methods: {
addAge:function(){
this.$store.commit('addAge',10)
}
}
}
</script>
vuex异步修改——actions
请求服务器,服务器响应了一些信息info,用一个List来存储
- 通过浏览器查看响应信息,发现数据封装在
response.result
中
访问https://api.apiopen.top/getJoke?page=1&count=10&type=text
得到json响应
- JSON响应
{
"code": 200,
"message": "成功!",
"result": [
{
"sid": "31287755",
"text": "和哥们去一个经常去的小饭馆吃饭,因为经常去所以特别熟!吃完饭结账时104块钱,我和老板说:打个把零抹了吧?\n\n老板:卧槽,抹零可不行,给你抹四块吧!\n我。。。",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "61",
"down": "5",
"forward": "0",
"comment": "0",
"uid": "16673240",
"name": "不得姐用户",
"header": "http://wimg.spriteapp.cn/profile",
"top_comments_content": null,
"top_comments_voiceuri": null,
"top_comments_uid": null,
"top_comments_name": null,
"top_comments_header": null,
"passtime": "2020-05-14 23:22:01"
},
{
"sid": "31283145",
"text": "昨晚预约了快递上门取件还预点了早餐,结果早上睡太死外卖打电话没听见,直接给我放门口窗台了,后来快递员来取件把我外卖寄走了",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "72",
"down": "6",
"forward": "1",
"comment": "0",
"uid": "20271806",
"name": "索月哒香",
"header": "http://wimg.spriteapp.cn/profile",
"top_comments_content": null,
"top_comments_voiceuri": null,
"top_comments_uid": null,
"top_comments_name": null,
"top_comments_header": null,
"passtime": "2020-05-14 22:26:02"
},
{
"sid": "31385676",
"text": "老王:“大湿,你是怎么看待网上的女神?”\n大湿:“她们就像是方便面。”\n老王:“大湿的意思是用来泡的?”\n大湿:“不,图片仅供参考。”",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "63",
"down": "5",
"forward": "0",
"comment": "0",
"uid": "11996791",
"name": "Pescado",
"header": "http://wimg.spriteapp.cn/profile/large/2019/02/10/5c6015142adc7_mini.jpg",
"top_comments_content": null,
"top_comments_voiceuri": null,
"top_comments_uid": null,
"top_comments_name": null,
"top_comments_header": null,
"passtime": "2020-05-13 23:22:01"
},
{
"sid": "31383147",
"text": "妻子下班回家忘记带钥匙,就喊老公开门。老公就逗她:“请输入密码。” 老婆说:“我是你女人!” 老公:“密码错误,请重新输入!” 老婆:“你欠扁啊!” 老公:“密码正确,登录成功。”",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "64",
"down": "5",
"forward": "0",
"comment": "0",
"uid": "11996791",
"name": "Pescado",
"header": "http://wimg.spriteapp.cn/profile/large/2019/02/10/5c6015142adc7_mini.jpg",
"top_comments_content": null,
"top_comments_voiceuri": null,
"top_comments_uid": null,
"top_comments_name": null,
"top_comments_header": null,
"passtime": "2020-05-13 22:26:01"
},
{
"sid": "31382103",
"text": "同学聚会的时候,个个同学都在炫耀自己,我实在忍不住了,一拍桌子说:你们都不要炫耀了,我是炒股的,这下没有一个同学敢说话,还抢着买单,大家知道为什么吗?",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "63",
"down": "7",
"forward": "0",
"comment": "2",
"uid": "5600770",
"name": "八年多的小姐夫",
"header": "http://wimg.spriteapp.cn/profile/large/2019/08/05/5d483867a3935_mini.jpg",
"top_comments_content": null,
"top_comments_voiceuri": null,
"top_comments_uid": null,
"top_comments_name": null,
"top_comments_header": null,
"passtime": "2020-05-13 21:30:01"
},
{
"sid": "31295272",
"text": "生活不止眼前的苟且,还有百思不得姐",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "92",
"down": "5",
"forward": "0",
"comment": "5",
"uid": "22954227",
"name": "自嘲mB9",
"header": "http://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJ3iajhaItniclpvRQGoJmZ8nD3OUCmqZkmJlqdXstxmbiaWzwDGnAumTRbxLiblbH31jBOc2Tp4Jjzcw/132",
"top_comments_content": null,
"top_comments_voiceuri": null,
"top_comments_uid": null,
"top_comments_name": null,
"top_comments_header": null,
"passtime": "2020-05-04 23:22:02"
},
{
"sid": "31260758",
"text": "最近谈了个女友,她家里人不同意,就想办法解决,白天用弹弓打她家烟筒,晚上拿砖头砸她家玻璃,最后,她爹和她哥把我打了一顿。直到村长出面,让她妈妈承诺把闺女嫁给我,才从医院出院回家。别说我赖皮,老祖宗传下来的苦肉计,还是挺管用的。",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "62",
"down": "0",
"forward": "0",
"comment": "1",
"uid": "23189155",
"name": "大王",
"header": "http://wimg.spriteapp.cn/profile/large/2019/12/24/5e0193452b0b5_mini.jpg",
"top_comments_content": null,
"top_comments_voiceuri": null,
"top_comments_uid": null,
"top_comments_name": null,
"top_comments_header": null,
"passtime": "2020-05-03 23:56:01"
},
{
"sid": "31273699",
"text": "和闺蜜一起看宫斗剧,我就问闺蜜: 你看,以我的智商,在皇宫里能活几集?闺蜜却说: 就你这身材和颜值,根本进不了宫!我……",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "65",
"down": "6",
"forward": "0",
"comment": "1",
"uid": "23133388",
"name": "小雪转大雪",
"header": "http://wimg.spriteapp.cn/profile/large/2019/07/04/5d1da00325802_mini.jpg",
"top_comments_content": null,
"top_comments_voiceuri": null,
"top_comments_uid": null,
"top_comments_name": null,
"top_comments_header": null,
"passtime": "2020-05-02 23:22:01"
},
{
"sid": "31272902",
"text": "老公:我也不是不讲理的人,你就不能解释几句?我:那好,你听我解释……老婆:你做的破事儿还有脸解释?我。。。",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "67",
"down": "4",
"forward": "0",
"comment": "4",
"uid": "23128117",
"name": "懒懒的雾",
"header": "http://wimg.spriteapp.cn/profile/large/2019/07/04/5d1d70444877d_mini.jpg",
"top_comments_content": "老公?老婆?我?这三个人到底什么关系?",
"top_comments_voiceuri": "",
"top_comments_uid": "20015605",
"top_comments_name": "Demaxiya",
"top_comments_header": "http://wimg.spriteapp.cn/profile/large/2019/09/06/5d7270dabe23b_mini.jpg",
"passtime": "2020-05-02 22:26:01"
},
{
"sid": "31272401",
"text": "出去遛狗的时候因为裤子没口袋,我灵机一动把钥匙别在狗项圈上了。半路这货竟然把绳子挣断了,然后跑了!已经半夜了,这货还不回来,我今晚怎么办啊?",
"type": "text",
"thumbnail": null,
"video": null,
"images": null,
"up": "69",
"down": "8",
"forward": "0",
"comment": "2",
"uid": "23125873",
"name": "掉毛的加菲",
"header": "http://wimg.spriteapp.cn/profile/large/2019/07/04/5d1d6aada294a_mini.jpg",
"top_comments_content": null,
"top_comments_voiceuri": null,
"top_comments_uid": null,
"top_comments_name": null,
"top_comments_header": null,
"passtime": "2020-05-02 21:30:02"
}
]
}
- vuex->store->index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
// 放置全局状态
state: {
username: "bb",
age: 18,
list: [] // 存储响应的数据
},
// 计算属性
getters:{
xuAge:function(state){
return state.age + 1
}
},
// 修改数据/状态的方法methods
// payload就是commit调用时候的第二个参数
mutations: { // 相当于methods
addAge(state, payload){
// console.log(state)
state.age += payload
},
getList(state,payload){
// actions异步请求,通过comtext.commit触发这个方法
// 修改store中的list值为服务器的响应值
state.list = payload
}
},
// 异步修改数据,放ajax请求
actions: {
// 请求服务器
requestInfo(context) {
// ES6原生请求方法
let httpUrl = "https://api.apiopen.top/getJoke?page=1&count=10&type=text"
fetch(httpUrl).then((response) => {
return response.json(); // 转为json返回
}).then((response => {
// 第二次then拿到的就是json对象
console.log(response);
// 将响应的数据存储到全局数据中
// 要修改全局数据,需要在mutations中设置方法,通过这个方法修改store的值
//要触发mutations中的方法,需要使用context.commit方法
context.commit('getList',res.result)
}))
}
},
// vuex细分模块,额外的全局状态
modules: {
}
})
在组件中使用
dispatch()
触发vuex中的actions
异步方法
- 使用列表显示vuex中的全局List
<template>
<div>
<h1>姓名:{ {$store.state.username} }</h1>
<h2>年龄:{ {$store.state.age} }</h2>
<h2>虚岁:{ {$store.getters.xuAge} }</h2>
<button @click="addAge">点我增加年龄</button>
<!-- 从vuex中取出异步请求响应的list -->
<ul>
<li v-for="(item, i) in $store.state.list" :key="i">
<h3>{ {item.name} }</h3>
<p>{ {item.text} }</p>
</li>
</ul>
</div>
</template>
<script>
export default {
mounted() {
console.log(this)
// 触发vuex的action方法
this.$store.dispatch('requestInfo')
},
methods: {
addAge:function(){
this.$store.commit('addAge',10)
}
}
}
</script>
辅助函数
简化
$store.state.属性名
这种写法
针对属性
mapState
mapGetters
针对方法
mapMutations
mapActions
- 页面组件
- 在script中引入四个辅助函数
- 解构: 用
...
关键字解构- 在组件的
methods
中解构mapActions
和mapMutations
因为它们对应Vuex中的方法 - 在组件的
computed
中解构mapState
和mapGetters
,因为它们对应vuex中的属性
- 在组件的
- 调用显示:直接使用
参数名
而不再使用$store.state.参数名
<template>
<div>
<h1>姓名:{ {$store.state.username} }</h1>
<h2>年龄:{ {$store.state.age} }</h2>
<h2>虚岁:{ {$store.getters.xuAge} }</h2>
<button @click="addAge">点我增加年龄</button>
<!-- 辅助函数下的用法 -->
<h1>姓名:{ {username} }</h1>
<h2>年龄:{ {age} }</h2>
<h2>虚岁:{ {xuAge} }</h2>
<!-- 从vuex中取出异步请求响应的list -->
<ul>
<li v-for="(item, i) in $store.state.list" :key="i">
<h3>{ {item.name} }</h3>
<p>{ {item.text} }</p>
</li>
</ul>
</div>
</template>
<script>
// 辅助函数
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
mounted() {
console.log(this)
// 触发vuex的action方法
this.$store.dispatch('requestInfo')
},
methods: {
addAge:function(){
this.$store.commit('addAge',10)
}
},
computed: {
...mapState(['username', 'age', 'list']),
...mapGetters(['xuAge'])
}
}
</script>
- 针对方法
在原先的methods中,为了调用vuex中的mutations方法,用了如下的写法
methods: {
addAge:function(){
this.$store.commit('addAge',10)
}
}
可以看到,定义了一个addAge
方法,进去又调了vuex mutations的addAge
方法,显然这个步骤可以省略一下
利用mapMutations
- 原先的形参
10
,改到绑定事件的位置写
...mapMutations(['addAge'])
<!-- 参数改到这里写 -->
<button @click="addAge(20)">点我增加年龄</button>
- 组件页面
<template>
<div>
<h1>姓名:{ {$store.state.username} }</h1>
<h2>年龄:{ {$store.state.age} }</h2>
<h2>虚岁:{ {$store.getters.xuAge} }</h2>
<!-- 参数改到这里写 -->
<button @click="addAge(20)">点我增加年龄</button>
<!-- 辅助函数下的用法 -->
<h1>姓名:{ {username} }</h1>
<h2>年龄:{ {age} }</h2>
<h2>虚岁:{ {xuAge} }</h2>
<!-- 从vuex中取出异步请求响应的list -->
<ul>
<li v-for="(item, i) in $store.state.list" :key="i">
<h3>{ {item.name} }</h3>
<p>{ {item.text} }</p>
</li>
</ul>
</div>
</template>
<script>
// 辅助函数
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
mounted() {
console.log(this)
// 触发vuex的action方法
this.$store.dispatch('requestInfo')
},
methods: {
...mapMutations(['addAge', 'getList'])
},
computed: {
...mapState(['username', 'age', 'list']),
...mapGetters(['xuAge'])
}
}
</script>
对于vuex中actions方法的调用
- 现在组件methods中使用
...mapActions
写actions中的方法 - 接下来,在组件生命周期函数中,用
this.actions方法名
调用vuex的actions方法
<template>
<div>
<h1>姓名:{ {$store.state.username} }</h1>
<h2>年龄:{ {$store.state.age} }</h2>
<h2>虚岁:{ {$store.getters.xuAge} }</h2>
<!-- 参数改到这里写 -->
<button @click="addAge(20)">点我增加年龄</button>
<!-- 辅助函数下的用法 -->
<h1>姓名:{ {username} }</h1>
<h2>年龄:{ {age} }</h2>
<h2>虚岁:{ {xuAge} }</h2>
<!-- 从vuex中取出异步请求响应的list -->
<ul>
<li v-for="(item, i) in $store.state.list" :key="i">
<h3>{ {item.name} }</h3>
<p>{ {item.text} }</p>
</li>
</ul>
</div>
</template>
<script>
// 辅助函数
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
mounted() {
console.log(this)
// 触发vuex的action方法
// this.$store.dispatch('requestInfo')
this.requestInfo();
},
methods: {
// 映射vuex actions方法
...mapActions(['requestInfo']),
...mapMutations(['addAge', 'getList'])
},
computed: {
...mapState(['username', 'age', 'list']),
...mapGetters(['xuAge'])
}
}
</script>
Vuex模块
一个Vuex不够用,可以再细分
在vuex的js文件中,再整一个Vuex模块mall
// vuex细分模块
modules: {
mall,
}
- 新建一个
mall.js
export default {
state:{
mallname:"商城的名字"
},
mutations: {
setMallName:function(state, payload) {
state.mallname = payload;
}
}
}
- 在vuex默认的index.js中,导入
mall.js
import mall from './mall'
在页面中使用vuex模块中的数据
- 使用
mapState
导入子vuex模块,使用模块名.属性名
调用 - 使用
mapMutations
导入子vuex模块的方法,注意不需要写模块名,直接写方法名即可
<template>
<div>
<!-- vuex mall模块中的数据 mall模块的mallname-->
<!-- vuex mall模块中的方法被调用-->
<h1 @click="setMallName("改名商城")">{ {mall.mallname} }</h1>
<h1>姓名:{ {$store.state.username} }</h1>
<h2>年龄:{ {$store.state.age} }</h2>
<h2>虚岁:{ {$store.getters.xuAge} }</h2>
<!-- 参数改到这里写 -->
<button @click="addAge(20)">点我增加年龄</button>
<!-- 辅助函数下的用法 -->
<h1>姓名:{ {username} }</h1>
<h2>年龄:{ {age} }</h2>
<h2>虚岁:{ {xuAge} }</h2>
<!-- 从vuex中取出异步请求响应的list -->
<ul>
<li v-for="(item, i) in $store.state.list" :key="i">
<h3>{ {item.name} }</h3>
<p>{ {item.text} }</p>
</li>
</ul>
</div>
</template>
<script>
// 辅助函数
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
mounted() {
console.log(this)
// 触发vuex的action方法
// this.$store.dispatch('requestInfo')
this.requestInfo();
},
methods: {
// 映射vuex actions方法
...mapActions(['requestInfo']),
//...mapMutations(['addAge', 'getList'])
// 导入mall模块中的mutations方法,注意不需要写模块的名字mall
...mapMutations(['addAge', 'getList', 'setMallName'])
},
computed: {
// ...mapState(['username', 'age', 'list']),
// 导入vuex index.js下的vuex模块mall
...mapState(['username', 'age', 'list', 'mall']),
...mapGetters(['xuAge'])
}
}
</script>
带命名空间的子模块
- Vuex子模块
export default {
namespaced:true,
state:{
luntan:"论坛"
},
mutations:{
setLuntan:function(state, payload){
state.luntan = payload
}
}
}
- 主vuex index.js导入
import luntan from './luntan'
- 页面组件
methods:{
...mapActions(['getJoke']),
...mapMutations(['addAge','getList','setMallname']),
// 命名空间写法
...mapMutations('luntan',['setLuntan'])
},
computed:{
...mapState(['username','age','list','mall']),
...mapGetters(['xuAge']),
// 命名空间的写法
...mapState('luntan',['luntan'])
}
显示调用
<h1 @click="setLuntan('论坛')">{ {luntan} }</h1>