preface

Vue3.0-beta has been around for a while, and the official release is said to be in the middle of the year (whether it’s the middle of the year or the end of the year, online rumors say June). But I was honest enough to create a vuE3 project. When I introduced the vue2 plug-in with great enthusiasm, I found that things were not so simple.

The browser relentlessly throws an error:

Uncaught TypeError: Cannot set property ‘$toast’ of undefined

The plugin is not compatible with vue2. You have to deal with the problem after you complain. Study the code of the plug-in, and this is how it is implemented

var Toast = {};
Toast.install = function (Vue, options) {
    Vue.prototype.$toast = 'Hello World';
}
module.exports = Toast;
Copy the code

The vue2 plug-in exposes an install method and uses the plug-in through the global vue.use () method. The first argument to the Install method is the Vue constructor, to which the plug-in’s methods are added. Once instantiated by new Vue(), the component can be used by calling this.$toast in the component. (Specific implementation can refer to my previous article: vue.js plug-in development details, the following is also based on this plug-in demo comparison and modification).

The vue3 install method does not pass in the Vue constructor, there is no prototype object, vue. prototype is undefined, so error. Vue3 uses dependency injection to provide and inject inside plug-ins and expose a composite function for use in components.

A plugin

The basic framework

Let’s start with the basic framework of a plug-in.

import { provide, inject } from 'vue'; const ToastSymbol = Symbol(); // Use Symbol to create a unique Symbol that does not conflict between plug-ins const _toast = () => {export functionProvideToast (config) {// The exposed method provides the _toast method to the descendant component provide(ToastSymbol, _toast); }export function useToast() {// Descendant components can get toast methods from this method const toast = inject(ToastSymbol);if(! toast) { throw new Error('error');
    }
    return toast;
}
Copy the code

Components use

In the provideToast method, the _toast method is provided. Call the provideToast method in the root component, pass in the plug-in parameter, and the toast function is available in the child component.

// app.vue root component
import { provideToast } from 'vue2-toast';
export default {
    setup() {
        provideToast({
			width: '200px'.// Configure the toast width
			duration: 2000		// Configure toast to display duration}); }};Copy the code

In the useToast method, the toast method is returned. Call the useToast method in all descendants of the component to get the Toast method.

// child.vue child component
import { useToast } from 'vue2-toast';
export default {
    setup() {
        const Toast = useToast(); // All child components get the toast method from useToast
		Toast('Hello World'); }};Copy the code

Data response

To control the display and hiding of toast DOM elements and the change of prompt text, you need to create reactive data. In VUe3, reactive objects can be created using reactive methods.

const state = reactive({
    show: true.// Whether the DOM element is displayed
    text: ' '	// Prompt text
});
Copy the code

Mount the DOM

Displaying a toast on a page inevitably creates a DOM and mounts it to the page. Vue2 creates a subclass with vuue. Extend and mounts the instance generated by the subclass to an element, whereas VUe3 does this with the createApp method.

const _toast = text= > {
    state.show = true;
    state.text = text;
	toastVM = createApp({
		setup() {
			return (a)= >
				h('div', {
					style: { display: state.show ? 'block' : 'none' }	// display sets display to hide}, state.text ); }}); toastWrapper =document.createElement('div');
	toastWrapper.id = 'toast';
	document.body.appendChild(toastWrapper);  // Add a node to the page to mount the toast element
	toastVM.mount('#toast');
};
Copy the code

Complete sample

Each step above is the key content of this plug-in, and the next step is to improve the details, such as user configuration of global parameters of the plug-in, setting of toast style, duration, display location, etc., here I will not go into details, the complete example is as follows:

import { provide, inject, reactive, createApp, h } from 'vue';
const ToastSymbol = Symbol();

const globalConfig = {
    type: 'bottom', // toast position duration: 2500, //false// width:'auto'/ / width}; const state = reactive({ show:false// If the toast element displays text:' '
});

let [toastTimer, toastVM, toastWrapper] = [null, null, null];

const _toast = text => {
    state.show = true;
    state.text = text;
    if(! ToastVM) {// toastVM will not be recreated if the toastVM instance exists = createApp({setup() {
                return () =>
                    h(
                        'div', {// here is a different style according to the configuration class: ['lx-toast',
                                `lx-toast-${globalConfig.type}`,
                                globalConfig.wordWrap ? 'lx-word-wrap' : ' '
                            ],
                            style: {
                                display: state.show ? 'block' : 'none', width: globalConfig.width } }, state.text ); }}); }if(! ToastWrapper) {// Do not recreate toastWrapper if the node already exists = document.createElement('div');
        toastWrapper.id = 'lx-toast';
        document.body.appendChild(toastWrapper);
        toastVM.mount('#lx-toast');
    }
    if(toastTimer) clearTimeout(toastTimer); // Hide toastTimer = after durationsetTimeout(() => {
        state.show = false;
        clearTimeout(toastTimer);
    }, globalConfig.duration);
};

export function provideToast(config = {}) {
    for (const key in config) {
        globalConfig[key] = config[key];
    }
    provide(ToastSymbol, _toast);
}

export function useToast() {
    const toast = inject(ToastSymbol);
    if(! toast) { throw new Error('error');
    }
    return toast;
}
Copy the code

conclusion

The big difference with vue2’s plug-in is that the useToast method is introduced in every component that needs to useToast, which seems a bit cumbersome. But that’s the purpose of the VUE composite API, to make code more readable and easier to understand, and it’s clear that this approach comes from there. As the title suggests, this is an early release, the official version of VUE3 has not been released yet, whether there will be more plug-ins in the future, I dare not ask, at least this one is relatively stable.