preface

Worked on a mobile TERMINAL H5 project built with vue2 + typescirpt. You need to use a global prompt component in your project, similar to the Message component of Element UI. So you implement a global Message component that does the above.

Technical approaches

Implementation on VUe2

The install function is key to instantiating and rendering the Message component you wrote to the page. The steps are as follows:

  1. Generates its constructor from the Message component
  2. Instantiate a Message component
  3. AppendChild instance on document.body

Write the Message component code

// Message.vue
<template>
  <transition name="slide">
    <div
      class="message-wrap"
      :class="[type, center ? 'text-center' : '']"
      :style="{ ...style }"
      v-if="visible"
    >
      <div v-if="messageArr.length" class="message-line">
        <div
          v-for="(item, index) in messageArr"
          :key="index"
          class="message-line-item"
        >
          {{ item }}
        </div>
      </div>
      <div v-else class="message">{{ message }}</div>
    </div>
  </transition>
</template>
<script lang='ts'>
import { Component, Vue } from 'vue-property-decorator';
@Component({
  components: {},})export default class extends Vue {
  private message = ' '; // Message content
  private messageArr: Array<string> = [];
  private visible = false; // Whether to display components
  private type = 'info'; // 'success','error'
  private duration = 2000; // Timer duration
  private center = false; // Whether the text is centered
  private style = {}; // Customize the style
  created(): void {
    const arr = this.message.split('\n');
    if (arr.length > 1) {
      this.messageArr = arr;
    }
  }
  private startTimer() {
    window.setTimeout(() = > {
      this.visible = false;
    }, this.duration);
  }
  private mounted() {
    this.startTimer(); }}</script>
Copy the code

Write the install function and mount it globally to vue

// install.ts
import Vue from 'vue';
import MessageComp from './Message.vue';

const MessageBox = Vue.extend(MessageComp); // Create a component constructor, not an instance
let hasInsatll = false;
const Message = {
  install: (options: any): void= > {
    if (typeof options === 'string' || typeof options === 'number') {
      options = {
        message: options,
      };
    }  else {
      if (typeofoptions ! = ='object') {
        options = {
          message: ' '}; }}if (typeofoptions.duration ! = ='number' || options.duration < 0) {
      delete  options.duration;
    }
    // Create a Message instance
    const instance: any  = new MessageBox({
      data: options,
    }).$mount();
    if(! hasInsatll) { hasInsatll =true;
    } else {
      // Mount the instance to the body
      document.body.appendChild(instance.$el); // Add a DOM element
    }
    Vue.nextTick(() = > { // Execute the callback after the DOM element is rendered
      // Display Message component instance
      instance.visible = true; }); }};// Mount the install function to vue globally
Vue.prototype.$message = Message.install;

// Extend the success and error functions
['success'.'error'].forEach((type) = > {
  Vue.prototype.$message[type] = (message: any) = > Vue.prototype.$message({ message, type });
});
export default Message;
Copy the code

Message Use is a global component

// main.ts
import Message from '@/components/Message';

Vue.use(Message as any);
Copy the code

Add $message to Vue ts declaration to eliminate ts error

// shims-tsx.d.ts
import Vue, { VNode } from 'vue';

declare global {
  namespace JSX {
    // tslint:disable no-empty-interface
    interface Element extends VNode {}
    // tslint:disable no-empty-interface
    interface ElementClass extends Vue {}
    interface IntrinsicElements {
      [elem: string]: any
    }
  }
}

declare module 'vue/types/vue' {
  interface Vue {
    $message: any; }}Copy the code

use

// Basic usage
this.$message('info type'); // info Message type
this.$message.success('success type'); // Success message type
this.$message.error('error type'); // Error message type

// Customize the property value
this.$message({
    message: 'message'.type: 'info' | 'success' | 'error'.// info is the default
    duration: 5000.// in milliseconds
})
Copy the code