一、基于VueCli自定义创建项目
233
344

二、Vuex 初始准备
建项目的时候把vuex勾选上就不用再yarn add vuex@3了

store/index.js
javascript
// 这里面存放的就是vuex相关的核心代码
import Vuex from 'vuex'
import Vue from 'vue'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store()
// 到处给main.js使用
export default store
App.vue
javascript
created () {
// console.log(this.$router) // 没配
console.log(this.$store) // 没配
},
main.js
javascript
import Vue from 'vue'
import App from './App.vue'
import store from '@/store/index'
console.log(store.state.count)
Vue.config.productionTip = false
new Vue({
render: h => h(App),
store
}).$mount('#app')
三、通过vuex仓库访问数据

(1)通过store直接访问
新建仓库数据,这样别的模块、组件都可以访问到仓库中的数据。
javascript
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 通过state可以提供数据,所有组件共享的数据
state: {
title: '大标题',
count: 100
}
}
)
例如,App.vue中的模块中(指的是template中)
javascript
<h1>根组件
--{{ $store.state.title }}
--{{ $store.state.count }}
</h1>
App.vue中的组件中(指的是script中)
javascript
created () {
console.log(this.$store.state.count) // 没配
},
Son.vue(模块template中)
javascript
从vuex中获取的值: <label>{{ $store.state.count }}</label>
main.js(js中)
javascript
console.log(store.state.count)
总结:只需要在App.vue中写好仓库,后面可以直接通过底层的逻辑去调用,即:
模板中:{{$store.state.xxx }}
组件逻辑中:this.$store.state.xxx
JS模块中:store.state.xxx
Son1.vue
javascript
<template>
<div class="box">
<h2>Son1 子组件 {{ $store.state.title }}</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<br>
<button>值 + 1</button>
</div>
</template>
<script>
export default {
name: 'Son1Com'
}
</script>
<style lang="css" scoped>
.box{
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
(2)通过辅助函数(简化)
mapState是辅助函数,帮助我们把store中的数据自动映射到组件的计算属性中

App.vue
//展示一下 不用
javascript
import { mapState } from 'vuex'
console.log(mapState(['count', 'title']))
在App.vue中这么写,就可以直接调用使用里面的值
javascript
<template>
<div id="app">
<h1>根组件
--{{ title }}
--{{ count }}
</h1>
<input type="text">
<Son1></Son1>
<hr>
<Son2></Son2>
</div>
</template>
computed: {
...mapState(['count', 'title'])
},
Son2.vue,虽然写起来简单还是需要再写一遍解构函数,即 computed: {
...mapState(['count', 'title'])
}
javascript
<template>
<div class="box">
<h2>Son2 子组件 {{ title }}</h2>
从vuex中获取的值:<label>{{ count }}</label>
<br />
<button>值 - 1</button>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'Son2Com',
computed: {
...mapState(['count', 'title'])
}
}
</script>
<style lang="css" scoped>
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
四、组件修改仓库中的数据(mutations)
(1)错误情况

javascript
<template>
<div class="box">
<h2>Son1 子组件 {{ $store.state.title }}</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<br>
<button @click="handleAdd">值 + 1</button>
</div>
</template>
<script>
export default {
name: 'Son1Com',
methods: {
handleAdd () {
// 错误代码,不会报错,并且可以实现,但其实是错的 (但是vue不会监测 监测需要成本)
// this.$store.state.count++
// console.log(this.$store.state.count)
// 应该通过mutation 核心概念 进行修改
}
}
}
</script>
<style lang="css" scoped>
.box{
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
(2)严格模式 strict:true
为了避免这种情况,方便初学者检查,我们采用严格模式。store/index.js中操作
javascript
// 这里面存放的就是vuex相关的核心代码
import Vuex from 'vuex'
import Vue from 'vue'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 严格模式(有利于初学者,检测不规范的代码 => 上线时需要关闭)
// 其实还是可以修改,只是会提示报错
strict: true,
// 通过state可以提供数据,所有组件共享的数据
state: {
title: '大标题',
count: 100
}
}
)
// 到处给main.js使用
export default store
(3)修改数据-mutations

store/index.js
javascript
// 这里面存放的就是vuex相关的核心代码
import Vuex from 'vuex'
import Vue from 'vue'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 严格模式(有利于初学者,检测不规范的代码 => 上线时需要关闭)
// 其实还是可以修改,只是会提示报错
strict: true,
// 1.通过state可以提供数据,所有组件共享的数据
state: {
title: '大标题',
count: 100
},
// 2.通过mutations可以提供修改数据的方法,mutation是一个对象
mutations: {
// 所有的mutation函数,第一个参数,都是state
addCount (state) {
// 修改数据
state.count += 1
},
addFive (state) {
// 修改数据
state.count += 5
},
changeTitle (state) {
state.title = '小标题'
}
}
}
)
// 到处给main.js使用
export default store
Son1.vue
javascript
<template>
<div class="box">
<h2>Son1 子组件 {{ $store.state.title }}</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<br>
<button @click="handleAdd">值 + 1</button>
<button @click="addFive">值 + 5</button>
<button @click="changeFn">改标题</button>
</div>
</template>
<script>
export default {
name: 'Son1Com',
methods: {
handleAdd () {
// 错误代码,不会报错,并且可以实现,但其实是错的 (但是vue不会监测 监测需要成本)
// this.$store.state.count++
// console.log(this.$store.state.count)
// 应该通过mutation 核心概念 进行修改数据
// 需要提交调用mutation
this.$store.commit('addCount')
},
addFive () {
this.$store.commit('addFive')
},
changeFn () {
this.$store.commit('changeTitle')
}
}
}
</script>
<style lang="css" scoped>
.box{
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
(4)mutations传参

index.js
javascript
// 2.通过mutations可以提供修改数据的方法,mutation是一个对象
mutations: {
// 所有的mutation函数,第一个参数,都是state
// addCount (state) {
// // 修改数据
// state.count += 1
// },
addCount (state, n) {
// 修改数据
state.count += n
},
changeTitle (state, newTitle) {
state.title = newTitle
}
}
Son.vue
javascript
<template>
<div class="box">
<h2>Son1 子组件 {{ $store.state.title }}</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<br>
<button @click="handleAdd(1)">值 + 1</button>
<button @click="handleAdd(5)">值 + 5</button>
<button @click="handleAdd(10)">值 + 10</button>
<button @click="changeFn">改标题</button>
</div>
</template>
<script>
export default {
name: 'Son1Com',
methods: {
handleAdd (n) {
// 错误代码,不会报错,并且可以实现,但其实是错的 (但是vue不会监测 监测需要成本)
// this.$store.state.count++
// console.log(this.$store.state.count)
// 应该通过mutation 核心概念 进行修改数据
// 需要提交调用mutation
// this.$store.commit('addCount')
this.$store.commit('addCount', n)
console.log(n)
},
changeFn (newTitle) {
this.$store.commit('changeTitle', '黑马程序员')
}
}
}
</script>
<style lang="css" scoped>
.box{
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
(5)mutations传多参
只能传递有且仅有一个参数,如果是想传递多个参数,可以写成对象数组的形式。
Son1.vue
javascript
<template>
<div class="box">
<h2>Son1 子组件 {{ $store.state.title }}</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<br>
<button @click="handleAdd(1)">值 + 1</button>
<button @click="handleAdd(5)">值 + 5</button>
<button @click="handleAdd(10)">值 + 10</button>
<button @click="changeFn">改标题</button>
</div>
</template>
<script>
export default {
name: 'Son1Com',
methods: {
handleAdd (n) {
// 错误代码,不会报错,并且可以实现,但其实是错的 (但是vue不会监测 监测需要成本)
// this.$store.state.count++
// console.log(this.$store.state.count)
// 应该通过mutation 核心概念 进行修改数据
// 需要提交调用mutation
// this.$store.commit('addCount')
// this.$store.commit('addCount', n)
// 只能传递有且仅有一个参数,如果是想传递多个参数,可以写成对象数组的形式。
this.$store.commit('addCount', {
count: n,
msg: '哈哈'
})
console.log(n)
},
changeFn (newTitle) {
this.$store.commit('changeTitle', '黑马程序员')
}
}
}
</script>
<style lang="css" scoped>
.box{
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
index.js
javascript
// 2.通过mutations可以提供修改数据的方法,mutation是一个对象
mutations: {
addCount (state, obj) {
// 修改数据
state.count += obj.count
}
}
)

(6)实时输入,实时更新
不能用:value 因为不能直接改变仓库的值,但是:value是由:value和@input组成,所以可以分开用

App.vue
javascript
<template>
<div id="app">
<h1>根组件
--{{ title }}
--{{ count }}
</h1>
<input type="text" :value="count" @input="handleInput">
<Son1></Son1>
<hr>
<Son2></Son2>
</div>
</template>
<script>
import { mapState } from 'vuex'
import Son1 from './components/Son1.vue'
import Son2 from './components/Son2.vue'
// console.log(mapState(['count', 'title']))
export default {
name: 'app',
data: function () {
return {
}
},
created () {
// console.log(this.$router) // 没配
// console.log(this.$store) // 没配
// console.log(this.$store.state.count) // 没配
},
computed: {
...mapState(['count', 'title'])
},
components: {
Son1,
Son2
},
methods: {
handleInput (e) {
// 1.实时获取输入框的值
// e.target指得是输入框 +是转化成数字类型
const num = +e.target.value
// 2.提交mutation,调用mutation函数
this.$store.commit('changeCount', num)
}
}
}
</script>
<style>
#app {
width: 600px;
margin: 20px auto;
border: 3px solid #ccc;
border-radius: 3px;
padding: 10px;
}
</style>
index.js
javascript
changeCount (state, newCount) {
state.count = newCount
}
五、mapMutations(辅助函数)

Son2.vue
javascript
<template>
<div class="box">
<h2>Son2 子组件 {{ title }}</h2>
从vuex中获取的值:<label>{{ count }}</label>
<br />
<button @click="handleSub(1)">值 - 1</button>
<button @click="handleSub(5)">值 - 5</button>
<button @click="handleSub(10)">值 - 10</button>
<!-- 上面可以直接用subCount()了,都没必要封装了 -->
<button @click="subCount(10)">值 - 10</button>
<button @click="changeTitle('改了标题')">改标题</button>
</div>
</template>
<script>
import { mapMutations, mapState } from 'vuex'
export default {
name: 'Son2Com',
computed: {
...mapState(['count', 'title'])
},
methods: {
...mapMutations(['subCount', 'changeTitle']),
handleSub (n) {
// this.$store.commit('subCount', n)
this.subCount(n)
}
}
}
</script>
<style lang="css" scoped>
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
六、actions和getters
(1)actions和dispatch
目标:明确actions的基本用法,处理异步操作。
需求:一秒钟之后,修改state的count成666。
说明:mutations必须是同步的(便于检测数据变化,记录调试)
index.js
javascript
// 这里面存放的就是vuex相关的核心代码
import Vuex from 'vuex'
import Vue from 'vue'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 严格模式(有利于初学者,检测不规范的代码 => 上线时需要关闭)
// 其实还是可以修改,只是会提示报错
strict: true,
// 1.通过state可以提供数据,所有组件共享的数据
state: {
title: '大标题',
count: 100
},
// 3.actions处理异步
// 注意:不能直接操作state,操作state,还是需要commit mutation
actions: {
// context上下文(此处未分模块,可以当作store仓库)
// context.commit('mutation名字',额外参数)
changeCountAction (context, num) {
// 这里是setTimeout模拟异步,以后大部分场景是发请求
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
}
}
)
// 到处给main.js使用
export default store
Son1.vue
javascript
<template>
<div class="box">
<h2>Son1 子组件 {{ $store.state.title }}</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<br>
<button @click="handleAdd(1)">值 + 1</button>
<button @click="handleAdd(5)">值 + 5</button>
<button @click="handleAdd(10)">值 + 10</button>
<button @click="handleChange(66)">疫苗后改为66</button>
<button @click="changeFn">改标题</button>
</div>
</template>
<script>
export default {
name: 'Son1Com',
methods: {
handleAdd (n) {
// 错误代码,不会报错,并且可以实现,但其实是错的 (但是vue不会监测 监测需要成本)
// this.$store.state.count++
// console.log(this.$store.state.count)
// 应该通过mutation 核心概念 进行修改数据
// 需要提交调用mutation
// this.$store.commit('addCount')
// this.$store.commit('addCount', n)
// 只能传递有且仅有一个参数,如果是想传递多个参数,可以写成对象数组的形式。
this.$store.commit('addCount', {
count: n,
msg: '哈哈'
})
// console.log(n)
},
changeFn (newTitle) {
this.$store.commit('changeTitle', '黑马程序员')
},
handleSub (n) {
this.$store.commit('subCount', n)
},
handleChange () {
// 调用action
// this.$store.dispatch('action名字',额外参数)
this.$store.dispatch('changeCountAction', '666')
}
}
}
</script>
<style lang="css" scoped>
.box{
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
(2)辅助函数-mapActions
目标:掌握辅助函数mapActions,映射方法,这样可以简化dispatch

Son2.vue
javascript
<template>
<div class="box">
<h2>Son2 子组件 {{ title }}</h2>
从vuex中获取的值:<label>{{ count }}</label>
<br />
<button @click="handleSub(1)">值 - 1</button>
<button @click="handleSub(5)">值 - 5</button>
<button @click="subCount(10)">值 - 10</button>
<!-- 上面可以直接用subCount()了,都没必要封装了 -->
<button @click="subCount(10)">值 - 10</button>
<button @click="changeTitle('改了标题')">改标题</button>
<button @click="changeCountAction(888)">一秒后改成888</button>
</div>
</template>
<script>
import { mapActions, mapMutations, mapState } from 'vuex'
export default {
name: 'Son2Com',
computed: {
...mapState(['count', 'title'])
},
methods: {
...mapMutations(['subCount', 'changeTitle']),
handleSub (n) {
// this.$store.commit('subCount', n)
this.subCount(n)
},
...mapActions(['changeCountAction'])
}
}
</script>
<style lang="css" scoped>
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
(3)getters
也就是对仓库中的数据(state)进行操作

index.js
javascript
// 这里面存放的就是vuex相关的核心代码
import Vuex from 'vuex'
import Vue from 'vue'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 严格模式(有利于初学者,检测不规范的代码 => 上线时需要关闭)
// 其实还是可以修改,只是会提示报错
strict: true,
// 1.通过state可以提供数据,所有组件共享的数据
state: {
title: '大标题',
count: 100,
list: [1, 2, 3, 4, 5, 6, 7, 8, 9]
},
// 2.通过mutations可以提供修改数据的方法,mutation是一个对象
mutations: {
// 所有的mutation函数,第一个参数,都是state
// addCount (state) {
// // 修改数据
// state.count += 1
// },
// addCount (state, n) {
// // 修改数据
// state.count += n
// },
addCount (state, obj) {
// 修改数据
state.count += obj.count
},
changeTitle (state, newTitle) {
state.title = newTitle
},
subCount (state, n) {
state.count -= n
},
changeCount (state, newCount) {
state.count = newCount
}
},
// 3.actions处理异步
// 注意:不能直接操作state,操作state,还是需要commit mutation
actions: {
// context上下文(此处未分模块,可以当作store仓库)
// context.commit('mutation名字',额外参数)
changeCountAction (context, num) {
// 这里是setTimeout模拟异步,以后大部分场景是发请求
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
},
// 4.getters类似于计算属性
// 但是只有获取,没有修改,修改只能通过mutations
getters: {
// 注意点:
// 1.形参第一个参数,就是state
// 必须有返回值,返回值就是getters的值
filterList (state) {
return state.list.filter(item => item > 5)
}
}
}
)
// 到处给main.js使用
export default store
Son1.vue(纯原生)
javascript
<template>
<div class="box">
<h2>Son1 子组件 {{ $store.state.title }}</h2>
从vuex中获取的值: <label>{{ $store.state.count }}</label>
<br>
<button @click="handleAdd(1)">值 + 1</button>
<button @click="handleAdd(5)">值 + 5</button>
<button @click="handleAdd(10)">值 + 10</button>
<button @click="handleChange">一秒后改为666</button>
<button @click="changeFn">改标题</button>
<hr>
<div>{{ $store.state.list }}</div>
<div>{{ $store.getters.filterList }}</div>
</div>
</template>
<script>
export default {
name: 'Son1Com',
methods: {
handleAdd (n) {
// 错误代码,不会报错,并且可以实现,但其实是错的 (但是vue不会监测 监测需要成本)
// this.$store.state.count++
// console.log(this.$store.state.count)
// 应该通过mutation 核心概念 进行修改数据
// 需要提交调用mutation
// this.$store.commit('addCount')
// this.$store.commit('addCount', n)
// 只能传递有且仅有一个参数,如果是想传递多个参数,可以写成对象数组的形式。
this.$store.commit('addCount', {
count: n,
msg: '哈哈'
})
// console.log(n)
},
changeFn (newTitle) {
this.$store.commit('changeTitle', '黑马程序员')
},
handleChange () {
// 调用action
// this.$store.dispatch('action名字',额外参数)
this.$store.dispatch('changeCountAction', 666)
}
}
}
</script>
<style lang="css" scoped>
.box{
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
(4)辅助函数-mapGetters
Son2.vue(辅助函数)
javascript
<template>
<div class="box">
<h2>Son2 子组件 {{ title }}</h2>
从vuex中获取的值:<label>{{ count }}</label>
<br />
<button @click="handleSub(1)">值 - 1</button>
<button @click="handleSub(5)">值 - 5</button>
<button @click="subCount(10)">值 - 10</button>
<!-- 上面可以直接用subCount()了,都没必要封装了 -->
<button @click="subCount(10)">值 - 10</button>
<button @click="changeTitle('改了标题')">改标题</button>
<button @click="changeCountAction(888)">一秒后改成888</button>
<hr>
<div>{{ filterList }}</div>
</div>
</template>
<script>
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'
export default {
name: 'Son2Com',
computed: {
// mapState和mapGetters都是映射属性
...mapState(['count', 'title']),
...mapGetters(['filterList'])
},
methods: {
handleSub (n) {
// this.$store.commit('subCount', n)
this.subCount(n)
},
// mapMutations和mapActions都是映射方法
...mapMutations(['subCount', 'changeTitle']),
...mapActions(['changeCountAction'])
}
}
</script>
<style lang="css" scoped>
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
</style>
七、模块创建


