基於TypeScript與React Hooks開發的通用組件庫

項目地址(歡迎star):react-draggable-layercss

技術博客:www.linxiangjun.com前端

前言

2019年以來,愈來愈多的公司與項目都選擇使用強類型語言TypeScript做爲主要語言,能夠預見的是2020年TypeScript將成爲前端開發所須要具有的能力之一。react

目前前端工程師使用最多的無疑問是微軟開源的VSCode,它自己提供的功能並很少,可是經過支持插件的方式使得其具有了IDE的強大能力。同時,VSCode是使用TypeScript基於Eletron開發的,使得它對於TypeScript的支持很是的強大。若是你使用的編輯器是VSCode,那麼項目中徹底使用TypeScript編程將會大大的提升編程效率,甚至使用一段時間後你會發現,已經漸漸離不開TypeScript。git

應用新的語言仍是語法都會面臨着許多困難和陷阱,這個時候若是可以參考一些現成的寫法確定會帶來收益。這也是我寫這篇文章的初衷。github

下面是react-draggable-layer使用到的一些技術細節:npm

  • TypeScript
  • React Hooks
  • React Portals
  • emotion
  • Babel

實現

效果動畫

Portals

實現一個彈層類組件,React提供了Portals方法,可以將子節點渲染到存在於父組件之外的DOM節點上。咱們先實現一個封裝了Portals方法的通用組件:編程

components/Portal.jsx前端工程師

import React, { useEffect, useRef } from "react";
import ReactDOM from "react-dom";

interface PortalProps {
  children: React.ReactElement;
}

const Portal: React.FC<PortalProps> = props => {
  // 使用useRef建立ref對象,能夠用來保存節點
  const { current: el } = useRef(document.createElement("div"));

  // 等同於類組件的componentDidMount方法
  useEffect(() => {
    const root = document.getElementById("root");
    if (root) {
      root.appendChild(el);
    }

    // 組件銷燬後記得移除div
    return () => {
      if (root) {
        root.removeChild(el);
      }
    };
  }, []);

  return ReactDOM.createPortal(props.children, el);
};

export default Portal;

複製代碼

css-in-js

有了Portal組件以後在可拖拽彈層組件中引入,這樣組件在使用時就能夠掛載到root節點下。在組件中樣主要是以css-in-js的方式來實現的,它的優勢有:app

  1. 不須要引入css樣式文件或者css預處理器
  2. 可避免由於樣式名衝突帶來的全局污染問題
  3. 不須要各類繁瑣的命名規則

這並非說它就沒有缺點的,一樣的,使用css-in-js來開發會使得不少高階css用法很是的複雜,因此須要根據項目狀況來辯證的思考與選擇。不過對於此項目來講css-in-js就很是的合適,它使得咱們能夠將更多的精力放在組件化上面。另外這裏推薦下emotion這個庫。dom

React.FC

這裏先來基於項目說一下TypeScript開發React函數式組件的規範:

interface DraggableLayerProps {
  children?: React.ReactElement;
  titleName?: string;
  visible?: boolean;
  onClose?: () => void;
}

const DraggableLayer: React.FC<DraggableLayerProps> = props => <Component />

export default DraggableLayer
複製代碼

使用函數式組件時須要將組件申明爲React.FC類型,也就是Functional Component的意思,另外props須要申明各個參數的類型,而後經過泛型傳遞給React.FC

draggable

可拖拽功能的實現是基於實時計算組件x軸與y軸的距離來實現的,具體代碼比較簡潔:

let initX = 0;
let initY = 0;
let isMouseDown = false;

const handleMouseDown = (e: MouseEvent) => {
    isMouseDown = true;
    initX = e.offsetX;
    initY = e.offsetY;
    draggableRef.current.style.opacity = 0.5;
  };

  const handleMouseMove = (e: MouseEvent) => {
    if (isMouseDown) {
      const x = e.clientX - initX;
      const y = e.clientY - initY;
      draggableRef.current.style.left = `${x}px`;
      draggableRef.current.style.top = `${y}px`;
    }
  };

  const handleMouseUp = () => {
    isMouseDown = false;
    if (draggableRef && draggableRef.current) {
      draggableRef.current.style.opacity = 1;
    }
  };
複製代碼

穩健性

在組件獲取props時有不少可選的參數,好比titleName,由於使用了TypeScript,因此對可選參數進行賦值操做時提示錯誤信息,這點在開發時可以有效的避免出錯。另外,組件銷燬後須要在useEffectreturn回調函數中清除綁定的event。這些細節須要注意。

總結

很是歡迎嘗試本項目,能夠直接使用npm install react-draggable-layer來使用,有好的建議也但願可以收到提交的issues。一些更加詳細的使用說明在項目中的README文件中。若是本文或者項目對你有幫助的話,很是高興您可以點下star支持。

相關文章
相關標籤/搜索