Vuex
概念:状态管理模式
中文学习网址:
https://vuex.vuejs.org/zh/
安装:
npm install vuex --save(或 -S)
引用:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
其解决了组件数据复杂传值的问题 更符合单项数据流:
view -----------> actions
<---state<-----
其将组件中的data抽离出来 不在组件中大量的使用data
使用状态管理器:
1、新建文件夹及文件src/store/index.js
index.js
import Vue from 'vue'
import VueX from 'vueX'
Vue.use(VueX)
const store = new VueX.Store({
modules: {
}
})
export default store // 暴露模块
main.js
import store from '@/store' // 引入要使用的vueX的模块
new Vue({
el: '#app',
store, // 在此调用模块 在任何一个组件中都可以用this.$store访问
2、以分类页面为例 练习使用vueX
注:以前的数据是存在vue文件下 export default { data () { return{ 该处存放数据 }}}
现在将数据放在如下文件中
新建文件夹及文件src/store/kind/index.js
const store = {
state: { // 存放页面的状态
},
getters: { // 状态的衍生值 其实就是state的计算属性
},
actions: { // 处理组件中的异步操作
},
mutations: { // 唯一改变当前页面的状态的地方
}
}
export default store
3、在store/index.js引入关于分类页面的状态管理
import kindStore from './kind'
modules: {
kindStore
}
4、定义更改状态的方法
store/kind/index.js
state: {
bannerdata: ['banner1','banner2'],
prolist: ['pro1','pro2']
},
mutations: {
changeBannerData (state, data) { // state就是上面代码的state
state.bannerdata = data // 改变状态管理器中的数据
},
changeProList (state, data) {
state.prolist = data
}
}
5、将初始化数据渲染到页面中
kind.vue
computed: { // 计算属性
bannerdata () {
return this.$store.state.kindStore.bannerdata
},
{{bannerdata}}
6、使用mapState辅助函数结合计算属性获取状态
export default {
name: 'kind',
computed: { // 计算属性
...mapState({ // 使用对象展开运算符 会将此对象混入到外部对象中
bannerdata: state => state.kindStore.bannerdata,
prolist: state => state.kindStore.prolist
})
{{bannerdata}}
7、请求数据渲染
新建src/api/kind/index.js — 用来请求数据
import axios from 'axios'
const api = {
requestdata (url) {
return new Promise((resolve, reject) => {
axios.get(url).then(data => {
console.log(data.data)
resolve(data.data)
}).catch(err => reject(err))
})
}
}
export default api
kind.vue
import api from '@/api/kind'
export default {
……
created () { // vue的生命周期钩子函数
api.reqestdata('https://www.daxunxun.com/douban')
.then(data => {
this.$store.commit('changeProList', data) // 会触发api/kind/index.js中mutations-->changeProList方法
this.$store.commit('changeBannerData', data)
})
}
以上请求的数据会被渲染到store/kind/index.js中
state: {
bannerdata: ['banner1', 'banner2'], 数据同步到该处
抽离异步请求
kind.vue
注释如下代码
// import api from '@/api/kind'
created () { // vue的生命周期钩子函数
// api.reqestdata('https://www.daxunxun.com/douban')
// .then(data => {
// this.$store.commit('changeProList', data) // 会触发api/kind/index.js中mutations-->changeProList方法
// this.$store.commit('changeBannerData', data)
// })
//在钩子函数中添加该话执行异步请求 执行下段代码中的函数
this.$store.dispatch('requestBannerdata')
this.$store.dispatch('requestProlist')
}
即异步请求不在vue文件中执行了
src/store/kind/index.js
const store = {
……
actions: { // 处理组件中的异步操作 将请求放在该处
requestBannerdata (context) {
api.requestdata('https://www.daxunxun.com/banner').then(data => {
console.log(data)
context.commit('changeBannerData', data) // 会触发api/kind/index.js中mutations-->changeProList方法
})
},
requestProlist (context) {
api.requestdata('https://www.daxunxun.com/douban').then(data => {
console.log(data)
context.commit('changeProList', data)
})
}
},
使用mapAction分发action
以前分发action的方式为:
kind.vue
created () { // vue的生命周期钩子函数
this.$store.dispatch('requestBannerdata')
this.$store.dispatch('requestProlist')
}
修改代码为:
kind.vue
import { mapState, mapActions } from 'vuex' // 引入mapActions
export default {
……
created () { // vue的生命周期钩子函数
this.requestBannerdata()
this.requestProlist()
},
methods: {
...mapActions([
'requestBannerdata',
'requestProlist'
])
}
}
getters的使用
src/store/kind/index.js
const store = {
……
getters: { // 状态的衍生值 其实就是state的计算属性
year1994 (state) {
return state.prolist.filter(item => { // 过滤上面state中prolist数组的值
if (item.year >= 1994) {
return true // 返回true 得到满足条件的值
}
})
}
},
kind.vue
// mapGetters 用来获取vuex中的getters
import { ……, mapGetters } from 'vuex'
export default {
……
computed: { // 计算属性
// year1994 () {
// return this.$store.getters.year1994
// }, 或者如下
// ...mapGetters({
// year1994: 'year1994'
// }),或者如下
...mapGetters(['year1994']),
通过状态管理实现购物车
新建文件夹及文件
src/api/cart/index.js 代码如下
const api = {
requestdata () {
const cartArr = [ // 模拟数据
{
id: 1,
name: '方便面',
num: 3,
price: 1,
flag: false // 该属性用来判断是否被选中
},
{
id: 2,
name: '火腿',
num: 5,
price: 3,
flag: false // 该属性用来判断是否被选中
},
{
id: 3,
name: '面包',
num: 2,
price: 10,
flag: false // 该属性用来判断是否被选中
}
]
return new Promise((resolve, reject) => {
// 模拟请求成功后的数据
resolve(cartArr)
})
}
}
export default api
新建文件夹及文件
src/store/cart/index.js 代码如下
import api from '@/api/cart'
const store = {
state: { // 存放页面的状态
cartlist: []
},
getters: { // 状态的衍生值 其实就是state的计算属性
totalPrice (state) { // 计算总价格
return state.cartlist.reduce((sum, item) => {
if (item.flag) { // 判断是否勾选
return sum + item.price * item.num
} else {
return sum
}
}, 0)
},
totalNum (state) { // 计算总数量
return state.cartlist.reduce((sum, item) => {
if (item.flag) { // 判断是否勾选
return sum + item.num
} else {
return sum
}
}, 0)
}
},
actions: { // 处理组件中的异步操作
requestdata (context) {
api.requestdata().then(data => {
console.log(data)
context.commit('changeCartList', data)
})
}
},
mutations: { // 唯一改变当前页面的状态的地方
changeCartList (state, data) { // state就是上面代码的state
state.cartlist = data // 改变状态管理器中的数据
}
}
}
export default store
修改Cart.vue
代码如下
<div class="content">
<ul>
<li v-for="item of cartlist" :key="item.id">
<input type="checkbox" v-model="item.flag" />
{{item.name}} ---- ¥{{item.price}} ---- {{ item.num }}
</li>
</ul>
总价格:{{ totalPrice }} ---- 总数量:{{ totalNum }}
</div>
import {mapState, mapActions, mapGetters} from 'vuex'
export default {
computed: { // 计算属性
...mapState({
cartlist: state => state.cartStore.cartlist
}),
...mapGetters(['totalPrice', 'totalNum'])
},
methods: { // 方法
...mapActions(['requestdata'])
},
created () {
this.requestdata()
},
修改src/store/index.js
import cartStore from './cart' // 导入磨矿
const store = new VueX.Store({
modules: {
kindStore,
cartStore // 在此引入
}
})
购物车实例代码下载网址入下:
https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart