preface

The tip component is probably the one we use the most in our projects, but the one we use the most. Are you sure you really know it? Let’s talk about it today

Start implementing it

start

It’s not that hard to implement a component. Create a component, import the component, and say show and hide

<template> <div> <Alert v-if="show"> </Alert> < button@click ="show = true"> <script> import Alert from '.. /component/alert.vue'; export default { components: { Alert }, data () { return { show: false } } } </script>Copy the code

This implementation has several disadvantages

  • Every place you use it, you have to register it

  • Both require

    to be placed in the template

  • Additional data is required to control the display state of the Alert

  • The location of the Alert, which is under the current component and not under the body, may be obscured by other components

Very user unfriendly anyway, so how do you gracefully implement such a component?

// Global alert window.alert(' This is an alert '); // double confirm const confirm = window.confirm(' Do you want to delete? '); if (confirm) { // ok } else { // cancel }Copy the code

In fact, native JavaScript already provides the answer:

So we need to try calling component apis from JS

Let’s take our first step

This is what we expect the final API to look like

Methods: {handleShow () {this.$Alert({content: 'this is a prompt ', duration: 3})}}Copy the code

$Alert can be called from anywhere, without having to be introduced separately. This method takes two arguments:

  • Content: prompt content
  • Duration: indicates the duration, in seconds. The default value is 1.5 seconds.

Let’s start with the simplest of the best and write a basic Alert component first.

Create an alert directory under SRC/Component and create the file alert.vue:

Notice is multiple, and we manage each notice by using an array of notice

<! -- alert.vue --> <template> <div class="alert"> <div class="alert-main" v-for="item in notices" :key="item.name"> <div class="alert-content">{{ item.content }}</div> </div> </div> </template> <script> export default { data () { return { notices: [] } } } </script>Copy the code

The Alert component is different from normal component usage in that it is ultimately called through JS, so the component does not have to reserve the props and Events interfaces.

We’ll assume that content and duration will eventually be passed in by calling the add method of Alert via JS:

<! -- alert. Vue --> <script> let seed = 0; function getUuid() { return 'alert_' + (seed++); } export default { data () { return { notices: [] } }, methods: { add (notice) { const name = getUuid(); let _notice = Object.assign({ name: name }, notice); this.notices.push(_notice); // Timing removal, in seconds const duration = notice.duration; setTimeout(() => { this.remove(name); }, duration * 1000); }, remove (name) { const notices = this.notices; for (let i = 0; i < notices.length; i++) { if (notices[i].name === name) { this.notices.splice(i, 1); break; } } } } } </script>Copy the code

In the add method, each incoming hint data is identified by a unique name field, and a timer is created by setTimeout. When the specified duration is reached, the remove method is called. Find the prompt for name and remove it from the array.

With this idea, the Alert component can be extended indefinitely, passing more parameters in the add method to support more complex components, such as whether to display a manual close button, a OK/cancel button, or even passing in a Render function.

Instantiation encapsulation

In this step, we further encapsulate the Alert component so that it can be instantiated instead of the normal component usage. Extend or new Vue and mount it under the body node with $mount.

Create a new notification.js file under SRC /components/alert:

// notification.js import Alert from './alert.vue'; import Vue from 'vue'; Alert.newInstance = properties => { const props = properties || {}; const Instance = new Vue({ data: props, render (h) { return h(Alert, { props: props }); }}); const component = Instance.$mount(); document.body.appendChild(component.$el); const alert = Instance.$children[0]; return { add (noticeProps) { alert.add(noticeProps); }, remove (name) { alert.remove(name); }}}; export default Alert;Copy the code

Notification. js is not the final file, it just adds a method called newInstance to alert.vue. Although alert.vue contains template, script, and style tags, it is not a JS object. How can we extend newInstance to it? In fact, alert.vue will be compiled by Webpack’s Vue-loader, which compiles the template into the Render function and eventually becomes a JS object that can be naturally extended.

The Alert component doesn’t have any props, so when Render the Alert component, we give props ({}) as an empty object, and it doesn’t work even if the content is passed. Again, this is for extensibility, so if you want to add props to Alert to support more features, you pass it in here. But then again, because you can get an Alert instance, you can use data or props.

The entrance

The last thing you need to do is call notification.js to create an instance and pass the data through add, which is the final step in component development and the final entry point. Create alert.js under SRC /component/alert:

// alert.js import Notification from './notification.js'; let messageInstance; function getMessageInstance () { messageInstance = messageInstance || Notification.newInstance(); return messageInstance; } function notice({duration = 1.5, content = ""}) {let instance = getMessageInstance(); instance.add({ content: content, duration: duration }); } export default { info (options) { return notice(options); }}Copy the code

The getMessageInstance function is used to get the instance. It does not create the instance repeatedly. If the messageInstance already exists, it returns the instance directly.

Alert. Js provides a method info. If you need various display effects, such as success, failure, warning, you can provide more methods under info, such as success, fail, warning, etc. And pass different parameters to let alert. vue know which status icon to display. This example, because there is only one info, can actually omit it and export a default function, so that when called, instead of this.$Alert. Info (), this.

/ / SRC /main.js; / / SRC /main.js; / / SRC /main.js;

The end of the

  1. Alert. Vue has an.alert node in its outermost layer, which is called the first time$AlertIs created under body because it is not there<router-view>In, it is not affected by routing, that is, once created, the node does not disappear until the page is refreshed. Therefore, in the design of alert.vue, instead of actively destroying this component, an array of child nodes is maintainednotices.
  2. Alert node isposition: fixedFixed, so design it properlyz-indexOtherwise, it may be blocked by other nodes.
  3. Notification. js and alert.vue can be reused if other similar components, such as the secondary validation component, are also developed$Confirm, just write another entryconfirm.jsAnd willalert.vueFurther encapsulation will benoticesThe loop body of the array is written as a new component that is configured to render Alert or Confirm, which is maintenance-friendly.
  4. In the notification. Js new Vue, use the Render function to Render alert. The Vue, this is because the template in the runtime Vue. Js version will be an error.

conclusion

The essence of vue.js is a component, and the essence of a component is JavaScript. Combine JavaScript development techniques with vue.js components and you can play something different.