跨组件v-model实现双向绑定

目标和内容: 在完全理解 v-model,$attrs, $listener 的基础上,实现父(A)、子(B)、后代(C)的三层组件结构中,A组件和C组件跨越B组件之间的数据双向绑定。

一、v-model 的本质

<MyList v-model="lovingVue"></MyList>

<!-- 其实是以下的语法糖 -->
<MyList :value="lovingVue" @input="(data) => lovingVue = data"></MyList>


没耐心理解代码的话,直接看下面的文字:

v-model 的本质是:父组件给子组件传一个名为 value 的prop,然后对子组件挂载一个名为 input 的事件监听。

当子组件手动 emit 这个input 事件时,携带的载荷自动赋值到v-model后绑的父组件变量上。

(所以其实不是自动双向绑定,还是需要手动emit input事件的。)

二、$attrs的本质

父组件以形如:foo="xxx"或者v-bind="{age:12}"传给子组件的属性,但凡没有被子组件的props接收的,都会被扔到$attrs里去。

(题外话,被props指名接收的,都放入$props里。)

三、 $listeners的本质

父组件以 @eventName="fn" 或者 v-on:eventName="fn",对子组件挂载了一些事件的监听。对子组件而言都打包放在$listeners里。

如果子组件对后代组件使用v-on="$listeners",那么后代组件的emit同样会越过子组件直接被父组件监听到,进而触发父组件事件方法。(当然子组件自己也可以emit,同样会触发父组件事件)

那么掌握了以上知识了之后,我们如何实现跨越三层的一个双向绑定呢?

<!-- A Component -->
<template>
    <BComponent v-model="modalShow"></BComponent>
</template>

<script>
    this.modalShow = true // 往下传递状态,直接到C
</script>


<!-- B Component -->
<template>
    <CComponent v-bind="$attrs" v-on="$listeners"></CComponent>
</template>

<script>
    // 中间组件也可以中途向两边更改状态,一致性需要手动保持
    // this.$attrs.value = true
    // this.$emit('input', true)
</script>


<!-- C Component -->
<script>
    @Props()
    value:boolean
    
    handleClose(){
        this.$emit('input', false) // 往上emit状态,直接到A
    }
</script>

总结一下,主要是中间传递组件的 v-bind="$attrs" v-on="$listeners"。

父组件更改了数据,会因为 $atrrs 的传递自然地传递到后代组件。而后代组件 emit 一个 input 事件,会因为 $listeners 自然地冒到父组件处,又因为父组件的 v-model 而自动把新数据赋值到父组件变量上,因此实现了所谓的"双向绑定"。

发布了34 篇原创文章 · 获赞 1 · 访问量 7883

猜你喜欢

转载自blog.csdn.net/landiyaaa/article/details/103979426