I wrote a toash component in vue, but how can I call it in js?

effect:

clipboard.png

subcomponents:

<template>
    <div class="toash" :style="{display:ifShow}">
        <span>{{text}}</span>
    </div>
</template>

<script>
export default {
    props:["text","timer"],
    data () {
        return {
            ifShow:"block"
        }
    },
    mounted(){
        setTimeout(()=>{
            this.ifShow = "none";
        },this.timer)
    }
}
</script>

parent component:

<template>
    <div class="hello">
        <toash text="" timer=3000></toash>
    </div>
</template>

question:
I have seen a lot of frames, as long as in js: this.$toash ("text description") can call toash, which is very convenient to operate. So how can I call the toash component in js?

Jun.07,2021

happened to have an article: Vue plug-ins and extend methods

To put it simply, write a $toash method on the prototype of Vue: Vue.prototype.$toash = function (desc) {}
and you can use it this.$toash ("text description") within the component.

then, in the declaration $toash method, all you have to do is take the parameters, generate a piece of dom, and manually document.body.appendChild (), to insert the toash into the page. And reasonably control the hiding of this piece of dom. The logic depends on your needs.

the blog post is my own notes, which may not be written in detail. You can check (xi) element UI's $message source code ;

in (chao).

recently I have been drawing the ui component of vue, and there is a message component, which is similar to yours. To put it simply, the difficulty of such components is:

  1. use Vue.extend instead of writing components in html
  2. needs to implement a singleton pattern

many frameworks have two files for such components, one xxx.vue, and one xxx.js.
message.vue

<template>
    <div :class="['jn-message','jn-message-'+icon]" :style="{'z-index':ZINDEXPP}">
        <i :class="['jn-icon-'+icon,'jn-message-icon']" v-if="icon"></i>
        <div class="jn-message-content">
          <template v-if="htmlEnable">
              <div v-html="$slots.default[0]" class="jn-message-content" >

              </div>
          </template>
          <template v-else>
              <slot>

              </slot>
          </template>
        </div>
        <i v-if="closeButton" class="jn-message-close jn-icon-close" @click="closeMessage"></i>
    </div>
</template>
<script>
import {ZINDEX} from '@/js/utils/const.js'
export default {
  name: "jn-message",
  data(){
    return {
      ZINDEX
    }
  },
  mounted() {
    setTimeout(() => {
      this.close();
    }, this.delay);
  },
  props: {
    delay: {
      type: Number,
      default: 3000
    },
    htmlEnable: {
      type: Boolean,
      default: false
    },
    closeButton:{
      type:Boolean,
      default:false
    },
    callback:{
      type:Object
    },
    icon: {
      type: String,
      default: "info"
    }
  },
  methods: {
    close() {
      this.$el.remove();
      this.$emit("close");
      this.$destroy();
    },
    closeMessage() {
      var beforeClose = this.callback.beforeClose,
          afterClose = this.callback.afterClose
      beforeClose && beforeClose.call(this, this);
      this.close();
      afterClose && afterClose.call(this, this);
    }
  }
};
</script>
<style lang="scss">
@import "../../../css/message.scss";
</style>

message.js

import Vue from 'vue';
import Message from './message.vue';
import {mergeDeep} from '@/js/utils/tools.js'

let MessageConstructor = Vue.extend(Message);

const message = function () {
    var instance = null,
        uid = null
    return function (option) {
        if(typeof option == 'string'){
            option = {
                text: option
            }
        }
        var config = mergeDeep({
            props: {
                htmlEnable: false,
            },
            text: 'default'
        }, option)
        if (!instance || instance._uid != uid) {

            if (!instance) {
                instance = new MessageConstructor({
                    propsData: config.props
                })
                uid = instance._uid
            } else {
                let t = new MessageConstructor({
                    propsData: config.props
                })
                if (t._uid != uid) {
                    instance.closeMessage()
                    instance = t
                    uid = t._uid
                }
            }
            
            instance.$slots.default = [config.text]
            instance.$mount()
            instance.$on('close', function () {
                instance = null
                uid = null
            })

            document.body.appendChild(instance.$el)

        }
        return instance
    }
}

const plugin = {}
plugin.install = function (Vue, options) {
    Vue.prototype.$message = message()
}

export default plugin;

vue component is mounted to the global method refer to

Menu