任务一:Vuex 状态管理
1、课程目标
- Vue 组件间通信方式回顾
- Vuex 核心概念和基本使用回顾
- 购物车案例
- 模拟实现 Vuex
2、组件内的状态管理流程
- 状态管理:
- state:驱动应用的数据源
- view:以声明方式将 state 映射到视图
- actions:响应在 view 上的用户输入导致的状态变化
3、组件间通信方式回顾
- 四种通信方式:
- 父组件给子组件传值
- 子组件通过 props 接收数据
- 父组件中给子组件通过相应属性传值
- 子组件给父组件传值
- 子组件通过 this.$emit(fn, data)
- 父组件中给子组件通过 v-on:子组件emit的函数名=父组件函数名
- 不相关组件传值
import Vue from 'vue'
export default new Vue()
<template>
<div>
<h1>Event Bus Sibling01</h1>
<div class="number" @click="sub">-</div>
<input type="text" style="width: 30px; text-align: center" :value="value">
<div class="number" @click="add">+</div>
</div>
</template>
<script>
import bus from './eventbus'
export default {
props: {
num: Number
},
created () {
this.value = this.num
},
data () {
return {
value: -1
}
},
methods: {
sub () {
if (this.value > 1) {
this.value--
bus.$emit('numchange', this.value)
}
},
add () {
this.value++
bus.$emit('numchange', this.value)
}
}
}
</script>
<style>
.number {
display: inline-block;
cursor: pointer;
width: 20px;
text-align: center;
}
</style>
<template>
<div>
<h1>Event Bus Sibling02</h1>
<div>{
{
msg }}</div>
</div>
</template>
<script>
import bus from './eventbus'
export default {
data () {
return {
msg: ''
}
},
created () {
bus.$on('numchange', (value) => {
this.msg = `您选择了${
value}件商品`
})
}
}
</script>
<style>
</style>
- 通过 ref 获取子组件
- ref 两个作用
- 在普通 HTML 标签上使用 ref,获取到的是 DOM
<template>
<div>
<h1>ref Child</h1>
<input ref="input" type="text" v-model="value">
</div>
</template>
<script>
export default {
data () {
return {
value: ''
}
},
methods: {
focus () {
this.$refs.input.focus()
}
}
}
</script>
<template>
<div>
<h1>ref Parent</h1>
<child ref="c"></child>
</div>
</template>
<script>
import child from './04-Child'
export default {
components: {
child
},
mounted () {
this.$refs.c.focus()
this.$refs.c.value = 'hello input'
}
}
</script>
4、Vuex 回顾
- 什么是 Vuex:
- Vuex 专门为 Vue.js 设计的状态管理库
- Vuex 采用集中式的方式存储需要共享的状态
- Vuex 的作用是进行状态管理,解决复杂组件通信,数据共享
- Vuex 集成到了 devtools 中,提供了 time-travel 时光旅行历史回滚功能
- 什么情况下使用 Vuex
- 非必要的情况下不要使用 Vuex
- 大型的单页应用程序
- 多个视图依赖于同一状态
- 来自不同视图的行为需要变更同一状态
5、Vuex 核心概念回顾
- Store: 是一个容器,包含着应用中的大部分状态,不能直接改变 store 中的状态,要通过 mutation 的方式改变状态。
- State:是状态,保存在 Store 中,因为 Store 是唯一的,所以 State 也是唯一的,也称为单一状态树。这里的状态是响应式的。
- Getter:是 Vuex 中的计算属性,方便从一个属性派生出其他的值。它内部会对计算的属性进行缓存,只有当依赖改变的时候,才会重新进行计算。
- Mutation:状态的变换必须要通过提交 Mutation 来完成。
- Action:和 MuTation 类似,不同的是 Action 可以进行异步的操作,内部改变状态的时候,都需要提交 Mutation。
- Module:当 Store 太过臃肿时,可以将 Store 分成多个模块,每个模块里有 State、Mutation、Action、Getter,甚至是子模块。
6、State
export default new Vuex.Store({
state: {
count: 0,
msg: 'Hello Vuex'
},
mutations: {
},
actions: {
},
modules: {
}
})
<template>
<div id="app">
<h1>Vuex - Demo</h1>
<!-- count:{
{
count }} <br>
msg: {
{
msg }} -->
<!-- count:{
{
$store.state.count }} <br>
msg: {
{
$store.state.msg }} -->
count: {
{
num }} <br>
msg: {
{
message }}
</div>
</template>
<script>
import {
mapState } from 'vuex'
export default {
computed: {
...mapState({
num: 'count', message: 'msg' })
}
}
</script>
7、Getter
export default new Vuex.Store({
state: {
count: 0,
msg: 'Hello Vuex'
},
getters: {
reverseMsg (state) {
return state.msg.split('').reverse().join('')
}
},
mutations: {
},
actions: {
},
modules: {
}
})
<template>
<div id="app">
<h1>Vuex - Demo</h1>
reverseMsg: {
{
reverseMsg }}
</div>
</template>
<script>
import {
mapState, mapGetters } from 'vuex'
export default {
computed: {
...mapGetters(['reverseMsg'])
}
}
</script>
8、Mutation
<template>
<div id="app">
<h1>Vuex - Demo</h1>
<!-- count:{
{
count }} <br>
msg: {
{
msg }} -->
<!-- count:{
{
$store.state.count }} <br