网站建设视频教程百度云,上海网站设计公司排行榜,米拓建站官网怎么用不了,企业平台入口基本概念
vue进行开发过程中有没有遇到这样一种场景#xff0c;就是有些时候一些数据是一种通用的共享数据#xff08;比如登录信息#xff09;#xff0c;那么这类数据在各个组件模块中可能都会用到#xff0c;如果每个组件中都去后台重新获取那么势必会造成性能浪费就是有些时候一些数据是一种通用的共享数据比如登录信息那么这类数据在各个组件模块中可能都会用到如果每个组件中都去后台重新获取那么势必会造成性能浪费为了解决这一问题一个新的状态管理工具 - vuex就应运而生 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态并以相应的规则保证状态以一种可预测的方式发生变化。
什么是“状态管理模式”
这个状态自管理应用包含以下几个部分
状态驱动应用的数据源视图以声明方式将状态映射到视图操作响应在视图上的用户输入导致的状态变化。
安装方式
CDN引用
https://unpkg.com/vuex4Unpkg.com 提供了基于 npm 的 CDN 链接。以上的链接会一直指向npm 上发布的最新版本。 您也可以通过 https://unpkg.com/vuex4.0.0/dist/vuex.global.js 这样的方式指定特定的版本。
Npm
npm install vuexnext --save
Yarn
yarn add vuexnext --save核心概念
State
单一状态树 Vuex 使用单一状态树用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段在调试的过程中也能轻易地取得整个当前应用状态的快照。在 Vue 组件中获得 Vuex 状态 由于 Vuex 的状态存储是响应式的从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态
const Counter {template: div{{ count }}/div,computed: {count () {return store.state.count}}}每当store.state.count变化的时候, 都会重新求取计算属性并且触发更新相关联的 DOM Vuex 通过 Vue 的插件系统将 store 实例从根组件中“注入”到所有的子组件里。且子组件能通过this.$store访问到。让我们更新下Counter的实现
const Counter {template: div{{ count }}/div,computed: {count () {return this.$store.state.count}}}mapState 辅助函数 当一个组件需要获取多个状态的时候将这些状态都声明为计算属性会有些重复和冗余。 为了解决这个问题我们可以使用 mapState辅助函数帮助我们生成计算属性让你少按几次键
import { mapState } from vuex
export default {computed: mapState({count: state state.count, // 箭头函数可使代码更简练// 传字符串参数 count 等同于 state state.countcountAlias: count,// 为了能够使用 this 获取局部状态必须使用常规函数countPlusLocalState (state) {return state.count this.localCount}})}对象展开运算符 mapState函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢通常我们需要使用一个工具函数将多个对象合并为一个以使我们可以将最终对象传给computed属性。但是自从有了对象展开运算符【…】我们可以极大地简化写法
computed: {localComputed () { /* ... */ },// 使用对象展开运算符将此对象混入到外部对象中...mapState({// ...})}对象展开运算符 var obj {a:1,b:2} var obj1 {c:3,d:4} var obj2 {…obj,…obj1} var obj3 {…obj,a:8,w:66} var obj4 {…obj,a:8,w:66,…obj1} console.log(obj); //{a: 1, b: 2} console.log(obj1); //{c: 3, d: 4} console.log(obj2); //{a: 1, b: 2,c: 3, d: 4} console.log(obj3); //{a: 8, b: 2, w: 66} console.log(obj4); //{a: 8, b: 2, w: 66, c: 3, d: 4} Getter
我们需要从 store 中的 state 中派生出一些状态,如果有多个组件需要用到此属性我们要么复制这个函数或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。 Vuex 允许我们在 store 中定义“getter”可以认为是 store 的计算属性。 从 Vue 3.0 开始getter 的结果不再像计算属性一样会被缓存起来 Getter 接受 state 作为其第一个参数
const store createStore({state: {todos: [{ id: 1, text: ..., done: true },{ id: 2, text: ..., done: false }]},getters: {doneTodos (state) {return state.todos.filter(todo todo.done)}}})通过属性访问 Getter 会暴露为 store.getters 对象你可以以属性的形式访问这些值
store.getters.doneTodos Getter 也可以接受其他 getter 作为第二个参数
getters: {// ...doneTodosCount (state, getters) {return getters.doneTodos.length}}通过方法访问 你也可以通过让 getter 返回一个函数来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。
getters: {getTodoById: (state) (id) {return state.todos.find(todo todo.id id)}}
store.getters.getTodoById(2)getter 在通过方法访问时每次都会去进行调用而不会缓存结果。
mapGetters 辅助函数 mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性
import { mapGetters } from vuex
export default {// ...computed: {// 使用对象展开运算符将 getter 混入 computed 对象中...mapGetters([doneTodosCount,anotherGetter,// ...])}}Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方并且它会接受 state 作为第一个参数
const store createStore({state: {count: 1},mutations: {increment (state) {// 变更状态state.count}}})提交载荷Payload 你可以向 store.commit 传入额外的参数即 mutation 的载荷payload
mutations: {increment (state, n) {state.count n}}
store.commit(increment, 10)对象风格的提交方式 提交 mutation 的另一种方式是直接使用包含 type 属性的对象
store.commit({type: increment,amount: 10})当使用对象风格的提交方式整个对象都作为载荷传给 mutation 函数因此处理函数保持不变
mutations: {increment (state, payload) {state.count payload.amount}}Mutation 必须是同步函数 一条重要的原则就是要记住 mutation 必须是同步函数
Action
Action 类似于 mutation不同在于
Action 提交的是 mutation而不是直接变更状态。Action 可以包含任意异步操作。分发 Action Action 通过 store.dispatch 方法触发
store.dispatch(increment)
actions: {incrementAsync ({ commit }) {setTimeout(() {commit(increment)}, 1000)}}在组件中分发 Action 你在组件中使用this.$store.dispatch(‘xxx’)分发 action或者使用mapActions辅助函数将组件的methods映射为store.dispatch调用需要先在根节点注入store
import { mapActions } from vuex
export default {methods: {...mapActions([increment, // 将 this.increment() 映射为 this.$store.dispatch(increment)// mapActions 也支持载荷incrementBy // 将 this.incrementBy(amount) 映射为 this.$store.dispatch(incrementBy, amount)]),...mapActions({add: increment // 将 this.add() 映射为 this.$store.dispatch(increment)})}}Module
由于使用单一状态树应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时store 对象就有可能变得相当臃肿 为了解决以上问题Vuex允许我们将store分割成模块module。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块
const moduleA {state: () ({ ... }),mutations: { ... },actions: { ... },getters: { ... }}const moduleB {state: () ({ ... }),mutations: { ... },actions: { ... }}const store createStore({modules: {a: moduleA,b: moduleB}})store.state.a // - moduleA 的状态
store.state.b // - moduleB 的状态进阶
项目结构
Vuex 并不限制你的代码结构。但是它规定了一些需要遵守的规则
应用层级的状态应该集中到单个 store 对象中。提交 mutation 是更改状态的唯一方法并且这个过程是同步的。异步逻辑都应该封装到 action 里面。 只要你遵守以上规则如何组织代码随你便。如果你的 store 文件太大只需将 action、mutation 和 getter 分割到单独的文件。 对于大型应用我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例
热重载
使用 webpack 的 Hot Module Replacement APIVuex 支持在开发过程中热重载 mutation、module、action 和 getter。你也可以在 Browserify 中使用 browserify-hmr 插件。 对于 mutation 和模块你需要使用 store.hotUpdate() 方法
// store.js
import { createStore } from vuex
import mutations from ./mutations
import moduleA from ./modules/a
const state { ... }
const store createStore({state,mutations,modules: {a: moduleA}})
if (module.hot) {// 使 action 和 mutation 成为可热重载模块module.hot.accept([./mutations, ./modules/a], () {// 获取更新后的模块// 因为 babel 6 的模块编译格式问题这里需要加上 .defaultconst newMutations require(./mutations).defaultconst newModuleA require(./modules/a).default// 加载新模块store.hotUpdate({mutations: newMutations,modules: {a: newModuleA}})})}动态模块热重载 如果你仅使用模块你可以使用 require.context 来动态地加载或热重载所有的模块。
// store.js
import { createStore } from vuex
// 加载所有模块。function loadModules() {const context require.context(./modules, false, /([a-z_])\.js$/i)const modules context.keys().map((key) ({ key, name: key.match(/([a-z_])\.js$/i)[1] })).reduce((modules, { key, name }) ({...modules,[name]: context(key).default}),{})return { context, modules }}
const { context, modules } loadModules()
const store new createStore({modules})
if (module.hot) {// 在任何模块发生改变时进行热重载。module.hot.accept(context.id, () {const { modules } loadModules()store.hotUpdate({modules})})}组合式api
可以通过调用 useStore 函数来在 setup 钩子函数中访问 store。这与在组件中使用选项式 API 访问 this.$store 是等效的。
import { useStore } from vuex
export default {setup () {const store useStore()}}访问 State 和 Getter 为了访问 state 和 getter需要创建 computed 引用以保留响应性这与在选项式 API 中创建计算属性等效。
import { computed } from vueimport { useStore } from vuex
export default {setup () {const store useStore()return {// 在 computed 函数中访问 statecount: computed(() store.state.count),// 在 computed 函数中访问 getterdouble: computed(() store.getters.double)}}}访问 Mutation 和 Action 要使用 mutation 和 action 时只需要在 setup 钩子函数中调用 commit 和 dispatch 函数。
import { useStore } from vuex
export default {setup () {const store useStore()return {// 使用 mutationincrement: () store.commit(increment),// 使用 actionasyncIncrement: () store.dispatch(asyncIncrement)}}}