Vuex是Vue中的一个状态管理插件,它采用集中式存储管理所有组件的公共状态, 并以相应的规则保证状态变化的一致性。
并不是所有情况都需要使用 Vuex, 通常是在一个界面中有多个组件同时操作一个数据时需要使用它。下面,我们通过一个例子来说明。
不使用 Vuex 的情况
我们定义了一个名为 TodoWidget 的组件,在组件中可以操作一个由外部(父组件)传入的值: title。 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <template> <div class="card"> <div> <input v-model="title" placeholder="Please input new value"/> </div> <div> title: {{ title }} </div> </div>
</template>
<script> export default { name: 'TodoWidget', props: ['title'] } </script>
<style> .card { border: 1px solid black; margin: 10px 10px } </style>
|
现在,我们在项目的 App.vue 组件中使用这个控件,而且会加入两个 TodoWidget 的实例,修改后的 App.vue 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <template> <div id="app"> <div> <h3>First</h3> <todo-widget v-bind:title='title'></todo-widget> </div> <div> <h3>Second</h3> <todo-widget v-bind:title='title'></todo-widget> </div> <div> <h1>Value</h1> {{ title }} </div> </div> </template>
<script> import TodoWidget from './components/TodoWidget'
export default { name: 'app', components: { TodoWidget }, data() { return { title: '' } } } </script>
<style>
</style>
|
从代码中可以看到,我们在 App.vue 中放置了两个 TodoWidget 控件,并且传递了同一个值 title 给到这两个控件。我们期望的行为是改变其中一个的值,另一个也会自动改变。
但是,实际的运行效果并不是这样,两个组件实例中的 title 完全不能同步。
使用 Vuex
加入 vuex 插件
执行以下代码,在项目中加入 vuex
新增一个Store
- 加入一个 store.js 文件,在文件中定义一个 Store 并在其中加入状态 title, 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import Vue from 'vue' import Vuex from 'vuex'
Vue.use( Vuex );
const store = new Vuex.Store({ state: { title: '' }, mutations: { update (state, ctitle) { state.title = ctitle } } })
export default store
|
- 修改 main.js 文件,将定义好的 store 加入到 Vue 对象中, 代码如下:
1 2 3 4 5 6 7 8 9 10 11
| import Vue from 'vue' import App from './App.vue'
import store from './store'
Vue.config.productionTip = false
new Vue({ store, render: h => h(App), }).$mount('#app')
|
- 修改 TodoWidget 的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <template> <div class="card"> <div> <input v-model="ctitle" placeholder="Please input new value" /> </div> <div> <button v-on:click="change">Change</button> </div> <div> title: {{ this.$store.state.title }} </div> </div>
</template>
<script> export default { name: 'TodoWidget', data() { return { ctitle: '' } }, methods: { change: function() { this.$store.commit('update', this.ctitle) } } } </script>
<style> .card { border: 1px solid black; margin: 10px 10px } </style>
|
- 修改 App.vue 文件,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <template> <div id="app"> <div> <h3>First</h3> <todo-widget ></todo-widget> </div> <div> <h3>Second</h3> <todo-widget></todo-widget> </div> <div> <h1>Value</h1> {{ this.$store.state.title }} </div> </div> </template>
<script> import TodoWidget from './components/TodoWidget'
export default { name: 'app', components: { TodoWidget } } </script>
<style>
</style>
|
现在,可以在其中一个 TodoWidget 中输入新的 title值,然后按下 Change 按钮,可以看到状态被同步。