Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
243 views
in Technique[技术] by (71.8m points)

javascript - vue wrap another component, passing props and events

How can I write my component to wrap another vue component, while my wrapper component get some extra props? My wrapper template component should be:

<wrapper-component>
   <v-table></v-table> <!-- pass to v-table all the props beside prop1 and prop2 -->
</wrapper-component>

and the wrapper props:

props: {
  prop1: String,
  prop2: String
}

Here I want to wrap a table component, and pass to the table component all the props and events that were passed to the wrapper, beside two extra props prop1 and prop2. What is the correct way of doing this in vue? And is there a solution for events too?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Place the component you wish to wrap into the template of the wrapper component, add v-bind="$attrs" v-on="$listeners" to that component tag, then add the inner component (and, optionally, inheritAttrs: false) to the wrapper component's config object.

Vue's documentation doesn't seem to cover this in a guide or anything, but docs for $attrs, $listeners, and inheritAttrs can be found in Vue's API documentation. Also, a term that may help you when searching for this topic in the future is "Higher-Order Component" (HOC) - which is basically the same as your use of "wrapper component". (This term is how I originally found $attrs)

For example...

<!-- WrapperComponent.vue -->
<template>
    <div class="wrapper-component">
        <v-table v-bind="$attrs" v-on="$listeners"></v-table>
    </div>
</template>

<script>
    import Table from './BaseTable'

    export default {
        components: { 'v-table': Table },
        inheritAttrs: false // optional
    }
</script>

Edit: Alternatively, you may want to use dynamic components via the is attribute so you can pass in the component to be wrapped as a prop (closer to the higher-order component idea) instead of it always being the same inner component. For example:

<!-- WrapperComponent.vue -->
<template>
    <div class="wrapper-component">
        <component :is="wraps" v-bind="$attrs" v-on="$listeners"></component>
    </div>
</template>

<script>
    export default {
        inheritAttrs: false, // optional
        props: ['wraps']
    }
</script>

Edit 2: The part of OP's original question that I missed was passing all props EXCEPT one or two. This is handled by explicitly defining the prop on the wrapper. To quote the documentation for $attrs:

Contains parent-scope attribute bindings (except for class and style) that are not recognized (and extracted) as props

For example, example1 is recognized and extracted as a prop in the snippet below, so it doesn't get included as part of the $attrs being passed down.

Vue.component('wrapper-component', { 
  template: `
    <div class="wrapper-component">
        <component :is="wraps" v-bind="$attrs" v-on="$listeners"></component>
    </div>
  `,
  // NOTE: "example1" is explicitly defined on wrapper, not passed down to nested component via $attrs
  props: ['wraps', 'example1']
})

Vue.component('posts', {
  template: `
    <div>
      <div>Posts component</div>
      <div v-text="example1"></div>
      <div v-text="example2"></div>
      <div v-text="example3"></div>
    </div>
  `,
  props: ['example1', 'example2', 'example3'],
})

new Vue({
  el: '#app',
  template: `
    <wrapper-component wraps="posts"
      example1="example1"
      example2="example2"
      example3="example3"
    ></wrapper-component>
  `,
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...