DMack
DMack

Reputation: 949

How can I access/mutate Vue component properties from vanilla JS

I have a Vue 2 project made with Vue CLI, and I plan to distribute it as a library, ideally with the dependencies and Vue syntax stuff abstracted away by some kind of wrapper script. I would like to allow this kind of interaction:

// mount the component on a plain JS webpage
const myComponent = new MyComponent('#my-component');

// handle events from the component in vanilla JS
myComponent.on('load', someHandler);

// (A.) call a component method and get a return value
const processedData = myComponent.process(123);

// (B.) access/mutate reactive component data properties
myComponent.setMessage('Hello world!');

I have tried changing the "build target" to build a Libary or a Web Component as mentioned in the Vue documentation. I can mount the library component just fine, and handle events, but it doesn't mention how I might interact with the component data from outside the Vue VM (see comments A and B).

How can I access Vue component methods and data properties from outside the Vue VM, in vanilla JS?

Upvotes: 1

Views: 639

Answers (1)

DMack
DMack

Reputation: 949

To access the Vue component properties (and methods) outside of the VM, you can mount it with a "template ref" like this:

const vm = new Vue({
    components: {
        MyComponent,
    },

    template: `
        <my-component
            ref="myComponent"
        />
    `,
}).$mount('#mount-element");

and then you can call its methods like this:

vm.$refs.myComponent.someFunction();

You'll get the returned values and it will access/mutate reactive properties inside the VM as expected.

To use the class syntax described in the original question, we can create a simple class to wrap the vue component:

// import the component built by Vue CLI with the "library" build target
// (puts `MyComponent` in the global namespace)
import './MyComponent.umd.min.js'; 

import Vue from 'https://unpkg.com/vue@2/dist/vue.esm.browser.min.js';

export default class {
    constructor(mountElement) {
        // mount vue VM with a template ref to access its properties
        const thisClass = this;
        this.vm = new Vue({
            components: {
                MyComponent,
            },

            template: `
                <my-component
                    ref="myComponent"
                />
            `,
        }).$mount(mountElement);

        this.component = this.vm.$refs.myComponent;
    }

    // define methods that could call this.component's functions
    someFunction() {
        // do stuff
        return this.component.someFunction()
    }

}

It seems to work pretty well. A possible improvement would be to build the component library with a different tool, since Vue CLI v3 (with Vue v2 projects) can't output ESM module files, so the best we can do is a UMD modle that gets defined globally.

Upvotes: 1

Related Questions