We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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中的组件通信是一个比较复杂的一个知识点,涵盖各种api和语法糖,接下来我们分别来介绍下常见的九种组件通信方法
这是我们日常开发最常见的一种父子组件通信的方法了,我们来看一个简单的例子,后文全部方法都围绕这个例子进行
// App.vue <Parent /> import Parent from './components/Parent' export default { components: { Parent, } }
// Parent.vue <Son @change="change" :number="number" /> import Son from './Son' export default { data() { return { number: 100, } }, methods: { change(newVale) { this.number = newVale } } }
// Son.vue <div>子组件 {{ number }} <button @click="change">修改父组件的值</button> </div> export default { props: { number: { type: Number } }, methods: { change() { this.$emit('change', 200) } } }
我们可以发现,父组件通过props将数据传递给子组件,而子组件可以通过$emit的方式调用父组件的方法修改父组件的值,我们知道Vue和React都是单向数据流,也就是数据是从上往下传递的,当我们子组件修改父组件的数据的时候,自己拿到的数据也会随着修改
props
$emit
介绍了最常见的一种用法,我们接下来看下一种更暴力的用法 $parent 和 $children
$parent
$children
// Son.vue <button @click="change">修改父组件的值</button> methods: { change() { this.$parent.change(200) } }
我们可以通过$parent拿到父组件的实例,然后调用父组件的方法改变父组件的数据,同样道理我们在父组件中也可以使用$children的方法修改子组件的值,这里就不演示啦
这个也是在element ui 的源码中看到的一个方法
// main.js Vue.prototype.$dispatch = function(eventName, newValue) { let parent = this.$parent while (parent) { parent.$emit(eventName, newValue) parent = parent.$parent // 继续递归接着往上找 } }
我们将$dispatch挂载到Vue的原型上方便调用,我们可以看到,$dispatch的原理是一直递归找父组件,然后执行父组件中对应的$emit方法,我们来看下怎么用
$dispatch
// Parent.vue <div>父组件 <Son @change="change" :number="number" /> </div> export default { data() { return { number: 100, } }, methods: { change(newVale) { this.number = newVale } } }
// Son.vue <div>子组件 {{ number }} <br/> <Grandson /> </div> export default { props: { number: { type: Number } }, }
// Grandson.vue <div>孙组件 <button @click="change">修改父组件的值</button> </div> export default { methods: { change(newVale) { this.$dispatch('change', 200) } } }
我们可以发现在孙子组件中调用$dispatch方法,他会触发所以父组件中的$emit('xxx', xxx)方法,达到修改对应父组件数据的目的
$emit('xxx', xxx)
$broadcast的原理和$dispatch很像,$dispatch是一直往父元素上面找,而$broadcast刚刚相反,一直往子元素上面找对应的方法执行
$broadcast
// main.js Vue.prototype.$broadcast = function(eventName, newValue) { let children = this.$children function broad(children) { children.forEach(child => { child.$emit(eventName, newValue) if (child.$children) { broad(child.$children) } }) } broad(children) }
同样是挂载原型的方法,有了这个方法我们就可以在父组件中主动调用全部后代组件中的$emit方法了
接下来我们看到的这种用法其实是 props 和 $emit的一些语法糖, 我们来看下使用props 和 $emit时候的代码
// Parent.vue <Son @update:number="newValue =>number = newValue" :number="number" />
// Son.vue <button @click="change">更新父组件的方法</button> methods: { change() { this.$emit('update:number', 200) } }
我们只需要将$emit(fn)中的fn改为update:xxx就可以了,其中xxx为父组件传递给子组件的数据名
$emit(fn)
update:xxx
为什么要这样写呢?因为上述代码Vue给我们提供了一个语法糖
// Parent.vue <Son @update:number="newValue =>number = newValue" :number="number" /> // 等价于 <Son :number.sync="number" />
不过需要注意的是,在子组件中调用$emit(fn, val)的时候fn的名字一定是这样的格式的update:xxx
$emit(fn, val)
既然 props 和 $emit 可以这么玩了,那我们再试一下另外的玩法
// Parent.vue <Son @input="newValue =>number = newValue" :value="number" />
// Son.vue props: { value: { type: Number } }, change() { this.$emit('input', 200) }
我们只需要稍微的修改一下props 和 $emit的用法也可以实现相应的逻辑,但是这样写的话我们不由想到这种写法是的语法糖是 v-modal,那我们的父组件可以这样使用
v-modal
<Son v-model="number" />
但是啊v-modal的局限性是只能传递value, 而且只可以传递一次
value
假设我们有一个需求,要将父组件的数据传递给孙组件,但是我们的子组件又没有使用到这些数据,这个时候我们可以使用$attrs了
$attrs
// Parent.vue <Son :number="number" :count="count" />
// Son.vue <Grandson v-bind="$attrs" />
// Grandson.vue {{ $attrs }}
在子组件中可以通过v-bind="$attrs"的方式将父组件传递下来的数据原封不动的传递给孙组件,而孙组件可以通过$attrs来接收,不过这个用法有个局限性就是子组件不可以接收父组件的数据,也就是不可以有props钩子
v-bind="$attrs"
既然可以这样传数据了,那方法是不是也可以这么玩,答案是肯定的
// Parent.vue <Son :number="number" @change="change" @say="say" :count="count" />
// Son.vue <Grandson v-on="$listeners" />
// Grandson.vue mounted() { console.log(this.$listeners) }
通过 $listeners 和 v-on的配合可以将全部事件传递给孙组件,但是这里需要注意的一点是,子组件也是可以通过$listeners来接收父组件传递的全部事件的
$listeners
v-on
我们先来说下eventbus的原理,假设现在2个组件A和B需要通信,那么我可以在组件C上面用$on发布一个事件,那么A和B就可以通过C.$emit()来互相通信了吧,就是弄一个全局的发布订阅
eventbus
$on
C.$emit()
// main.js Vue.prototype.$bug = function() { return new Vue() }
我们知道Vue本身就是具有发布订阅能力的,这里我们直接new Vue()就好啦
new Vue()
那么怎么使用呢?
// 组件A - 在组件A中发布事件 this.$bus.$on('change', ()=>{})
// 组件B - 在组件B中可以订阅这个事件实现通信 this.$bus.$emit('change')
其实一直在纠结ref算不算组件通信的一种,但是我们可以通过ref拿到某一个组件的实例,也就是拿到某一个组件的方法和数据
ref
// Parent.vue <Son ref="son"/> mounted() { console.log(this.$refs.son) }
可以通过$refs拿到某个组件的实例
$refs
接下来我们来说一下很多人都不知道的一种组件传值方法provide 和 inject 我们只需要在父组件使用provide定义需要向下传递的数据,不管层级多深后代组件都可以通过inject接收
provide
inject
// Parent.vue export default { provide() { return {vm: this} }, }
父组件向下传递数据vm
// Son.vue export default { inject: ['vm'], mounted() { console.log(this.vm) } }
子组件可以通过inject接收
但是这个方法在日常开发中不建议使用,因为太乱太难管理了
Vue的组件通信太复杂了,因为语法糖和api太多了,所以我们还是选择vuex
vuex
The text was updated successfully, but these errors were encountered:
No branches or pull requests
Vue中组件通信的九种方法
前言
Vue中的组件通信是一个比较复杂的一个知识点,涵盖各种api和语法糖,接下来我们分别来介绍下常见的九种组件通信方法
props 和 $emit
这是我们日常开发最常见的一种父子组件通信的方法了,我们来看一个简单的例子,后文全部方法都围绕这个例子进行
我们可以发现,父组件通过
props
将数据传递给子组件,而子组件可以通过$emit
的方式调用父组件的方法修改父组件的值,我们知道Vue和React都是单向数据流,也就是数据是从上往下传递的,当我们子组件修改父组件的数据的时候,自己拿到的数据也会随着修改$parent 和 $children
介绍了最常见的一种用法,我们接下来看下一种更暴力的用法
$parent
和$children
我们可以通过
$parent
拿到父组件的实例,然后调用父组件的方法改变父组件的数据,同样道理我们在父组件中也可以使用$children
的方法修改子组件的值,这里就不演示啦$dispatch
这个也是在element ui 的源码中看到的一个方法
我们将
$dispatch
挂载到Vue的原型上方便调用,我们可以看到,$dispatch
的原理是一直递归找父组件,然后执行父组件中对应的$emit
方法,我们来看下怎么用我们可以发现在孙子组件中调用
$dispatch
方法,他会触发所以父组件中的$emit('xxx', xxx)
方法,达到修改对应父组件数据的目的$broadcast
$broadcast
的原理和$dispatch
很像,$dispatch
是一直往父元素上面找,而$broadcast
刚刚相反,一直往子元素上面找对应的方法执行同样是挂载原型的方法,有了这个方法我们就可以在父组件中主动调用全部后代组件中的
$emit
方法了.sync 和 v-modal
.sync
接下来我们看到的这种用法其实是
props
和$emit
的一些语法糖, 我们来看下使用props
和$emit
时候的代码我们只需要将
$emit(fn)
中的fn改为update:xxx
就可以了,其中xxx为父组件传递给子组件的数据名为什么要这样写呢?因为上述代码Vue给我们提供了一个语法糖
不过需要注意的是,在子组件中调用
$emit(fn, val)
的时候fn的名字一定是这样的格式的update:xxx
v-modal
既然
props
和$emit
可以这么玩了,那我们再试一下另外的玩法我们只需要稍微的修改一下
props
和$emit
的用法也可以实现相应的逻辑,但是这样写的话我们不由想到这种写法是的语法糖是v-modal
,那我们的父组件可以这样使用但是啊
v-modal
的局限性是只能传递value
, 而且只可以传递一次$attrs 和 $listeners
$attrs 和 v-bind
假设我们有一个需求,要将父组件的数据传递给孙组件,但是我们的子组件又没有使用到这些数据,这个时候我们可以使用
$attrs
了在子组件中可以通过
v-bind="$attrs"
的方式将父组件传递下来的数据原封不动的传递给孙组件,而孙组件可以通过$attrs
来接收,不过这个用法有个局限性就是子组件不可以接收父组件的数据,也就是不可以有props
钩子$listeners 和 v-on
既然可以这样传数据了,那方法是不是也可以这么玩,答案是肯定的
通过
$listeners
和v-on
的配合可以将全部事件传递给孙组件,但是这里需要注意的一点是,子组件也是可以通过$listeners
来接收父组件传递的全部事件的eventbus
我们先来说下
eventbus
的原理,假设现在2个组件A和B需要通信,那么我可以在组件C上面用$on
发布一个事件,那么A和B就可以通过C.$emit()
来互相通信了吧,就是弄一个全局的发布订阅我们知道Vue本身就是具有发布订阅能力的,这里我们直接
new Vue()
就好啦那么怎么使用呢?
ref
其实一直在纠结
ref
算不算组件通信的一种,但是我们可以通过ref
拿到某一个组件的实例,也就是拿到某一个组件的方法和数据可以通过
$refs
拿到某个组件的实例provide 和 inject
接下来我们来说一下很多人都不知道的一种组件传值方法
provide
和inject
我们只需要在父组件使用
provide
定义需要向下传递的数据,不管层级多深后代组件都可以通过inject
接收父组件向下传递数据vm
子组件可以通过
inject
接收但是这个方法在日常开发中不建议使用,因为太乱太难管理了
总结
Vue的组件通信太复杂了,因为语法糖和api太多了,所以我们还是选择
vuex
The text was updated successfully, but these errors were encountered: