09:vuex组件间通信
1.1 vuex简介
官网:https://vuex.vuejs.org/zh/guide/
参考博客:https://www.cnblogs.com/first-time/p/6815036.html
1、什么是Vuex?
      1. 官方说法:Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。
      2. 它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
      3. 个人理解:Vuex是用来管理组件之间通信的一个插件
2、vuex作用
      1. 我们知道组件之间是独立的,组件之间想要实现通信,我目前知道的就只有props选项,但这也仅限于父组件和子组件之间的通信。
      2. 如果兄弟组件之间想要实现通信呢?当做中大型项目时,面对一大堆组件之间的通信,还有一大堆的逻辑代码,会不会很抓狂??
      3. 那为何不把组件之间共享的数据给“拎”出来,在一定的规则下管理这些数据呢? 这就是Vuex的基本思想了。
总结:使用vuex作用就是实现组件间数据共享
3、vuex原理
1. vue团队为了简化组件间的通信,将state抽象成一个单例模式,将其放到全局,让各个组件都能共享使用
2. vuex数据传递是单向的:action ---> mutation ---> state ---> component ---> action
          vue component指的就是我门定义的组件
			          action 交互中产生的动作
			          mutations 动作产生的修改数据的行为
			          state 共享数据
3. vuex设计的时候相对修改的行为做单测(测试),开发了devtools来做测试,只能检测同步的操作
4. 规范定义:只能在mutations中做同步操作,所以增加了action来异步处理数据
5. 将mutations中的异步操作转移到actions中了,这样就可以测试同步的操作了
4、vuex使用场景
1. 如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
2. 如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。
5、vuex流程图
      1、vue组件(Vue Components)会 发出(Dispatch)一些动作(Actions)
      2、动作会 提交(Commit)一个对数据的改变(Mutations)
      3、提交的改变数据存放在 状态(State) 中的
      4、最后 State将改变的数据再 渲染(Render)到组件(Vue Components),展示被改变后的数据
      
1.2 vuex使用(vuex使用分为以下两步)
1、第一步:实例化一个store
注:vuex.store用来创建store,参数对象中,可以定义各个模块
1. state定义状态模块(存储数据的),存放组件之间共享的数据
2. getters定义动态的数据,类似组件中的computed动态数据
3. mutations:定义改动states的动作行为,类似观察者模式中的订阅事件on
4. action:定义这些交互动作(异步),类似观察者模式中的订阅事件方法on(只不过是用来处理异步的)
2、第二步:在vue实例化对象中,注册store
1. 将第一步的实例化对象注册进来,注册路由后,组件实例化对象有了$route属性对象
2. 注册store,组件实例化对象有了$store属性对象,这个store对象有下面这些方法
$.store.commit用来触发mutations订阅的消息
$.store.dispatch用来触发action订阅的消息的
$.store.state使用状态中的数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<h1 @click="$store.commit('reduce', 20);">vue实例化对象:点击减20</h1>
<h2 @click="$store.dispatch('dealNum', 10, 20, 30)">更新数据:将num两秒后重置为:10</h2>
<h1>state中的数据 {{$store.state.num}}</h1>
<h2>双倍num {{$store.getters.doubleNum}}</h2>
<router-view></router-view> <!-- 定义渲染的容器 -->
</div>
<template id="home">
<div>
<h1 @click="$store.commit('add', 10, 'hello')">home:点击加10</h1>
<h2>home组件中 {{$store.state.num}}</h2>
<router-view></router-view> <!-- 第一步 定义子路由渲染的容器 -->
</div>
</template>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript" src="vue-router.js"></script>
<script type="text/javascript" src="vuex.js"></script>
<script type="text/javascript">
// 定义组件
var Home = {
template: '#home'
}; // 第一步 定义路由规则
var routes = [
{
path: '/home',
name: 'home',
component: Home
}
]; // 定义store第一步 定义store实例化对象
var store = new Vuex.Store({
state: { // 定义状态
num: 0
},
getters: { // 定义动态绑定的数据
doubleNum: function(state) {
return state.num * 2;
}
},
mutations: { // 修改的消息
add: function(state, num) { // 增加num值
state.num += num;
},
reduce: function(state, num) { // 减少num值
state.num -= num;
},
resetNum: function(state, num) {
state.num = num;
}
},
actions: { // 定义actions
dealNum: function(context, num) {
setTimeout(function() { // 我们可以异步提交
context.commit('resetNum', num)
}, 2000)
}
}
}); // 第二步 实例化路由对象
var router = new VueRouter({
routes: routes // 定义路由规则
}); // 第三步 注册路由 和 store对象
var app = new Vue({
el: '#app', // 注册路由
router: router,
store: store // 使用vuex第二步 注册store
})
</script>
</body>
</html>
vuex基本使用
    
1.3 vuex基本用法
1、初始化环境
vue init webpack-simple vuex-demo
cd vuex-demo
npm install
cnpm install vuex -S # 安装vuex
npm run dev
2、在main.js中导入并配置store.选项(创建 sre/store.js文件,可以是一个空文件)
1. 在main.js中导入 store对象: import store from './store'
2. 配置store选项后,vue就会自动将store对象注入到所有子组件中,在子组件中通过this.$store 访问store对象
import Vue from 'vue'
import App from './App.vue' import store from './store' // 导入store对象 new Vue({
store, // 配置store选项后,指定为store对象,vue就会自动将store对象注入到所有子组件中
// 在子组件中通过this.$store 访问store对象
el: '#app',
render: h => h(App)
});
main.js
3、编辑store.js文件
注1:Vuex的核心是Store(仓库),相当于是一个容器,一个store实例中包含以下属性的方法:
注2:不能直接修改数据,必须显式提交变化,目的是为了追踪到状态的变化
1) state 定义属性(状态、数据)
2) getters 用来获取属性
3) actions 定义方法(动作)
4) commit 提交变化,修改数据的唯一方式就是显式的提交mutations
5) mutations 定义变化
/**
* vuex配置:store.js
**/
import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex); //1、定义属性(数据)
var state = {
count:6
}; //2、定义gettters获取属性:在App.vue中使用 辅助函数 访问 vuex 组件中数据调用此函数
var getters={
count(state){
return state.count;
}
}; //3、定义actions提交变化:其他组件中调用的方法()
const actions = {
increment({commit,state}){ // context包含属性(函数):commit,dispatch,state
if(state.count<10){ // 当count数值小于10才会提交改变(大于10就不增加了)
commit('increment');
}
// 1、commit提交改变(不能直接修改数据)
// 2、commit中的参数 'increment' 是自定义的,可以认为是类型名
// 3、commit提交的改变会给 mutations
}
}; //4、定义mutations定义变化,处理状态(数据的改变)
const mutations={
increment(state){
state.count++;
}
}; // 创建一个store对象(对象里定义需要导出的变量)
const store=new Vuex.Store({
state,
getters,
actions,
mutations,
}); // 导出store对象
export default store;
sre/store.js
4、 编辑App.vue
1. 在子组件中访问store对象的两种方式
方式1:通过this.$store访问
方式2:通过辅助函数:mapState、mapGetters、mapActions 访问,vuex提供了两个方法
mapState 获取state
mapGetters 获取getters(获取属性:数据)
mapActions 获取actions(获取方法:动作)
<template>
<div id="app">
<button @click="increment">增加</button>
<button>减小</button>
<p>当前数字为:{{count}}</p>
</div>
</template> <script>
import {mapGetters,mapActions} from 'vuex' export default {
name: 'app',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}, // 方式二:使用 辅助函数 访问 vuex 组件中数据
computed:mapGetters([ // 这里定义一个数组,数组中指定要从vuex中获取的属性
'count', // 这里的count就是 store.js中getters定义的属性
]),
methods:mapActions([ // 这里定义一个数组,数组中指定要从vuex中获取的方法
'increment' // 这里的increment就是 store.js中actions定义的函数
]) // // 方式一:通过this.$store访问vuex组件中的数据
// computed:{
// count(){
// return this.$store.state.count;
// }
// }
}
</script> <style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
} h1, h2 {
font-weight: normal;
} ul {
list-style-type: none;
padding: 0;
} li {
display: inline-block;
margin: 0 10px;
} a {
color: #42b983;
}
</style>
App.vue
5、效果图
      
6、异步操作
import Vue from 'vue'
import App from './App.vue' import store from './store' // 导入store对象 new Vue({
store, // 配置store选项后,指定为store对象,vue就会自动将store对象注入到所有子组件中
// 在子组件中通过this.$store 访问store对象
el: '#app',
render: h => h(App)
});
main.js
/**
* vuex配置:store.js
**/
import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex); //1、定义属性(数据)
var state = {
count:6
}; //2、定义gettters获取属性:在App.vue中使用 辅助函数 访问 vuex 组件中数据调用此函数
var getters={
count(state){
return state.count;
}
}; //3、定义actions提交变化:其他组件中调用的方法()
const actions = {
increment({commit,state}){ // context包含属性(函数):commit,dispatch,state
if(state.count<10){ // 当count数值小于10才会提交改变(大于10就不增加了)
commit('increment');
}
// 1、commit提交改变(不能直接修改数据)
// 2、commit中的参数 'increment' 是自定义的,可以认为是类型名
// 3、commit提交的改变会给 mutations
}, /** 定义异步操作 **/
incrementAsyn({commit,state}){
var p=new Promise((resolve,reject) => { // 异步操作
setTimeout(() => {
resolve()
},3000)
});
p.then(() => { // 上面执行完成后才执行 p.then()
commit('increment');
}).catch(() => { // 异常处理
console.log('异步操作失败')
})
}
}; //4、定义mutations定义变化,处理状态(数据的改变)
const mutations={
increment(state){
state.count++;
}
}; // 创建一个store对象(对象里定义需要导出的变量)
const store=new Vuex.Store({
state,
getters,
actions,
mutations,
}); // 导出store对象
export default store;
store.js
<template>
<div id="app">
<button @click="increment">增加</button>
<button @click="incrementAsyn">异步增加</button>
<p>当前数字为:{{count}}</p>
</div>
</template> <script>
import {mapGetters,mapActions} from 'vuex' export default {
name: 'app',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}, // 方式二:使用 辅助函数 访问 vuex 组件中数据
computed:mapGetters([ // 这里定义一个数组,数组中指定要从vuex中获取的属性
'count', // 这里的count就是 store.js中getters定义的属性
]),
methods:mapActions([ // 这里定义一个数组,数组中指定要从vuex中获取的方法
'increment', // 这里的increment就是 store.js中actions定义的函数
'incrementAsyn' // 异步提交
])
}
</script> <style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
} h1, h2 {
font-weight: normal;
} ul {
list-style-type: none;
padding: 0;
} li {
display: inline-block;
margin: 0 10px;
} a {
color: #42b983;
}
</style>
App.vue
    
1.4 分模块组织Vuex
1、初始化环境
vue init webpack-simple vuex-demo2
cd vuex-demo2
npm install
cnpm install vuex -S # 安装vuex
npm run dev
2、Vuex模块化结构
|-src
|-main.js // 项目入口文件
|-App.vue |-store
|-index.js // 我们组装模块并导出 store 的地方
|-getters.js // 公共的 getters (用来获取公共属性)
|-actions.js // 根级别的 action (提交公共改变)
|-mutations.js // 根级别的 mutation (处理状态,数据的改变)
|-types.js // 定义类型常量(commit中提交的常量) |-modules //分为多个模块,每个模块都可以拥有自己的state、getters、actions、mutations
|-user.js // 用户模块(这里仅以user模块作为事例)
Vuex模块化结构
3、代码事例
import Vue from 'vue'
import App from './App.vue' import store from './store/index.js' new Vue({
store,
el: '#app',
render: h => h(App)
});
main.js
<template>
<div id="app"> <button @click="increment">增加</button>
<button @click="decrement">减小</button>
<button @click="incrementAsync">增加</button>
<p>当前数字为:{{count}}</p>
<p>{{isEvenOrOdd}}</p> </div>
</template> <script>
import {mapState,mapGetters,mapActions} from 'vuex' export default {
name: 'app',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:mapGetters([
'count',
'isEvenOrOdd'
]),
methods:mapActions([
'increment',
'decrement',
'incrementAsync'
])
}
</script> <style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
} h1, h2 {
font-weight: normal;
} ul {
list-style-type: none;
padding: 0;
} li {
display: inline-block;
margin: 0 10px;
} a {
color: #42b983;
}
</style>
App.vue
import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex); import getters from './getters.js'
import actions from './actions.js'
import user from './modules/user.js' export default new Vuex.Store({
getters,
actions,
modules:{
user
}
});
store/index.js
const getters={
    isEvenOrOdd(state){
        return state.user.count%2==0?'偶数':'奇数';  // user模块中的count
    }
};
export default getters;
store/getters.js
import types from './types.js'
const actions={
    incrementAsync({commit,state}){
        //异步操作
        var p=new Promise((resolve,reject) => {
            setTimeout(() => {
                resolve();
            },3000);
        });
        p.then(() => {
            commit(types.INCREMENT);
        }).catch(() => {
            console.log('异步操作');
        });
    }
};
export default actions;
store/actions.js
/**
* 定义类型常量
*/ const INCREMENT='INCREMENT';
const DECREMENT='DECREMENT'; export default {
INCREMENT,
DECREMENT
}
store/types.js
/**
* 用户模块
*/ import types from '../types.js' const state={
count:6
}; var getters={
count(state){
return state.count;
}
}; const actions = {
increment({commit,state}){
commit(types.INCREMENT); //提交一个名为increment的变化,名称可自定义,可以认为是类型名
},
decrement({commit,state}){
if(state.count>10){
commit(types.DECREMENT);
}
}
}; const mutations={
[types.INCREMENT](state){ // ES6中中括号里表示 变量
state.count++;
},
[types.DECREMENT](state){
state.count--;
}
}; export default {
state,
getters,
actions,
mutations
}
store/modules/user.js
4、项目结构
       
   
5、简化版
import Vue from 'vue'
import App from './App.vue' import store from './store/index' new Vue({
store,
el: '#app',
render: h => h(App)
})
main.js
<template>
<div id="app">
<h1>app</h1>
<p>数据:{{count}}</p>
<p @click="increment">增加</p>
</div>
</template> <script>
import {mapGetters, mapActions} from 'vuex' export default {
name: 'app',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
computed:mapGetters([
'count',
]),
methods:mapActions([
'increment'
])
}
</script> <style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
} h1, h2 {
font-weight: normal;
} ul {
list-style-type: none;
padding: 0;
} li {
display: inline-block;
margin: 0 10px;
} a {
color: #42b983;
}
</style>
App.vue
import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex); // import getters from './getters.js'
// import actions from './actions.js'
import user from './modules/user.js' export default new Vuex.Store({
// getters,
// actions,
modules:{
user
}
});
src\store\index.js
//1、定义属性(数据)
var state = {
count:6
}; //2、定义gettters获取属性:在App.vue中使用 辅助函数 访问 vuex 组件中数据调用此函数
var getters = {
count(state){
return state.count
}
}; //3、定义actions提交变化:其他组件中调用的方法()
var actions = {
increment({commit,state}){
commit('increment')
}
}; //4、定义mutations定义变化,处理状态(数据的改变)
var mutations = {
increment(state){
state.count++
}
}; //5、导出store对象
export default {
state,
getters,
actions,
mutations
}
src\store\modules\user.js
    
09:vuex组件间通信的更多相关文章
- Vuex状态管理——任意组件间通信
		核心概念 在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信. 每一个 Vuex 应用的 ... 
- 聊聊Vue.js组件间通信的几种姿势
		写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出. 文章的原地址:https://github.com/a ... 
- python 全栈开发,Day91(Vue实例的生命周期,组件间通信之中央事件总线bus,Vue Router,vue-cli 工具)
		昨日内容回顾 0. 组件注意事项!!! data属性必须是一个函数! 1. 注册全局组件 Vue.component('组件名',{ template: `` }) var app = new Vue ... 
- Angular : 响应式编程, 组件间通信, 表单
		Angular 响应式编程相关 ------------------------------------------------------------------------------------ ... 
- vue组件间通信六种方式(完整版)
		本文总结了vue组件间通信的几种方式,如props. $emit/ $on.vuex. $parent / $children. $attrs/ $listeners和provide/inject,以 ... 
- Vue组件间通信6种方式
		摘要: 总有一款合适的通信方式. 作者:浪里行舟 Fundebug经授权转载,版权归原作者所有. 前言 组件是 vue.js 最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的 ... 
- vue-learning:31 - component - 组件间通信的6种方法
		vue组件间通信的6种方法 父子组件通信 prop / $emit 嵌套组件 $attrs / $liteners 后代组件通信 provide / inject 组件实例引用 $root / $pa ... 
- Vue中组件间通信的方式
		Vue中组件间通信的方式 Vue中组件间通信包括父子组件.兄弟组件.隔代组件之间通信. props $emit 这种组件通信的方式是我们运用的非常多的一种,props以单向数据流的形式可以很好的完成父 ... 
- React独立组件间通信联动
		React是现在主流的高效的前端框架,其官方文档 http://reactjs.cn/react/docs/getting-started.html 在介绍组件间通信时只给出了父子组件间通信的方法,而 ... 
随机推荐
- go https ajax
			这个很好用啊,估计大有用武之地 你会喜欢 //https-ajax.go package main import ( "fmt" "io" "net/ ... 
- unity3d对象池的使用
			说对象池之前首先来看看单例类和单例脚本的区别.这里有介绍 http://blog.csdn.net/lzhq1982/article/details/12649281 使用对象池的好处是不用每次都创建 ... 
- 永恒之蓝msf下  ms17_010 (64位kali下安装wine32)
			本次用到的环境: kali(2016.2)32位系统.ip地址:192.168.1.104 目标靶机为:win7sp1x64系统(关闭防火墙),ip地址:192.168.1.105 ========= ... 
- JavaScript三种判断语句和三元运算符
			三种判断语句 1.if结构 语法:if(条件){条件满足时执行的代码块} 2.if else结构 语法:if(条件){条件满足时执行的代码块} else{条件不满足时执行的代码块} 3.if el ... 
- linux设置时间显示格式和系统版本
			[修改显示日期格式] vim /etc/bashrc alias ll='ls -l --time-style="+%Y-%m-%d %H:%M:%S"' alias date=' ... 
- ReactiveCocoa(III)
			flatMap(FlattenStrategy.latest) observe(on: UIScheduler()).startWithResult 切换线程: observeOn(UISchedul ... 
- asp.net web form 的缺点
			与mvc相比,web form 的缺点: 代码架构麻烦. 以页面或控件为单位,把逻辑放在了一起,代码架构简单.平铺直叙,修改.维护比较麻烦. 不方便单元测试. 功能堆加在了一起,不方便对单个的功能进 ... 
- python seek()方法报错:“io.UnsupportedOperation: can't do nonzero cur-relative seeks”
			今天使用seek()时报错了, 看下图 然后就百度了一下,找到了解决方法 这篇博客https://www.cnblogs.com/xisheng/p/7636736.html 帮忙解决了问题, 照理说 ... 
- python 文件路径名,文件名,后缀名的操作
			需要使用路径名来获取文件名,目录名,绝对路径等等. 使用os.path 模块中的函数来操作路径名.下面是一个交互式例子来演示一些关键的特性: >>> import os >&g ... 
- Gamma函数深入理解
			Gamma函数 当n为正整数时,n的阶乘定义如下:n! = n * (n - 1) * (n - 2) * … * 2 * 1. 当n不是整数时,n!为多少?我们先给出答案. 容易证明,Γ(x + 1 ... 
