Vuex构建多组件共享的数据环境
index.js:
// 创建一个空仓库
// 目标:安装 vuex 插件,初始化一个空仓库
// 1.安装 vuex:yarn add vuex@3
// 2.新建 vuex 模块文件:新建 store/index.js 专门存放 vuex
// 3.创建仓库:Vue.use (Vuex),创建仓库 new Vuex.Store ()
// 4.main.js 导入挂载:在 main.js 中导入挂载到 Vue 实例上
// 这里面存放的就是 vuex 相关的核心代码
import Vue from 'vue'
import Vuex from 'vuex'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store()
// 导出给main.js使用
export default store
main.js:
import Vue from 'vue'
import App from './App.vue'
// 引入
import store from '@/store/index'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
// 挂载
store
}).$mount('#app')
提供并使用仓库中的数据
index.js:
import Vue from 'vue'
import Vuex from 'vuex'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 核心概念 - state 状态
// 目标:明确如何给仓库提供数据,如何使用仓库的数据
// 1.提供数据:
// State 提供唯一的公共数据源,所有共享的数据都要统一放到 Store 中的 State 中存储。
// 在 state 对象中可以添加要共享的数据。
// 2.使用数据:
// ① 通过 store 直接访问
// 获取 store:
// (1) this.$store
// (2) import 导入 store
// 模板中:{{ $store.state.xxx }}
// 组件逻辑中:this.$store.state.xxx
// JS模块中: store.state.xxx
// ② 通过辅助函数(简化)
// mapState是辅助函数,帮助我们把 store 中的数据自动映射到组件的计算属性中。
// 导入: mapState:import { mapState } from 'vuex'
// 数组方式引入: state:mapState(['count'])
// 展开运算符映射:
// computed: {
// ...mapState(['count'])
// }
// 通过 state 可以提供数据(所有组件共享的数据)
state: {
title: '仓库大标题',
count: 100
}
})
// 导出给main.js使用
export default store
App.vue:
根组件
- {{ title }}
- {{ count }}
import Son1 from './components/Son1.vue'
import Son2 from './components/Son2.vue'
// 使用辅助函数简化获取
// 导入
import { mapState } from 'vuex'
// 辅助函数使用
// console.log(mapState(['count', 'title']))
export default {
name: 'app',
created () {
// 组件逻辑中通过store导入数据
console.log(this.$store.state.count)
},
// 辅助函数通过对象的方式映照
computed: {
// 辅助函数使用
...mapState(['count', 'title'])
},
data: function () {
return {
}
},
components: {
Son1,
Son2
}
}
#app {
width: 600px;
margin: 20px auto;
border: 3px solid #ccc;
border-radius: 3px;
padding: 10px;
}
mutation传参并修改数据
index.js:
import Vue from 'vue'
import Vuex from 'vuex'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 开启严格模式(有利于初学者检测不规范的代码 => 上线时需要关闭) 直接修改组件数据的语法会报错,如
strict: true,
// 1.通过 state 可以提供数据(所有组件共享的数据)
state: {
title: '仓库大标题',
count: 100
},
// 2.通过 mutations 可以提供修改数据的方法
mutations: {
// 所有mutation函数,第一个参数,都是 state
// 注意点:mutation 后面的参数只能有一个(这里是n),如果需要多个参数,就包装成一个对象。
addCount (state, n) {
// 修改数据
state.count += n
},
changeTitle (state) {
state.title = '小标题'
}
}
})
// 导出给main.js使用
export default store
Son1.vue:
Son1 子组件
从vuex中获取的值:
export default {
name: 'Son1Com',
methods: {
handleAdd (n) {
// vuex同样遵循单向数据流,组件中不能直接修改仓库的数据
// this.$store.state.count++ // 错误代码 (vue 默认不会监测,监测需要成本,在index.js开启strict: true,可监测)
// 应该通过 mutation 核心概念,进行修改数据
// 触发mutations中方法要用commit
// 不传参的写法
// this.$store.commit('addCount')
// 传参的写法
this.$store.commit('addCount', n)
},
changeFn () {
this.$store.commit('changeTitle')
}
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
mapMutations调用方法
Son2.vue:
Son2 子组件
从vuex中获取的值:
import { mapState, mapMutations } from 'vuex'
export default {
name: 'Son2Com',
computed: {
...mapState(['count'])
},
methods: {
// 辅助函数:mapMutations
// 目标:掌握辅助函数 mapMutations,映射方法
// mapMutations 和 mapState 很像,它是把位于 mutations 中的方法提取了出来,映射到组件 methods 中
// 原来的写法
// handleSub (n) {
// this.$store.commit('subCount', n)
// }
// 调用函数的写法
// 调用
...mapMutations(['subCount', 'changeTitle'])
// 简写,直接删掉,在上面直接调用传过来的方法
// handleSub (n) {
// this.subCount(n)
// }
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
index.js:
import Vue from 'vue'
import Vuex from 'vuex'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 开启严格模式(有利于初学者检测不规范的代码 => 上线时需要关闭) 直接修改组件数据的语法会报错,如
strict: true,
// 1.通过 state 可以提供数据(所有组件共享的数据)
state: {
title: '仓库大标题',
count: 100
},
// 2.通过 mutations 可以提供修改数据的方法
mutations: {
// 所有mutation函数,第一个参数,都是 state
// 注意点:mutation 后面的参数只能有一个(这里是n),如果需要多个参数,就包装成一个对象。
addCount (state, n) {
// 修改数据
state.count += n
},
subCount (state, n) {
// 修改数据
state.count -= n
},
changeCount (state, newCount) {
state.count = newCount
},
changeTitle (state, newTitle) {
state.title = newTitle
}
}
})
// 导出给main.js使用
export default store
actions处理异步
index.js:
import Vue from 'vue'
import Vuex from 'vuex'
// 插件安装
Vue.use(Vuex)
// 创建仓库(空仓库)
const store = new Vuex.Store({
// 开启严格模式(有利于初学者检测不规范的代码 => 上线时需要关闭) 直接修改组件数据的语法会报错,如
strict: true,
// 1.通过 state 可以提供数据(所有组件共享的数据)
state: {
title: '仓库大标题',
count: 100
},
// 2.通过 mutations 可以提供修改数据的方法
mutations: {
// 所有mutation函数,第一个参数,都是 state
// 注意点:mutation 后面的参数只能有一个(这里是n),如果需要多个参数,就包装成一个对象。
addCount (state, n) {
// 修改数据
state.count += n
},
subCount (state, n) {
// 修改数据
state.count -= n
},
changeCount (state, newCount) {
state.count = newCount
},
changeTitle (state, newTitle) {
state.title = newTitle
}
},
// 3. actions处理异步
// 核心概念 - actions
// 目标:明确 actions 的基本语法,处理异步操作。
// 需求:一秒钟之后,修改 state 的 count 成 666。
// 说明:mutations 必须是同步的 (便于监测数据变化,记录调试)
// 注意:不能直接操作 state,操作 state,还是需要 commit mutation
// 1.提供 action 方法
actions: {
// context 上下文(此处未分模块,可以当成store仓库)
// context.commit('mutation名字', 额外参数)
changeCountAction (context, num) {
// 这里是setTimeout模拟异步,以后大部分场景是发请求
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
}
})
// 导出给main.js使用
export default store
Son1.vue:
Son1 子组件
从vuex中获取的值:
export default {
name: 'Son1Com',
methods: {
handleAdd (n) {
this.$store.commit('addCount', n)
},
changeFn () {
this.$store.commit('changeTitle')
},
handleChange () {
// 2.页面中 dispatch 调用action
// this.$store.dispatch('action名字', 额外参数)
this.$store.dispatch('changeCountAction', 666)
}
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
mapActions调用方法
Son2 子组件
从vuex中获取的值:
import { mapState, mapMutations, mapActions } from 'vuex'
export default {
name: 'Son2Com',
computed: {
...mapState(['count'])
},
methods: {
...mapMutations(['subCount', 'changeTitle']),
// 辅助函数 - mapActions
// 目标:掌握辅助函数 mapActions,映射方法
// mapActions 是把位于 actions 中的方法提取了出来,映射到组件 methods 中
// 原理同mapMutations
...mapActions(['changeCountAction'])
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
getters派生状态
index.js:
import Vue from 'vue'
import Vuex from 'vuex'
// 插件安装
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, 10]
},
// 2.通过 mutations 可以提供修改数据的方法
mutations: {
addCount (state, n) {
state.count += n
},
subCount (state, n) {
state.count -= n
},
changeCount (state, newCount) {
state.count = newCount
},
changeTitle (state, newTitle) {
state.title = newTitle
}
},
// 3. 通过 actions处理异步
actions: {
changeCountAction (context, num) {
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
},
// 4. getters 类似于计算属性
// 核心概念 - getters
// 目标:掌握核心概念 getters 的基本语法 (类似于计算属性)
// 说明:除了 state 之外,有时我们还需要从 state 中派生出一些状态,这些状态是依赖 state 的,此时会用到 getters。
// 例如:state 中定义了 list,为 1 - 10 的数组,组件中,需要显示所有大于 5 的数据。
// 定义getters
getters: {
// 注意点:
// 1. 形参第一个参数,就是state
// 2. 必须有返回值,返回值就是getters的值
filterList (state) {
return state.list.filter(item => item > 5)
}
}
})
// 导出给main.js使用
export default store
Son2.vue:
Son2 子组件
从vuex中获取的值:
{{ filterList }}
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
name: 'Son2Com',
computed: {
// mapState和mapGetters都是在映射属性
...mapState(['count']),
// 通过辅助函数 mapGetters 映射
...mapGetters(['filterList'])
},
methods: {
// mapMutations和mapActions都是在映射方法
...mapMutations(['subCount', 'changeTitle']),
...mapActions(['changeCountAction'])
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
08_modules分模块_模块创建
import Vue from 'vue'
import Vuex from 'vuex'
import user from './modules/user'
import setting from './modules/setting'
// 插件安装
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, 10]
},
// 2.通过 mutations 可以提供修改数据的方法
mutations: {
addCount (state, n) {
state.count += n
},
subCount (state, n) {
state.count -= n
},
changeCount (state, newCount) {
state.count = newCount
},
changeTitle (state, newTitle) {
state.title = newTitle
}
},
// 3. 通过 actions处理异步
actions: {
changeCountAction (context, num) {
setTimeout(() => {
context.commit('changeCount', num)
}, 1000)
}
},
// 4. getters 类似于计算属性
getters: {
filterList (state) {
return state.list.filter(item => item > 5)
}
},
// 5. modules 模块
// 核心概念 - 模块 module(进阶语法)
// 目标:掌握核心概念 module 模块的创建
// 由于 vuex 使用单一状态树,应用的所有状态会集中到一个比较大的对象。
// 当应用变得非常复杂时,store 对象就有可能变得相当臃肿。(当项目变得越来越大的时候,Vuex 会变得越来越难以维护)
// 模块拆分:
// user 模块:store/modules/user.js
modules: {
user,
setting
}
})
// 导出给main.js使用
export default store
模块中state的访问语法
Son2 子组件
从vuex中获取的值:
{{ filterList }}
{{ user.userInfo.name }}
{{ setting.theme }}
user模块的数据:{{ userInfo }}
setting模块的数据:{{ theme }} - {{ desc }}
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
name: 'Son2Com',
computed: {
// mapState和mapGetters都是在映射属性
// 2.通过 mapState 映射
// 默认根级别的映射 mapState(['xxx'])
...mapState(['count', 'user', 'setting']),
// 模块级别的映射 mapState('模块名', ['xxx'])
...mapState('user', ['userInfo']),
...mapState('setting', ['theme', 'desc']),
...mapGetters(['filterList'])
},
methods: {
// mapMutations和mapActions都是在映射方法
...mapMutations(['subCount', 'changeTitle']),
...mapActions(['changeCountAction'])
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
模块中getters的访问语法
Son2 子组件
从vuex中获取的值:
{{ filterList }}
{{ user.userInfo.name }}
{{ setting.theme }}
user模块的数据:{{ userInfo }}
setting模块的数据:{{ theme }} - {{ desc }}
{{ UpperCaseName }}
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
name: 'Son2Com',
computed: {
// mapState和mapGetters都是在映射属性
...mapState(['count', 'user', 'setting']),
...mapState('user', ['userInfo']),
...mapState('setting', ['theme', 'desc']),
...mapGetters(['filterList']),
...mapGetters('user', ['UpperCaseName'])
},
methods: {
// mapMutations和mapActions都是在映射方法
...mapMutations(['subCount', 'changeTitle']),
...mapActions(['changeCountAction'])
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
模块中mutation的调用语法
Son1.vue:
Son1 子组件
从vuex中获取的值:
{{ $store.state.list }}
{{ $store.getters.filterList }}
{{ $store.state.user.userInfo.name }}
{{ $store.state.setting.theme }}
{{ $store.getters['user/UpperCaseName'] }}
export default {
name: 'Son1Com',
methods: {
updateUser () {
// 核心概念 - 模块 module(进阶语法)
// 目标:掌握模块中 mutation 的调用语法
// 注意:默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。
// 调用子模块中 mutation:
// ① 直接通过 store 调用 $store.commit('模块名/xxx', 额外参数)
// ② 通过 mapMutations 映射
// 默认根级别的映射 mapMutations(['xxx'])
// 子模块的映射 mapMutations('模块名', ['xxx']) - 需要开启命名空间
// ① 直接通过 store 调用 $store.commit('模块名/mutation名', 额外参数)
this.$store.commit('user/setUser', {
name: 'xiaowang',
age: 25
})
},
updateTheme () {
this.$store.commit('setting/setTheme', 'pink')
},
handleAdd (n) {
this.$store.commit('addCount', n)
},
changeFn () {
this.$store.commit('changeTitle')
},
handleChange () {
this.$store.dispatch('changeCountAction', 666)
}
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
Son2.vue:
Son2 子组件
从vuex中获取的值:
{{ filterList }}
{{ user.userInfo.name }}
{{ setting.theme }}
user模块的数据:{{ userInfo }}
setting模块的数据:{{ theme }} - {{ desc }}
{{ UpperCaseName }}
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
name: 'Son2Com',
computed: {
// mapState和mapGetters都是在映射属性
...mapState(['count', 'user', 'setting']),
...mapState('user', ['userInfo']),
...mapState('setting', ['theme', 'desc']),
...mapGetters(['filterList']),
...mapGetters('user', ['UpperCaseName'])
},
methods: {
// mapMutations和mapActions都是在映射方法
// 全局级别的映射
...mapMutations(['subCount', 'changeTitle']),
...mapActions(['changeCountAction']),
// 分模块的映射
// ② 通过 mapMutations 映射
...mapMutations('setting', ['setTheme']),
...mapMutations('user', ['setUser'])
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
模块中action的调用语法
Son1.vue:
Son1 子组件
从vuex中获取的值:
{{ $store.state.list }}
{{ $store.getters.filterList }}
{{ $store.state.user.userInfo.name }}
{{ $store.state.setting.theme }}
{{ $store.getters['user/UpperCaseName'] }}
export default {
name: 'Son1Com',
methods: {
updateUser () {
this.$store.commit('user/setUser', {
name: 'xiaowang',
age: 25
})
},
updateUser2 () {
// 核心概念 - 模块 module(进阶语法)
// 目标:掌握模块中 action 的调用语法(同理 - 直接类比 mutation 即可)
// 注意:默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。
// 调用子模块中 action:
// ① 直接通过 store 调用 $store.dispatch('模块名/xxx', 额外参数)
// ② 通过 mapActions 映射
// 默认根级别的映射 mapActions(['xxx'])
// 子模块的映射 mapActions('模块名', ['xxx']) - 需要开启命名空间
// ① 调用action dispatch
this.$store.dispatch('user/setUserSecond', {
name: 'xiaohong',
age: 28
})
},
updateTheme () {
this.$store.commit('setting/setTheme', 'pink')
},
handleAdd (n) {
this.$store.commit('addCount', n)
},
changeFn () {
this.$store.commit('changeTitle')
},
handleChange () {
this.$store.dispatch('changeCountAction', 666)
}
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
Son2.vue:
Son2 子组件
从vuex中获取的值:
{{ filterList }}
{{ user.userInfo.name }}
{{ setting.theme }}
user模块的数据:{{ userInfo }}
setting模块的数据:{{ theme }} - {{ desc }}
{{ UpperCaseName }}
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
export default {
name: 'Son2Com',
computed: {
// mapState和mapGetters都是在映射属性
...mapState(['count', 'user', 'setting']),
...mapState('user', ['userInfo']),
...mapState('setting', ['theme', 'desc']),
...mapGetters(['filterList']),
...mapGetters('user', ['UpperCaseName'])
},
methods: {
// mapMutations和mapActions都是在映射方法
// 全局级别的映射
...mapMutations(['subCount', 'changeTitle']),
...mapActions(['changeCountAction']),
// 分模块的映射
...mapMutations('setting', ['setTheme']),
...mapMutations('user', ['setUser']),
// ② 通过 mapActions 映射
...mapActions(['user', ['setUserSecond']])
}
}
.box {
border: 3px solid #ccc;
width: 400px;
padding: 10px;
margin: 20px;
}
h2 {
margin-top: 10px;
}
目标:阅读文档,掌握按需导入的基本使用
按需导入:
① 安装 vant - ui:yarn add vant@latest - v2
② 安装插件:npm i babel - plugin - import - D
③ babel.config.js
中配置
④ main.js
按需导入注册:
⑤ 测试使用
⑥ 提取到 vant - ui.js
中,main.js
导入
目标:基于 postcss 插件实现项目 vw 适配
① 安装插件:yarn add postcss - px - to - [email protected] - D
② 根目录新建postcss.config.js
文件,填入配置