vue中几种组件通信方式

vue中的常用几种组件通信方式

1、父向子,通过props传值

2、子向父,通过$emit触发自定义事件来传值

3、利用eventBus方式,可以实现平级组件之间的通信(有内存泄漏问题)

  1. 创建一个事件总线,例如demo中的eventBus,用它作为通信桥梁
  2. 在需要传值的组件中用bus.$emit触发一个自定义事件,并传递参数
  3. 在需要接收数据的组件中用bus.$on监听自定义事件,并在回调函数中处理传递过来的参数

解决bus内存泄漏的两种方法:

  1. 解决办法一:在每次调用方法前先解绑事件( bus. o f f ) , 然 后 在 重 新 绑 定 ( b u s . off ),然后在重新绑定( bus. off)(bus.on )
  2. 解决办法二:注册的总线事件(Bus)要在组件销毁时(beforeDestroy/destroyed)卸载,否则会多次挂载,造成触发一次但多个响应的情况

4、vue高级组件之provide / inject,父组件可以向儿子,孙子,从孙等等后代传值(v2.2新增)

父组件

<template>
<div class="test">
<son prop="data"></son>
</div>
</template>

<script>
export default {
name: 'Test',
provide: {
name: 'Garrett'
}
}

后代组件

<template>
<div>
{{name}}
</div>
</template>

<script>
export default {
name: 'Grandson',
inject: [name]
}

使用 provide / inject 可以保证父子单向数据流的清晰性。

5、Vuex方式,

如何使用呢?

const store = new Vuex.Store({
    state: {
        name: 'weish',
        age: 22
    },
    getters: {
        personInfo(state) {
            return `My name is ${state.name}, I am ${state.age}`;
        }
    }
    mutations: {
        SET_AGE(state, age) {
            commit(age, age);
        }
    },
    actions: {
        nameAsyn({commit}) {
            setTimeout(() => {
                commit('SET_AGE', 18);
            }, 1000);
        }
    },
    modules: {
        a: modulesA
    }
}

一个完整的vuex包含以上5个基本对象:

  • state:存储状态。也就是变量;
  • getters:派生状态。也就是set、get中的get,有两个可选参数:state、getters分别可以获取state中的变量和其他的getters。外部调用方式:store.getters.personInfo()。就和vue的computed差不多;
  • mutations:提交状态修改。也就是set、get中的set,这是vuex中唯一修改state的方式,但不支持异步操作。第一个参数默认是state。外部调用方 式:store.commit(‘SET_AGE’,18)。和vue中的methods类似。
  • actions:和mutations类似。不过actions支持异步操作。第一个参数默认是和store具有相同参数属性的对象。外部调用方式:store.dispatch(‘nameAsyn’)
  • modules:store的子模块,内容就相当于是store的一个实例。调用方式和前面介绍的相似,只是要加上当前子模块名,如:store.a.getters.xxx()

如何在vue-cli中使用呢:

一般目录结构如下:

├── index.html
├── main.js
├── components
└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── state.js          # 跟级别的 state
    ├── getters.js        # 跟级别的 getter
    ├── mutation-types.js # 根级别的mutations名称(官方推荐mutions方法名使用大写)
    ├── mutations.js      # 根级别的 mutation
    ├── actions.js        # 根级别的 action
    └── modules
        ├── m1.js         # 模块1
        └── m2.js         # 模块2

state.js如下:

const state = {
    name: 'weish',
    age: 22
};

export default state;

getters.js示例(我们一般使用getters来获取state的状态,而不是直接使用state):

export const name = (state) => {
    return state.name;
}

export const age = (state) => {
    return state.age
}

export const other = (state) => {
    return `My name is ${state.name}, I am ${state.age}.`;
}

mutation-type.js示例(我们会将所有mutations的函数名放在这个文件里):

export const SET_NAME = 'SET_NAME';
export const SET_AGE = 'SET_AGE';

mutations.js示例:

import * as types from './mutation-type.js';

export default {
    [types.SET_NAME](state, name) {
        state.name = name;
    },
    [types.SET_AGE](state, age) {
        state.age = age;
    }
};

actions.js示例(异步操作、多个commit时):

import * as types from './mutation-type.js';

export default {
    nameAsyn({commit}, {age, name}) {
        commit(types.SET_NAME, name);
        commit(types.SET_AGE, age);
    }
};

modules–m1.js示例(如果不是很复杂的应用,一般来讲是不会分模块的):

export default {
    state: {},
    getters: {},
    mutations: {},
    actions: {}
};

index.js示例(组装vuex):

import vuex from 'vuex';
import state from './state.js';
import * as getters from './getters.js';
import mutations from './mutations.js';
import actions from './actions.js';
import m1 from './modules/m1.js';
import m2 from './modules/m2.js';
import createLogger from 'vuex/dist/logger'; // 修改日志

vue.use(vuex);

const debug = process.env.NODE_ENV !== 'production'; // 开发环境中为true,否则为false

export default new vuex.Store({
    state,
    getters,
    mutations,
    actions,
    modules: {
        m1,
        m2
    },
    plugins: debug ? [createLogger()] : [] // 开发环境下显示vuex的状态修改
});

最后将store实例挂载到main.js里面的vue上去就行了

import store from './store/index.js';

new Vue({
  el: '#app',
  store,
  render: h => h(App)
});

在vue组件中使用时,我们通常会使用mapGetters、mapActions、mapMutations,然后就可以按照vue调用methods和computed的方式去调用这些变量或函数,示例如下:

import {mapGetters, mapMutations, mapActions} from 'vuex';

/* 只写组件中的script部分 */
export default {
    computed: {
        ...mapGetters([
            'name',
            'age'
        ])
    },
    methods: {
        ...mapMutations({
            setName: 'SET_NAME',
            setAge: 'SET_AGE'
        }),
        ...mapActions([
            nameAsyn
        ])
    }
};

6、小型的store模式,用不到vuex的时候,或是在封装的组件内部使用,譬如element-ui中的table组件。

vue官方文档说的很清除,就算在新建一个store.js的文件。

// store.js
var store = {
  debug: true,
  state: {
    message: 'Hello!'
  },
  setMessageAction(newValue) {
    if (this.debug) console.log('setMessageAction triggered with', newValue)
    this.state.message = newValue
  },
  clearMessageAction() {
    if (this.debug) console.log('clearMessageAction triggered')
    this.state.message = ''
  }
}
export default store

在需要使用的组件中,import一下,

// demoA.vue
<template>
  <div class="hello">
    <button @click="change">改变</button>
    {{sharedState}}
  </div>
</template>

<script>
import store from './store.js'
export default {
  name: 'DemoA',
  components: {},
  data() {
    return {
      sharedState: store.state.message
    }
  },
  created() {},
  mounted() {},
  methods: {
    change() {
      store.setMessageAction('Hellow vue!')
    }
  }
}
</script>

在这个组件中点击按钮,调用了store.js上的方法修改了store.js中的值,
在另外一个也引入了store.js的组件中,它上面的关联store.js中的值就会跟着改变。

// demoB.vue
<template>
  <div class="hello">
    {{sharedState}}
  </div>
</template>

<script>
import store from './store.js'
export default {
  name: 'DemoB',
  components: {},
  data() {
    return {
      sharedState: store.state.message
    }
  },
  created() {},
  mounted() {},
  methods: {
  }
}
</script>

注意:这个时候,数据不说响应式的,有两种解决办法。
方案1,store.js包装一下,通过Vue.observalbe包装一下就变成了相应式的。

state: Vue.observable({
    message: 'Hello!'
  }),

方案二:watch属性

<template>
  <div class="hello">
    <button @click="change">改变</button>
    {{sharedState.message}}
  </div>
</template>

<script>
import store from '../store.js'
export default {
  name: 'Prarent',
  components: {},
  data() {
    return {
      sharedState: store.state
    }
  },
  watch: {
    'sharedState.state': function(newV) {
      this.sharedState = newV
    }
  },
  created() {},
  mounted() {},
  methods: {
    change() {
      store.setMessageAction('Hellow vue!')
    }
  }
}
</script>

方案三、computed属性

<template>
  <div class="hello">
    <button @click="change">改变</button>
    {{aMessage}}
  </div>
</template>

<script>
import store from '../store.js'
export default {
  name: 'Prarent',
  components: {},
  data() {
    return {
      sharedState: store.state
    }
  },
  computed: {
    aMessage() {
      return this.sharedState.message
    }
  },
  created() {},
  mounted() {},
  methods: {
    change() {
      store.setMessageAction('Hellow vue!')
    }
  }
}
</script>

6、mitt.js插件

随着vue3.x的发布,上面第三种通过实例化一个vue实例来做的eventBus方案已不支持。这里,我们可以采用官方推荐的mitt 插件实现。 整个源代码打包后职业200bit,很小很轻量,没有其他依赖。

参考文章:
https://segmentfault.com/a/1190000012015742

https://www.cnblogs.com/yszblog/p/10135969.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值