preface

This is my tenth article in component design, and today I’m going to introduce you to a very special component — the Notification box. This component can also be found in third-party component libraries such as Antd or elementUI and is used to provide system notification information to the user. We don’t call it by introducing a component label like we do with other components. For example, a Modal component is called like this:

<Modal title="Xui Basic Popover" centered mask={false} visible={false}>
    <p>I'm popover content</p>
    <p>I'm popover content</p>
    <p>I'm popover content</p>
    <p>I'm popover content</p>
</Modal>
Copy the code

But the Notification box, in most cases, is called using the JS API:

notification.open({
  message: 'Funny Talk front-end React'.description: 'Learn front end, React/vue/Node and join us soon'
});
Copy the code

We might see a component effect like this:

First, consolidate the taxonomy of the following components:

  • 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, as well as some design patterns commonly used in Javascript, such as the singleton pattern, but no matter what framework you use to implement it, the principles will be the same, if you are interested in using Vue to implement the following. 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 deconstruct the Notification component first. A Notification is divided into the following parts:

Here is the effect of the Notification component I implemented using React:

Let’s take a look at the design of the Notification box.

1. Design of the Notification component

Following the principles of component design outlined by the author earlier, our first step is to identify requirements. Notification components typically have the following requirements:

  • Control the timing of Notification automatic shutdown
  • The output location of the Notification render node can be configured
  • Can control the pop-up location of the Notification
  • Can customize close icon
  • You can manually select the notification window type
  • Can customize the offset of the notification box
  • Can set the notification box information and prompt text
  • Icon that can customize notification box
  • Provide a callback function when the notification box is clicked
  • Provides a callback function when the notification box closes
  • Can manually destroy notification box

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

2. Implement a Notification box based on React

The idea of the Notification box API call is to dynamically Render the specified tag through JSX, and then Render the DOM to the specified container by ReactDom’s Render API. In order to implement the notification.info method, you need to consider the problem of creating an instance. We should use the singleton pattern to control the number of instances created. The pseudocode is as follows:

const xNotification = (function() {
    let notification = null;
    if(notification) {
        return {
            render(dom){},
            config(config){},
            info(config){},
            error(config){}
            // ...}}else {
        notification = new Notification({})
        return {
            render(dom){},
            config(config){},
            info(config){},
            error(config){}
            // ...}}}) ()/ / usexNotification.info({... }) xNotification.error({... })Copy the code

However, to really implement the functions of the Notification box discussed above, in fact, we still need to write a lot of code to deal with different situations. Therefore, in order to facilitate your understanding, we use the React Notification third-party library to help us deal with the basic logic. Based on it, To implement the functions we discussed above.

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 xNotification = (function() {
  let notification = null
  /** * Notice Type popover * @param {config} Object Notification box configuration properties * @param {type} String Notification window type * @param {BTN} ReactNode Custom close button * @param {bottom} number Distance from the bottom when the message pops up from the bottom, Unit pixel * @ param {className} string a custom CSS class * @ param description string attach | ReactNode notifications, Mandatory * @param {duration} number Automatically turns off after 4.5 seconds by default, Null does not automatically disable * @param {getContainer} HTMLNode Configuration rendering node output location * @param {icon} ReactNode custom icon * @param {key} String The current notice only marked * @ param message string attach | ReactNode notifications at the 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, bottom, className, description, duration = 4.5,
      getContainer = (a)= > document.body, icon, 
      key, message, onClose, onClick, top, closable = true, closeIcon
    } = config
    notification.notice({
      content: <div className={classnames('xNotice', className)} >
        <div className={classnames('iconWrap', type)} >
            <Icon type={iconType[type]} />
        </div>
        <div>
          <div className="xNoticeTit">
            { message }
          </div>
          <div className="xNoticeDesc">
            { description }
          </div>
        </div>
      </div>})} /** * Notification prompt component, global parameter * @param {duration} number Specifies the distance from the bottom of the message when it is popup from the bottom, in pixels, default 24 * @param {duration} number * @param {getContainer} HTMLNode Configures the output location of the render node, default document.body * @param {placement} String Popup location, Optional topLeft topRight bottomLeft bottomRight * @param {top} number Specifies the distance from the top when a message is poped from the top, */ const Config = (config) => {const {duration, getContainer, Placement, closeIcon } = config Notification.newInstance({ getContainer: getContainer, duration: Duration | | 4.5, closeIcon}, (notice) = > notification = notice)} if {return (notification) {config, Pop}} // To create an instance, NewInstance ({}, (notice) => Notification = notice) return {config, pop } })() export default xNotificationCopy the code

First, we listed the attributes of each item according to the requirements. The configuration method we use globally is xnotification.config (config), and in the notification box instance we use xnotification.pop (config). For example, to render a successful notification box, we can do this:

xNotification.pop({type: 'success'})
Copy the code

Antd is called in the same way:

// 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.

2.2 Implementation of notification box type and custom icon

In fact, the author has completed the configuration of some attributes when building the component framework, so I will not introduce one here, the author will introduce some more important methods to achieve.

We can see from the observation that to implement different notification box types, we just need to dynamically replace the icon according to the type. Icon icon part of the author has implemented the ICON component, the specific usage and ANTD icon component is similar, if you want to learn how to encapsulate their own icon component can refer to the author source code.

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 Placement of the Notification box

The location of the Notification box should be configured globally according to the business scenario, so we set it in the config method. We can also define an enumeration class for how to control the location of the Notification based on the location information passed in by the user:

const adapterPos = {
    topLeft: {
      top: '24px'.left: '24px'
    },
    topRight: {
      top: '24px'.right: '24px'
    },
    bottomLeft: {
      bottom: '24px'.left: '24px'
    },
    bottomRight: {
      bottom: '24px'.right: '24px'}}Copy the code

As you can see from the code above, we will define four base positions, all with a default offset of 24px, and then we can match our position information according to the placement we pass in:

Notification.newInstance({
  style: {... adapterPos[placement] },// ...
Copy the code

The above code tells you the location information that we set with style. The specific effects are as follows:

2.4 Realize the animation effect of notification box

We implement an animation similar to antD’s entry from right to left. Let’s rewrite the style as follows:

.rc-notification-fade-enter {
    animation: moveLeft .3s;
}
.rc-notification-fade-leave {
    animation: moveOutLeft .3s;
}
.rc-notification-fade-enter.rc-notification-fade-enter-active {
    animation: moveLeft .3s;
}
.rc-notification-fade-leave.rc-notification-fade-leave-active {
    animation-name: moveOutLeft .3s;
}

@keyframes moveOutLeft {
    0%{}100% {
        right: -200%; }}@keyframes moveLeft {
    0% {
        right: -200%;
    }
    100% {
        right: 0; }}Copy the code

With these steps, a powerful Notification box is complete. The Notification component is one of the more complex components in the library. If you don’t know anything about it, you can ask questions in the comment section and I will answer them as soon as I see them.

2.5 Using the Notification component

We can use it in the following ways:

<Button type="primary" onClick={() = >{xnotification. pop({type: 'success', message: 'Learn to punch in ', Description:' Basic, intermediate, advanced, punch in ', 996 Away from you '})}}</Button>
Copy the code

Configure global properties:

import { xNotification } from '@alex_xu/xui'

xNotification.config({
    placement: 'topRight'
})
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,
  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,
  • Message(global prompt),
  • 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:

  • 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