Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vue跨组件通信的几种方法 #20

Open
zhouwenbin opened this issue Jun 30, 2016 · 8 comments
Open

vue跨组件通信的几种方法 #20

zhouwenbin opened this issue Jun 30, 2016 · 8 comments

Comments

@zhouwenbin
Copy link
Owner

zhouwenbin commented Jun 30, 2016

在开发组件的时候,一定会遇到组件的通信,比如点击一个图标出现弹窗和蒙层,这三个分别是不同的组件。管理他们之间的状态就成了问题。

props双向绑定

官方文档在这,通过sync双向绑定,属性变化会同步到所有组件,这也是最简单的实现方式,缺点是属性会比较多。实现方式如下
App.vue文件

<template>
  <div id="app">
    <mask :hide-mask.sync="hideMask"></mask>
    <dialog :hide-dialog.sync="hideDialog" :hide-mask.sync="hideMask"></dialog>
    <dialog-icon :hide-dialog.sync="hideDialog" :hide-mask.sync="hideMask"></dialog-icon>
  </div>
</template>

<script>
import mask from './components/mask/index'
import dialog from './components/dialog/index'
import dialogIcon from './components/dialog-icon/index'

export default {
  components: {
    mask,
    dialog,
    dialogIcon
  },
  data () {
    return {
      hideMask: true,
      hideDialog: true
    }
  }
}
</script>

component/dialog/index.vue文件

<template>
  <section class="dialog" :class="{ 'hide': hideDialog }">
    <div class="dialog-close" @click="hide()"></div>
  </section>
</template>

<script>
export default {
  props: ['hideDialog', 'hideMask'],
  methods: {
    hide () {
      this.hideDialog = !this.hideDialog
      this.hideMask = !this.hideMask
    }
  }
}
</script>

component/dialog-icon/index.vue文件

<template>
  <section class="dialog-icon" @click="show()">点击出现弹窗</section>
</template>

<script>
export default {
  props: ['hideDialog', 'hideMask'],
  methods: {
    show () {
      this.hideDialog = !this.hideDialog
      this.hideMask = !this.hideMask
    }
  }
}
</script>

component/mask/index.vue文件

<template>
  <div class="mask" :class="{ 'hide': hideMask }"></div>
</template>

<script>
export default {
  props: ['hideMask']
}
</script>

自定义事件

官方文档在这,子组件$dispatch()派发事件传递给父组件,父组件$broadcast()广播事件传递给子组件,这种方式虽然减少了props的使用,但是需要额外定义几个事件,状态多了就会变得很复杂,实现方法如下
App.vue文件

<template>
  <div id="app">
    <mask></mask>
    <dialog></dialog>
    <dialog-icon></dialog-icon>
</template>

<script>
import mask from './components/mask/index'
import dialog from './components/dialog/index'
import dialogIcon from './components/dialog-icon/index'

export default {
  components: {
    mask,
    dialog,
    dialogIcon
  },
  data () {
    return {
      hideMask: true,
      hideDialog: true
    }
  },
  events: {
    'dialog-dispatch' () {
      this.hidedialog = !this.hidedialog
      this.$broadcast('dialog-broadcast')
    },
    'mask-dispatch' () {
      this.hideMask = !this.hideMask
      this.$broadcast('mask-broadcast')
    }
  }
}
</script>

component/dialog-icon/index.vue文件

<template>
  <section class="dialog-icon" @click="show()">点击出现弹窗</section>
</template>

<script>
export default {
  methods: {
    show () {
      this.$dispatch('dialog-dispatch')
      this.$dispatch('mask-dispatch')
    }
  },
  events: {
    'dialog-broadcast' () {
      this.hideDialog = !this.hideDialog
    }
  },
  data () {
    return {
      hideDialog: this.$parent.hideDialog,
      hideMask: this.$parent.hideMask
    }
  }
}
</script>

component/dialog/index.vue文件

<template>
  <section class="dialog" :class="{ 'hide': hideDialog }">
    <div class="dialog-close" @click="hide()"></div>
  </section>
</template>

<script>
export default {
  methods: {
    hide () {
      this.$dispatch('dialog-dispatch')
      this.$dispatch('mask-dispatch')
    }
  },
  events: {
    'dialog-broadcast' () {
      this.hideDialog = !this.hideDialog
    }
  },
  data () {
    return {
      hideDialog: this.$parent.hideDialog,
      hideMask: this.$parent.hideMask
    }
  }
}
</script>

component/mask/index.vue文件

<template>
  <div class="mask" :class="{ 'hide': hideMask }"></div>
</template>

<script>
export default {
  data () {
    return {
      hideMask: this.$parent.hideMask
    }
  },
  events: {
    'mask-broadcast' () {
      this.hideMask = !this.hideMask
    }
  }
}
</script>

Vuex

官方文档在这里,状态统一放store管理,修改状态通过mutations,组件通过action调用mutations,虽然有点绕,但是所有东西放一起后期会更好维护,实现方法如下
App.vue文件

<template>
  <div id="app">
    <mask></mask>
    <dialog></dialog>
    <dialog-icon></dialog-icon>
  </div>
</template>

<script>
import mask from './components/mask/index'
import dialog from './components/dialog/index'
import dialogIcon from './components/dialog-icon/index'

export default {
  components: {
    mask,
    dialog,
    dialogIcon
  }
}
</script>

component/dialog/index.vue文件

<template>
  <section class="storehouse dialog" :class="{ 'hide': isHideDialog }">
    <div class="dialog-close" @click="hideDialog()"></div>
  </section>
</template>

<script>
import { hideDialog } from '../../vuex/actions'

export default {
  vuex: {
    state: {
      isHideDialog: state => state.isHideDialog
    },
    actions: {
      hideDialog
    }
  }
}
</script>

component/dialog-icon/index.vue文件

<template>
  <section class="storehouse-icon" @click="hideDialog()">点击出现弹窗</section>
</template>

<script>
import { hideDialog } from '../../vuex/actions'

export default {
  vuex: {
    actions: {
      hideDialog
    }
  }
}
</script>

component/mask/index.vue文件

<template>
  <div class="mask" :class="{ 'hide': isHideMask }"></div>
</template>

<script>
export default {
  vuex: {
    state: {
      isHideMask: state => state.isHideMask
    }
  }
}
</script>

vuex/store.js文件

import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutations'

Vue.use(Vuex)

const state = {
  isHideMask: true,
  isHideDialog: true
}

const store = new Vuex.Store({
  state,
  mutations
})

if (module.hot) {
  module.hot.accept(['./mutations'], () => {
    const mutations = require('./mutations').default
    store.hotUpdate({
      mutations
    })
  })
}

export default store

vuex/mutations.js文件

import {
  HIDEDIALOG
}
from './mutation-types'

export
default {
  [HIDEDIALOG] (state) {
    state.isHideDialog = !state.isHideDialog
    state.isHideMask = !state.isHideMask
  }
}

vuex/mutations-types.js文件

export const HIDEDIALOG = 'HIDEDIALOG'

vuex/action.js文件

import { HIDEDIALOG } from './mutation-types'

export const hideDialog = ({ dispatch }) => dispatch(HIDEDIALOG)
@gaoryrt
Copy link

gaoryrt commented Aug 9, 2016

正好学习的时候看到,言简意赅,非常感谢~

@jiangtao
Copy link

jiangtao commented Oct 7, 2016

mark

@RunningV
Copy link

RunningV commented Dec 9, 2016

🐶 🐶 🐶 🐶 🐶

@zhangwei900808
Copy link

mark

@old-zsh
Copy link

old-zsh commented Feb 27, 2017

我用你的vuex,报错,我也不知道为什么

@zhouwenbin
Copy link
Owner Author

@15831929073 文章是1.0版本的

@zycxwd
Copy link

zycxwd commented Apr 18, 2017

66666

@xuxuechao6
Copy link

mark

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants