• Vue.js 系列教程 4:Vuex


    原文:intro-to-vue-4-vuex

    译者:nzbin

    这是关于 JavaScript 框架 Vue.js 五个教程的第四部分。在这一部分,我们会学习使用 Vuex 进行状态管理。这个系列教程并不是一个完整的用户手册,而是通过基础知识让你快速了解 Vuejs 以及它的用途。

    系列文章:

    1. 渲染, 指令, 事件
    2. 组件, Props, Slots
    3. Vue-cli
    4. Vuex (你在这!)
    5. Animations

    Vuex

    如果你错过了关于组件及 Vue-cli 的部分,在阅读本篇文章之前应该先读读这几部分。现在我们已经了解了关于组件、传递状态和 props 的基本知识,接下来讨论一下 Vuex,它是状态管理的好工具。

    之前,我们是从顶层组件向下传递状态,而同胞组件之间并没有分享数据。如果它们需要相互通信,我们要在应用程序中推送状态。这是可以的!但是一旦你的程序变得复杂,这种方法就没有意义了。如果你之前用过 Redux,那 Vuex 中所有的概念及实现对你也不陌生。Vuex 是 Vue 中的 Redux。实际上,Redux 也可以用于 Vue,但是,使用专门为 Vue 设计的工具 Vuex 更加有利。

    首先,安装 Vuex:

    npm install vuex

    或者

    yarn add vuex

    我这样设置: 在 `/src` 目录下,我创建了名为 store 的目录 ( 这是一种选择,你也可以在同级目录创建一个 `store.js` 文件 ),再在其中创建一个名为 `store.js`的文件。`store.js` 中的初始设置如下 ( vstore sublime snippet ):

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export const store = new Vuex.Store({
      state: {
        key: value
      }
    });

    key: value 是状态数据的占位符。在其他例子中,我们已经使用 counter: 0

    在 `main.js` 文件中,我们将执行以下更新(加粗显示更新的行):

    import Vue from 'vue';
    import App from './App.vue';
    
    import { store } from './store/store';
    
    new Vue({
      el: '#app',
      store: store,
      template: '<App/>',
      components: { App }
    });

    更新之后,和之前做的组件一样,我们可以把 data() 作为状态,然后我们通过以下三种方式使用或者更新状态:

    • Getters 可以在模板中静态的显示数据。换句话说,getters 可以读取数据,但不能改变状态。
    • Mutations 允许更新状态,但永远是同步的。Mutations 是 store 中改变状态数据的唯一方式。
    • Actions 允许异步更新状态,但是需要使用一个已经存在的 mutation 。如果你需要以特定的顺序同时执行不同的 mutations 会非常有用。

    如果你以前没有接触过,也许很难理解为什么会使用异步状态的变化,所以先看看理论上它会发生什么,然后再开始下一部分。假如你运行 Tumblr。如果页面中有大量长时间运行的 gif 图片。你只想每次载入其中一部分,比如当用户将页面滚动到底部 200px 时,加载 20 个图片。

    你需要使用 mutation 展示后面的 20 个。但是现在还没有后面的 20 个,你不知道何时到达页面底部。因此,在程序中,创建一个事件来监听滚动的位置然后触发相应的操作。

    然后,该操作将从数据库中检索后面 20 个图像的 URL,并将 20 个图片的状态添加到 mutation 中然后显示。

    本质上,Actions 创建一个请求数据的框架。它们使用一致的方法来应用异步方式中的数据。

    最基本的抽象例子

    在下面的例子中,展示了每个属性最基本的实现方式,因此你可以了解如何设置及使用。载荷是可选参数,可以通过它定义正在更新的组件的数值。不用担心,我们随后将演示一个实际案例,现在最重要的是了解基本概念。

    `store.js`:

    export const store = new Vuex.Store({
      state: {
        counter: 0
      },
      // 展示内容, 无法改变状态
      getters: {
        tripleCounter: state => {
          return state.counter * 3;
        }
      },
      // 改变状态
      //mutations 永远是同步的
      mutations: {
        // 显示传递的载荷 payload, 用 num 表示
        increment: (state, num) => {
          state.counter += num;
        }
      }, 
      // 提交 mutation, 这是异步的
      actions: {
        // 显示传递的载荷 payload, 用 asynchNum ( 一个对象 )表示
        asyncDecrement: ({ commit }, asyncNum) => {
          setTimeout(() => {
            // asyncNum 对象可以是静态值
            commit('decrement', asyncNum.by);
          }, asyncNum.duration);
        }
      }
    });

    一个很好的功能是我们可以在 mutations 中返回整个状态对象,但是不必这样做,我们只使用我们需要的。时间穿梭测试(进入 mutations 中寻找错误)仍然可以工作。

    在组件中,我们将对 getters 使用 computed (这很重要,因为 value 值已经计算好了),在 methods 中使用 dispatch 来访问 mutations 和 actions

    `app.vue`:

    computed: {
      value() {
        return this.$store.getters.value;
      }
    },
    methods: {
      increment() {
        this.$store.dispatch('increment', 2)
      }
    }

    或者,您可以使用扩展运算符。我发现如果需要大量 mutations/actions 的时候是非常有用的:

    export default {
      // ...
      methods: {
        ...mapActions([
          'increment', // 将 this.increment() 映射到 this.$store.commit('increment')
          'decrement',
          'asyncIncrement'
        ])
      }
    }

    简单的实例

    让我们再看一看天气通知的程序, 在它的 Vuex store 中有少量且简单的状态。这是示例代码的仓库.

    See the Pen Vue Weather Notifier by Sarah Drasner (@sdras) on CodePen.

    `store.js`:

    import Vue from 'vue';
    import Vuex from 'vuex';
    
    Vue.use(Vuex);
    
    export const store = new Vuex.Store({
      state: {
        showWeather: false,
        template: 0
      },
        mutations: {
          toggle: state => state.showWeather = !state.showWeather,
          updateTemplate: (state) => {
            state.showWeather = !state.showWeather;
            state.template = (state.template + 1) % 4;
          }
      }
    });

    我们在这里设置了 showWeather 的状态,它的初始值为 false ,因为我们不希望任何动画立即执行,只有当用户点击按钮时才会执行。在 mutations 中,我们可以切换 showWeather 的状态。

    我们也将状态中的 template 设置为 0 。我们会在每个天气组件中循环使用这个数字。所以在 mutations 中,我们创建了一个名为 updateTemplate 的方法。它会同时切换 showWeather 的状态并且更新 template 加 1 后的数值,但是值为 4 时再点击会变成 0 。

    App.vue:

    <template>
      <div id="app">
        ...
        <g id="phonebutton" @click="updateTemplate" v-if="!showWeather">
           ...
        </g>
    
        <transition 
            @leave="leaveDroparea"
            :css="false">
          <g v-if="showWeather">
            <app-droparea v-if="template === 1"></app-droparea>
            <app-windarea v-else-if="template === 2"></app-windarea>
            <app-rainbowarea v-else-if="template === 3"></app-rainbowarea>
            <app-tornadoarea v-else></app-tornadoarea>
          </g>
        </transition>
        ...
    
      </div>
    </template>
    <script>
      import Dialog from './components/Dialog.vue';
      ...
      export default {
        computed: {
          showWeather() {
            return this.$store.state.showWeather;
          },
          template() {
            return this.$store.state.template;
          }
        },
        methods: {
          updateTemplate() {
            this.$store.commit('updateTemplate');
          }
        },
        ...
        components: {
          appDialog: Dialog,
          ...
        }
    }
    </script>

    `dialog.vue`:

    <script>
    export default {
      computed: {
        template() {
          return this.$store.state.template;
        }
      },
      methods: {
        toggle() {
          this.$store.commit('toggle');
        }
      },
      mounted () {
          //enter weather
          const tl = new TimelineMax();
        ...
      }
    }
    </script>

    在上面的代码中,App 组件使用了 showWeather 依次展示模板, 而 Dialog 组件只切换组件的可见性。在 App.vue 中,我们根据 App <template> 中的模板数值,通过第一章学过的的条件渲染来展示以及隐藏不同的子组件。在 App 中, 我们通过 computed 数值监听 store 中状态的变化,使用 methods 中的 toggle()updateTemplate() 提交 store 的 mutations 。

    这是一个基本示例,但是你可以了解如何处理有大量状态的复杂程序,这有利于在在一个地方管理所有的状态,而不是上下移动组件。尤其当同胞组件之间通信的时候。

    如果你想深入了解 Vuex , 可以看这篇 文档 。你肯能注意到我们在最后一个例子中使用了 <transition> 组件,还有大量动画。我们会在下一部分展开讨论。

  • 相关阅读:
    检测对象类型的两种方式,constructor属性和instanceof
    Javascript中的事件
    工厂模式、寄生构造函数模式、稳妥构造函数模式比较
    ECMAScript中的原型继承
    Javascript中new的作用
    js组合继承
    【原型模式】--重写原型对象prototype的影响
    动态原型模式
    js类型检测
    Javascript中的继承与复用
  • 原文地址:https://www.cnblogs.com/nzbin/p/6380670.html
Copyright © 2020-2023  润新知