乐趣区

Vue-组件间传参最佳实践

1. 父子组件间的数据传递

1.1 从父组件获取子组件的数据

1.1.1 通过绑定 props 将父组件的数据关联到子组件,并修饰 .sync 或者用 v-model 同步来自子组件的数据变化

// 使用.sync:// 父组件
<template>
  <div class="home">
   <my-dialog :show.sync="valueChild"/>
   <button @click="changeValue">toggle</button>
  </div>
</template>
<script>
import myDialog from '@/components/myDialog.vue'

export default {
  name: 'home',
  components: {myDialog},
  data(){
    return{valueChild:true,}
  },
   methods:{changeValue(){this.valueChild = !this.valueChild}
    }
}
</script>

// 子组件
<template>
  <div>
    <div>myDialog</div>
    <div v-if="show">
      <p> 默认初始值是 {{show}},所以是显示的 </p>
      <button @click.stop="closeDiv"> 关闭 </button>
    </div>
  </div>
</template>
<script>
export default {props:['show'],
  methods:{closeDiv(){this.$emit('update:show',false)
    }
  }
}
</script>
// v-model :

// 父组件:<template>
  <div class="home">
    <myDialog v-model="show"></myDialog>
    <button @click="toggle">Toggle</button>
  </div>
</template>
<script>
  import myDialog from '@/components/myDialog.vue'

  export default {
    name: 'home',
    components: {myDialog},
    data() {
      return {show: false}
    },
    methods: {toggle() {this.show = !this.show}
    }
  }
</script>

// 子组件:<template>
  <div>
    <div v-if="value" class="modal">
      {{value}}
      <button @click="close">x</button>
    </div>
  </div>
</template>
<script>
  export default {props: ['value'],
    methods: {close() {this.$emit('input', false)
      }
    }
  }
</script>

1.1.2 绑定 listener 事件监听器,当子组件状态或者数据发生变化时,触发事件并将数据传递到父组件

$listeners 和 $attrs 两者表面层都是一个意思,$attrs 是向下传递数据,$listeners 是向下传递方法,通过手动去调用 $listeners 对象里的方法,原理就是 $emit 监听事件,$listeners 也可以看成一个包裹监听事件的一个对象。

// 父组件:<template>
  <div class="home">
    {{firstMsg}}
    <myDialog v-on:changeData="changeData" v-on:another='another'></myDialog>
  </div>
</template>
<script>
  import myDialog from '@/components/myDialog.vue'

  export default {
    name: 'home',
    components: {myDialog},
    data() {
      return {firstMsg: '父组件'}
    },
    methods: {changeData(params) {this.firstMsg = params},
      another() {alert(2)
      }
    }
  }
</script>

// 子组件:<template>
  <div>
    <p @click="$emit('another')"> 子组件 </p>
    <other v-on="$listeners"/>
  </div>
</template>
<script>
  import other from '@/components/other.vue'
  export default {props: ['value'],
    components:{other},
    created () {
     // eslint-disable-next-line no-console
     console.log(this.$listeners)
   }
  }
</script>

// 孙子组件:<template>
  <div>
    <p @click='$listeners.changeData("change")'> 孙子组件 </p>
  </div>
</template>

<script>
export default {
  name: 'demo',
  created () {
      // eslint-disable-next-line no-console
      console.log(this.$listeners)
  },
}
</script>

1.2 从子组件获取父组件的数据

1.2.1 获取 props 或者 $attrs 传下来的数据

// 父组件:
<template>
  <div class="home">
    <myDialog :foo="foo" :boo="boo" :coo="coo" :doo="doo" title="前端工匠"></myDialog>
  </div>
</template>
<script>
  import myDialog from '@/components/myDialog.vue'

  export default {
    name: 'home',
    components: {myDialog},
    data() {
      return {
        foo: "Javascript",
        boo: "Html",
        coo: "CSS",
        doo: "Vue"
      }
    },
    methods: {changeData(params) {this.firstMsg = params},
      another() {alert(2)
      }
    }
  }
</script>

// 子组件:<template>
  <div>
    <p>foo:{{foo}}</p>
    <p> 子组件的 $attrs: {{$attrs}}</p>
    <other v-bind="$attrs" />
  </div>
</template>
<script>
  import other from '@/components/other.vue'
  export default {
    components: {other},
    inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在 props 声明的属性
    props: {foo: String // foo 作为 props 属性绑定},
    created() {
      // eslint-disable-next-line no-console
      console.log(this.$attrs);
    }
  }
</script>

// 孙子组件:<template>
  <div>
    <p>boo: {{boo}}</p>
    <p> 孙子:{{$attrs}}</p>
  </div>
</template>

<script>
  export default {
    name: 'demo',
    inheritAttrs: false,
    props: {boo: String},
    created() {
      // eslint-disable-next-line no-console
      console.log(this.$attrs);
    },
  }
</script>

2. 兄弟组件间的数据传递

处于兄弟关系的组件

2.1 通过 EventBus 或者 $root 去注册事件,由兄弟组件去监听事件传递过来的数据变化

2.2 在 Vuex 存放状态,并在两个组件中都监听状态变化
2.3 在父组件上绑定状态,并通过 v-model 或者 .sync 绑定到两个兄弟组件中去,以同步数据变化

3. 祖孙组件间的数据传递

3.1 孙组件被直接写在了祖先组件的 template 内

在 Vue 中,处于祖孙关系的组件,而且孙组件被直接写在了祖先组件的 template 内,要从祖先组件获取孙组件的数据,有以下几种方式:

3.1.1 可以在模板上给孙组件绑定 ref 并通过 $refs 调用孙组件的方法获取数据

// 父组件
<template>
  <div class="home">
    {{title}}
    {{text}}
    <myDialog ref="comA"></myDialog>
  </div>
</template>
<script>
  import myDialog from '@/components/myDialog.vue'

  export default {
    name: 'home',
    components: {myDialog},
    data() {
      return {
        title:'',
        text:''
      }
    },
    computed: { },
    mounted() {
      const comA = this.$refs.comA;
      // console.log(comA.title); // Vue.js
      this.title = comA.title
      this.text = comA.text
      comA.sayHello(); // 弹窗},
    methods: {}}
</script>

// 子组件:<template>
  <div>
    <div v-if="show">sayHello</div>
    <other ref="comB" />
  </div>
</template>
<script>
  import other from '@/components/other.vue'
  export default {
    components: {other},
    data() {
      return {
        title: 'Vue.js',
        show: false,
        text:''
      }
    },
    created() {},
    mounted() {
      const comB = this.$refs.comB;
      this.text = comB.text
    },
    methods: {sayHello() {
        this.show = true
        // window.alert('Hello');
      }
    }
  }
</script>

// 孙子组件:<template>
  <div>
  </div>
</template>

<script>
  export default {
    name: 'demo',
    data(){
      return{text:'c'}
    },
    created() {},
  }
</script>

3.1.2 可以在模板上给孙组件绑定 listener 获取孙组件传过来的数据
3.1.3 可以在模板上给孙组件绑定 v-model 或者 .sync 同步孙组件的数据

3.2 孙组件不在祖先组件的 template 内,要从祖先组件获取孙组件的数据

3.2.1 先在子组件上绑定 v-model 或者 .sync,接着再在子组件的模板上通过 v-model 或者 .sync 绑定孙组件,以同步孙组件的数据
3.2.2 现在孙组件上绑定 listener,再给子组件绑定 listener,数据由事件层层上传给祖先组件

3.3 孙组件在祖先组件的 template 内,要从孙组件获取祖先组件的数据

3.3.1 直接在祖先组件的 template 中通过 v-bind 将数据传递到孙组件中,孙组件通过 props 或者 $attrs 进行接收

3.4 孙组件不在祖先组件的 template 内,要从孙组件获取祖先组件的数据

3.4.1 先在子组件上 v-bind 绑定数据,接着再在子组件上通过 v-bind 绑定孙组件,数据层层向下传递
3.4.2 孙组件在 EventBus 中注册事件,监听来自祖先组件触发的事件数据
3.4.3 祖先组件将数据挂到 Vuex 中,再由孙组件从 Vuex 中去获取数据

退出移动版