preface

In this eleventh article in my series on component design, I’m going to introduce you to an equally special component, the Message component. We might see a component effect like this:

Realize a powerful Notification box with the React/Vue Series.

The basic component libraries are divided into the following categories:

  • Generic components: Button, Icon, etc.
  • Layout components: Grid, Layout, etc.
  • Navigation components: Breadcrumb, Dropdown, Menu, etc.
  • Data entry components: such as form, Switch, Upload file Upload, etc.
  • Data presentation components: Avator profile, Table, List, etc.
  • Feedback components: Progress bars, drawers, Modal dialog boxes, etc.
  • Other Business Types

Familiarity with the taxonomy above is a prerequisite for designing any component system, whether you are developing a front-end team’s UI library from zero to one or a secondary business component based on an existing component library.

This article will use React to develop this component. It will also use some design patterns commonly used in Javascript, such as the singleton pattern. However, no matter what framework you use to implement it, the principle will be the same. If you are not familiar with design patterns, you can move to:

15 minutes of javascript design patterns that front-end engineers need to know (with detailed mind maps and source code).

The body of the

Before starting component design, I hope you have a basic knowledge of CSS3 and JS, and understand the basic React /vue syntax. Let’s first deconstruct the Message component. A Message is divided into the following parts:

success
warning
error
info
Message

Here’s what the Message component looks like using React:

Next, let’s take a look at the specific design ideas of the Message box.

1. Message component design

Following the principles of component design outlined by the author earlier, our first step is to identify requirements. The Message component typically has the following requirements:

  • Can control the Message automatic closing time
  • Can configure the output location of the Message render node
  • Can customize close icon
  • You can manually select the global prompt type
  • The offset of the global prompt can be customized
  • Message text that can be set for global prompts
  • Icon that can customize the global prompt
  • Provide a callback function when a global prompt is clicked
  • Provide a callback function when the global prompt is closed
  • Can manually destroy notification box

Once the requirements have been gathered, as an aspiring programmer, the following wireframes emerge:

Notification Component Design

2. Implement a global Message component based on React

For the core part of the component, we will use the React Notification pattern.

2.1 Building the Basic framework of the Notification Box

First, in my code style, I usually consider the framework of the component design, and then step by step fill in the content and logic. Through this progressive design idea, we can make our logic more rigorous, more clear. The specific code is as follows:

import Notification from 'rc-notification'
import './index.less'

const xMessage = (function() {
  let message = null
  /** * Notice Type popover * @param {config} Object Prompt configuration properties * @param {type} String Prompt type * @param {BTN} ReactNode Custom close button * @param {className} string Custom CSS class * @param {duration} number Null does not automatically disable * @param {getContainer} HTMLNode Configuration rendering node output location * @param {icon} ReactNode custom icon * @param {key} String Current "the only indicator * @ param {content} string | ReactNode prompt title, Required * @param {onClose} func * @param {onClick} func * @param {top} number * @param {top} number * @param {top} number Unit pixel * @param {closeIcon} ReactNode custom closeIcon */
  const pop = (config) = > {
    const {
      type, className,
      duration = 4.5,
      getContainer = (a)= > document.body,
      icon, key, content, onClose, onClick,
      top, closable = true, closeIcon
    } = config
    message.notice({
      content: <div className={classnames('xMessage', className)} >
        <div className={classnames('iconWrap', type)} >
            <Icon type={iconType[type]} />
          </div>
        <div className="xNoticeTit">
          { content }
        </div>
      </div>, key, closable, getContainer, onClose() { onClose && onClose() }, onClick() { onClick && onClick() }, closeIcon, duration, style: {top}})} /** * Prompt component, global parameter * @param {duration} number Automatically turns off the delay by default, in seconds * @param {getContainer} HTMLNode Configures the output location of the render node, Default document.body * @param {closeIcon} HTMLNode custom closeIcon */ const config = (config) => {} const remove = (key) => {} const Destroy = () => {} if(message) {return {config, pop, remove, destroy}} NewInstance ({}, (notice) => message = notice) return {config, pop, remove, destroy } })() export default xMessageCopy the code

First, we listed the attributes according to the requirements. Through analysis, we should provide four external interfaces for developers to use, which are:

  • Config — Message global configuration, which controls global offsets, styles, rendering containers, etc.
  • Pop – a method used to create a global prompt instance while controlling its properties
  • Remove — Used to remove the specified instance
  • Destroy — To destroy global messages

Let’s implement the config first:

const config = (config) = > {
  const { duration, getContainer, closeIcon } = config

  Notification.newInstance({
    getContainer: getContainer,
    duration: duration || 4.5,
    closeIcon
  }, (notice) => message = notice)
}
Copy the code

Of course, we can also customize the extension according to their own needs.

Pop method implementation:

const pop = (config) = > {
    const {
      type,
      className,
      duration = 4.5,
      getContainer = (a)= > document.body,
      icon,
      key,
      content,
      onClose,
      onClick,
      top,
      closable = true,
      closeIcon
    } = config
    message.notice({
      content: <div className={classnames('xMessage', className)} >
        {
          (icon || ['info', 'success', 'error', 'warning'].indexOf(type) > -1) &&
          <div className={classnames('iconWrap', type)} >
            {
              icon ? icon : <Icon type={iconType[type]} />
            }
          </div>
        }
        <div className="xNoticeTit">
          { content }
        </div>
      </div>,
      key,
      closable,
      getContainer,
      onClose() {
        onClose && onClose()
      },
      onClick() {
        onClick && onClick()
      },
      closeIcon,
      duration,
      style: { top }
    })
  }
Copy the code

This method is used to create an instance of the global message from the definition. We can call this method:

xNotification.pop({type: 'success'.content: 'Your request has been approved! '})
Copy the code

The actual effect is as follows:

// antd
Notification.info({/ /... })
Copy the code

The reason why I did this is because the DOM structure of info, SUCCESS, and Warning states is completely reusable, so the configuration method can greatly reduce redundant code.

The remove and destroy methods are both simple, so let’s go straight to the code:

const remove = (key) = > {
    message.removeNotice(key)
  }

const destroy = (a)= > {
  message.destroy()
}
Copy the code

As you can see above, their implementations are based on the API that comes with the Message instance.

2.2 Implementation of notification box type and custom icon

First we define a mapping between a type and an icon:

 const iconType = {
    success: 'FaRegCheckCircle'.warning: 'FaRegMeh'.info: 'FaRegLightbulb'.error: 'FaRegTimesCircle'
 }
Copy the code

These four types correspond to different types of icon ICONS, so we can display different ICONS according to the type passed in by the user:

<div className={classnames('iconWrap', type)}>
    <Icon type={iconType[type]} />
</div>
Copy the code

However, one thing we need to consider is that if the user passes in a custom icon, we should theoretically display the custom icon, so type and icon should be related. If the user has not configured the type and has not passed the icon, then in fact there is no need to display the icon.

{
  (icon || ['info'.'success'.'error'.'warning'].indexOf(type) > - 1) &&
  <div className={classnames('iconWrap', type)} >
    {
      icon ? icon : <Icon type={iconType[type]} />
    }
  </div>
}
Copy the code

The realization effect is as follows:

2.3 Using the global Message component

We can use it in the following ways:

<Button type="warning" onClick={() = >{message. Pop ({type: 'error', content: 'error'})}}></Button>
Copy the code

Configure global properties:

import { message } from '@alex_xu/xui'

message.config({ duration: 6 })
Copy the code

I have published the implemented components to NPM. If you are interested, you can directly use NPM after installation. The method is as follows:

npm i @alex_xu/xui

/ / import xui
import { 
  Button, Skeleton, Empty, Progress,
  Message, Tag, Switch, Drawer, Badge, Alert
} from '@alex_xu/xui'
Copy the code

This component library can be imported on demand. We only need to configure babel-plugin-import in the project. The specific configuration is as follows:

// .babelrc
"plugins": [["import", { "libraryName": "@alex_xu/xui"."style": true}]]Copy the code

The NPM library screenshot is as follows:

The last

The author will continue to implement

  • The table (table),
  • Tooltip (tooltip bar)
  • Skeleton screen,
  • The form (form form),
  • The switch (switch),
  • Date/calendar,
  • Qr code recognizer component

And other components, to repeat the author of many years of componentization journey.

If you are not familiar with react/ Vue component design principles, please refer to my previous component design series:

  • Realize a powerful Notification box with the React/Vue Series.
  • Hand to Hand implements a lightweight and extensible Modal component
  • Master React/Vue Component Design implements a powerful Drawer component in conjunction with React Portals
  • Implement a Tag component and an Empty component in 5 minutes of React/Vue Component Design Mastery
  • Master React/Vue Component Design creates materialui-like button click animations with pure CSS and encapsulates react components
  • Quickly implement a customizable progress bar component in Master React/Vue Component Design
  • Master React/Vue Component Design: Repackaging a real-time preview JSON editor component in JsonEditor (React version)

I have published the component library on NPM, and you can experience the components through the NPM installation.

If you want to get the complete source code of component design series, or want to learn more H5 games, Webpack, node, gulp, CSS3, javascript, nodeJS, Canvas data visualization and other front-end knowledge and practical, welcome to join our technical group in the public number “interesting talk front end” to learn and discuss together, Explore the boundaries of the front end together.

More recommended

  • 2 years of vUE project practical experience summary
  • Javascript Design Patterns front-end Engineers Need to Know in 15 minutes (with detailed mind maps and source code)
  • In 2019, take a look at some of my top questions and advice for job seekers
  • A picture shows you how to play vue-Cli3 quickly
  • Vue Advanced Advanced series – Play with Vue and vuex in typescript
  • “Front-end combat summary” the use of pure CSS website skin and focus diagram switch animation
  • “Front-end combat summary” using CSS3 to achieve cool 3D rotation perspective
  • Add a loading progress bar to your site using pace. Js
  • The Application of design Pattern of “Summary of Front End Actual Combat” — Memorandum Pattern
  • “Front End Combat Summary” using postMessage to achieve pluggable cross-domain chatbot
  • “Front-end combat summary” of the variable promotion, function declaration promotion and variable scope detailed explanation
  • “Front-end combat summary” how to change the URL without refreshing the page