Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically mount a single file component in Vue.js

I have a single file component Main.Vue.

I also have three other single file components A.vue, B.vue and C.vue.

I want to be able to show inside Main.Vue a different component each time. What I did was this:

<template>
<div>
<a v-if="isAVisible" ></a>
<b v-if="isBVisible" ></a>
</div>
</template>

<script>
import A from './A.vue';
import B from './B.vue';
...

This works but not exactly what I wanted. I wanted a different file Factory.js, which does the importing of all the components A,B,C,.. And has functions that return my component, which I can use somehow in Main.vue. Here's what I tried Factory.js to look like:

import A from './A.vue';
import B from './B.vue';
function getComponent(){
  if (..)
    return new A();
  else if (..)
    return new B();
  ...
}

This didn't work at all. I want the factory file approach because:

1) I want to split it to different factory files

2) I want to "Attach" data to each component. So I'll have an object that contains the function returning the actual component + some additional data like "name"

Any ideas how to do this?

like image 423
Michael_S_ Avatar asked May 05 '17 07:05

Michael_S_


People also ask

How do I dynamically load components in Vue?

To make the component dynamic, we can bind it to a set property with the v-bind directive. Your component is now bound with the component property in the data. If you switch the component to Test2 , it will automatically mount the Test 2 component. Test it out on your browser.

How do I use lazy loading in VUE JS?

js, this means using the import statement to bring in a component into the app. vue file. Lazy loading refers to an approach by which all the scripts are not loaded on the DOM as the application starts. Instead, they're only loaded when requested, which makes the JavaScript bundle size very small at initial load.

What are Vue single file components?

Single File Components allow us to define the HTML/CSS and JS of a component all within a single . vue file. A single-file component is composed of three parts: The <template> section which contains the component's markup in plain HTML.

Is Vue synchronous or asynchronous?

You might know Vue updates reactively: when you change a value, the DOM is automatically updated to reflect the latest value. Vue does these updates asynchronously. In contrast, a test runner like Jest runs synchronously. This can cause some surprising results in tests.

How to mount two components in one Vue app?

Now that you have a second component, go to the App.vue file and register the component: The two test components are now nested in the root app component. If you want to mount only one component and then dynamically switch to the other, you have to create a dynamic component. Copy the code block below into the template section of your app.vue file:

What is a dynamic component in Vue?

Dynamic components Vue dynamic components enable users to switch between two or more components without routing, and even retain the state of data when switching back to the initial component. The central idea is to let users dynamically mount and unmount components in the user interface without using routers. Why are dynamic components important?

How do you build plugins in Vue?

We'd like the plugins to be built in the form of a Vue single-file component. At runtime, the end user would select a plugin to add to the app. The app would fetch the plain-text .vue file, compile it on the fly, and display it in the app. Vue supports dynamic and async components, but these to be compiled into the app ahead of time.

Is there a build step for Vue JS?

No build step restricts us to HTML and ES5 JavaScript, rather than preprocessors like Pug (formerly Jade) and Babel All of these are solved by single-file components with a .vue extension, made possible with build tools such as Webpack or Browserify.


2 Answers

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
like image 138
Wing Avatar answered Oct 18 '22 02:10

Wing


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://v2.vuejs.org/v2/guide/components.html#Dynamic-Components

like image 36
Gerardo Rosciano Avatar answered Oct 18 '22 03:10

Gerardo Rosciano