Dynamically mount a single file component in Vue.js
Use Vue's Dynamic Components
You could use Dynamic Components to dynamically switch between components. You will need to bind the component definition object to the is
attribute of the component
element – Vue's documentation on this is pretty self explanatory. Below is also a brief example:
<template>
<component :is="activeComponent"></component>
</template>
import componentA from 'component/a';
import componentB from 'component/b';
export default {
components: {
componentA,
componentB,
},
data() {
return {
activeComponent: 'componentA',
},
},
};
You could directly bind the component definition object to the data property itself:
import componentA from 'component/a';
import componentB from 'component/b';
export default {
data() {
return {
activeComponent: componentA,
};
},
};
To switch out components you can programmatically change the value of activeComponent
.
Use a render function
A more powerful way of dynamically mounting components can be achieved using component render functions. To do this we must create our own version of Vue's component
element – we'll call this the ElementProxy
:
import componentA from 'component/a';
import componentB from 'component/b';
export default {
components: {
componentA,
componentB,
},
props: {
type: {
type: String,
required: true,
},
props: {
type: Object,
default: () => ({}),
},
},
render(createElement) {
const { props: attrs } = this;
return createElement(element, { attrs });
},
};
You can now use the ElementProxy
to proxy elements. The additional benefit of this is that you can pass props in as an object which will solve the problem of passing props to dynamic components with differing models.
<template>
<element-proxy :type="activeComponent" :props="props"></element-proxy>
</template>
import ElementProxy from 'components/elementProxy';
export default {
components: {
ElementProxy,
},
data() {
return {
activeComponent: 'componentA',
props: { ... },
};
},
};
Further reading
- Vue's documentation for dynamic components
- Vue's documentation for the render function
- GitHub issue thread for binding props
Yes, you need dynamic components:
<template>
<div>
<component v-bind:is="currentView">
<!-- component changes when vm.currentView changes! -->
</component>
</div>
</template>
<script>
import A from './A.vue';
import B from './B.vue';
export default {
data: {
currentView: 'A'
},
components: {
A,
B,
}
})
then
function getComponent(){
if (..)
this.currentView = 'A';
else if (..)
this.currentView = 'B'
...
}
You can also bind components directly, according to manual:
https://vuejs.org/v2/guide/components.html#Dynamic-Components