vuejs2vuejs3

Stuck upgrading vue2 to vue3


// import Vue from "vue"; // vue2
import { createApp } from 'vue' // vue3
import fabComponent from "./components/Fab.vue";
import SvgIcon from "./components/SvgIcon.vue";

// The body of class
window.fab = {   
    mount(options) {

        var html = '<div data-vue-component="FabComponent"></div>';
        document.body.insertAdjacentHTML('beforeend', html);

        document
            .querySelectorAll("[data-vue-component=FabComponent]")
            .forEach((element) => {

                // works in vue2
                // const floatingButton = new Vue(fabComponent)
                // floatingButton.options(options);
                // floatingButton.$mount(element);

                // what is the equivalent in vue3?
                const app = createApp({});
                app.component('fb',fabComponent);
                const floatingButton = app.use(fabComponent);
                floatingButton.options(options);
                floatingButton.$mount(element);
            });
    }
}
<script>
// Fab.vue

export default {
    name: 'app',
    methods: {
        options(options) {
            // this was called in vue2
            Object.keys(options).forEach(key => {
                this[key] = options[key];
            });
        },
        alert() {
            alert('You have clicked me :)');
        }
    }
}
</script>

I'm not that proficient in vue but need to upgrade my vue2 widget (i.e. it can be loaded in any HTML by just including the bundled javascript) to a vue3 one.

I have spent 2 long days on this and tried about almost everything I can think of to translate this new Vue(fabComponent).

Webpack builds/transpiles without errors, but the issue surfaces when I try to load it in my browser. In vue2, floatingButton was assigned as a Proxy(Object), but I just can't seem to replicate that in vue3, floatingButton is an Object. As a result, floatingButton.options(options); throws an uncaught error.

I can use new Vue(fabComponent) as-is in vue3, but how would I get my app then? Because Fab.vue relies on another SvgIcon.vue component.

Any ideas? Thank you.

UPDATE

I added the <script> of Fab.vue where in vue2, the options method was called. In the vue3 example, I only saw defineProps(...) in <script setup>, also need help with that. Thank you.


Solution

  • Upgrading to Vue3, it is possible to create multiple Vue-app instances. On the contrary, in Vue2, it is limited to one single global instance.

    Another breaking change is how the app instance would bind to an element (there is a mount function instead of $mount).

    To address your issue, you can create an app instance with FabComponent for each element the query returned.

    import { createApp } from 'vue';
    import FabComponent from './FabComponent.vue';
    import SvgIcon from './SvgIcon.vue';
    
    window.fab = {
      mount(options) {
        var html = '<div data-vue-component="FabComponent">';
        document.body.insertAdjacentHTML('beforeend', html);
    
        document
          .querySelectorAll('[data-vue-component=FabComponent]')
          .forEach(element => {
             createApp(FabComponent, options)
             .mount(element);
          });
      },
    };
    
    window.fab.mount({
      modelValue:'A GLOBAL PROP'
    });
    

    Online Playground