1、概念:用户和视图交互更改状态的方式:actions,state:数据源,view:以声明方式将state映射到视图,数据的流向是单向的如下图:
2、组件间通信:a.父子组件通信:子组件给父组件传值:props/$emit---在父组件中可以通过@eventa="参数1+=$event"获取值也可以通过正常的函数形参获取值,
b.其他组件间传值(自定义事件):常用eventBus其他$parent,$root,$children,$refs等,
3、vuex适用场景:a.多个视图以来同一状态,b.来自不同视图的行为需要变更同一状态
4、核心概念:store:容器,state:数据源(状态--响应式的),getter:内部对状态缓存只有数据改变时,才会重新计算,mutation:状态改变的提交,action:状态改变的提交(可以进行异步的操作),并最终还是提交到mutation,module:模块,如果数据过多可以分成多个module,每个module中有自己的state,getter,mutation,action以及潜逃的子模块
5、state的使用:a.在computed中使用
<div>
{{count}}
{{msg}}
</div>
<div>
{{num}}
{{message}}
</div>
import { mapState } from 'vuex'
export default{
computed:{
// count:state=>state.count
... mapState(['count','msg']) // count ,msg是在vuex中定义的数据
/***
将vuex中的count和msg赋给两个变量num和message
**/
... mapState({ num:'count', message: 'msg'})
}
}
b.直接获取使用:
<div>
{{ $store.state.count }}
{{ $store.state.msg }}
</div>
import { mapState } from 'vuex'
export default{
data(){
return {
count:this.$store.state.count
}
}
}
6、getter的使用(getter类似于computed):
/**vuex 的 index.js
**/
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.store({
state:{
count:0,
msg:'Hello word'
},
getters:{
reverseMsg(state){
return state.msg.split('').reverse().join('')
}
}
})
<div>
reveseMsg:{{$store.getters.reverseMsg}} // 对应mapState
reveseMsg:{{reverseMsg}} // 对应mapGetters
</div>
import { mapState,mapGetters } from 'vuex'
export default{
computed:{
...mapGetters(['reverseMsg])
}
}
7、Mutation(只支持同步的操作):有两种使用方式,方式一直接在标签中使用$store.commit('increase',2),方式二是通过引入mapMutation,并将相应的函数结构到methods中,这样在标签中可以直接使用该方法名进行触发例如...mapMutations([‘increase’]),是将mapMutations中increase函数结构到methods中这样在标签内可以如下调用<button @click="increase(2)">Mutation</button>;至于解构...mapMutations([‘increase’]),mutition也可以如getter那样以对象形式解构同样action也是如此
/**vuex 的 index.js
**/
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.store({
state:{
count:0,
msg:'Hello word'
},
getters:{
reverseMsg(state){
return state.msg.split('').reverse().join('')
}
},
mutations:{
increase(state,payload){
state.count+=payload
}
}
})
<div>
/**方式一**/
<button @click="$store.commit('increase',2)">Mutation</button>
/**方式二**/
<button @click="increase(2)">Mutation</button>
</div>
import { mapState,mapGetters,mapMutations } from 'vuex' //方式二将mapMutations放到methods中
export default{
computed:{
...mapGetters(['reverseMsg])
},
methods:{
...mapMutations([‘increase’]) //方式二将mapMutations放到methods中
}
}
8、Action(异步操作),当操作完成后需要提交变更状态的时候需要提交Mutation来修改state:action的调用需要通过dispatch
/**vuex 的 index.js
**/
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.store({
state:{
count:0,
msg:'Hello word'
},
getters:{
reverseMsg(state){
return state.msg.split('').reverse().join('')
}
},
mutations:{
increase(state,payload){
state.count+=payload
}
},
action:{
increaseAsync(context,payload){
setTimeout(()=>{
context.commit('increase',payload)
},2000)
}
}
})
<div>
/**方式一**/
<button @click="$store.dsspatch('increaseAsync',2)">Action</button>
/**方式二**/
<button @click="increaseAsync(2)">Mutation</button>
</div>
import { mapState,mapGetters,mapActions} from 'Action' //方式二将mapActions放到methods中
export default{
computed:{
...mapGetters(['reverseMsg])
},
methods:{
...mapActions([‘increaseAsync’]) //方式二将mapMutations放到methods中
}
}
9、module:目录结构如下:
/***
cart.js
***/
const state = {
cartProducts: JSON.parse(window.localStorage.getItem('cart-products')) || []
}
const getters = {
totalCount (state) {
return state.cartProducts.reduce((sum, prod) => sum + prod.count, 0)
},
totalPrice (state) {
return state.cartProducts.reduce((sum, prod) => sum + prod.totalPrice, 0)
},
checkedCount (state) {
return state.cartProducts.reduce((sum, prod) => {
if (prod.isChecked) {
sum += prod.count
}
return sum
}, 0)
},
checkedPrice (state) {
return state.cartProducts.reduce((sum, prod) => {
if (prod.isChecked) {
sum += prod.totalPrice
}
return sum
}, 0)
}
}
const mutations = {
addToCart (state, product) {
// 1. cartProducts 中没有该商品,把该商品添加到数组,并增加 count,isChecked,totalPrice
// 2. cartProducts 有该商品,让商品的数量加1,选中,计算小计
const prod = state.cartProducts.find(item => item.id === product.id)
if (prod) {
prod.count++
prod.isChecked = true
prod.totalPrice = prod.count * prod.price
} else {
state.cartProducts.push({
...product,
count: 1,
isChecked: true,
totalPrice: product.price
})
}
},
deleteFromCart (state, prodId) {
const index = state.cartProducts.findIndex(item => item.id === prodId)
index !== -1 && state.cartProducts.splice(index, 1)
},
updateAllProductChecked (state, checked) {
state.cartProducts.forEach(prod => {
prod.isChecked = checked
})
},
updateProductChecked (state, {
checked,
prodId
}) {
const prod = state.cartProducts.find(prod => prod.id === prodId)
prod && (prod.isChecked = checked)
},
updateProduct (state, {
prodId,
count
}) {
const prod = state.cartProducts.find(prod => prod.id === prodId)
if (prod) {
prod.count = count
prod.totalPrice = count * prod.price
}
}
}
const actions = {}
export default {
namespaced: true,//开启命名空间可以在使用的时候更加方便的使用解构
state,
getters,
mutations,
actions
}
/***
product.js
***/
import axios from 'axios'
const state = {
products: []
}
const getters = {}
const mutations = {
setProducts (state, payload) {
state.products = payload
}
}
const actions = {
async getProducts ({ commit }) {
const { data } = await axios({
method: 'GET',
url: 'http://127.0.0.1:3000/products'
})
commit('setProducts', data)
}
}
export default {
namespaced: true, //开启命名空间可以在使用的时候更加方便的使用解构
state,
getters,
mutations,
actions
}
/***
vuex的index.js
****/
import Vue from 'vue'
import Vuex from 'vuex'
import products from './modules/products'
import cart from './modules/cart'
Vue.use(Vuex)
const myPlugin = store => {
store.subscribe((mutation, state) => {
if (mutation.type.startsWith('cart/')) {
window.localStorage.setItem('cart-products', JSON.stringify(state.cart.cartProducts))
}
})
}
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
products,
cart
},
plugins: [myPlugin]
})
使用:
<h2>Module</h2>
/***
第一个products是模块的名字,第二个products是模块中state的属性
***/
// 方式一
products: {{ $store.state.products.products }} <br>
<button @click="$store.commit('setProducts', [])">Mutation</button>
// 方式二
products: {{ products }} <br>
<button @click="setProducts([])">Mutation</button>
computed: {
...mapState('products', ['products'])
},
methods: {
...mapMutations('products', ['setProducts'])
}
10.vuex插件:vuex插件是一个函数,其接收一个store的参数,插件:例如
/***
插件定义
***/
const myPlugin = store => {
//当store初始化后调用
store.subscribe((mutation, state) => {
/***每次mutation之后调用,mutation的格式为:{type,payload},subscribe 订阅vuex的某个动作这里
订阅的是mutation***/
if (mutation.type.startsWith('cart/')) { // mutation.type=命名空间+mutation的名字
window.localStorage.setItem('cart-products', JSON.stringify(state.cart.cartProducts))
}
})
}
插件的注册:
// 插件注册
export default new Vuex.Store({
// ...
plugins: [myPlugin]
})