React 30 秒速學: 實現可摺疊、無限層級的樹形組件

本文譯自:30-seconds-of-react。React 30 秒速學:全篇中文翻譯、學習,地址:30-seconds-of-react-zh_CN-umi,全部案例進行分析、註釋、上線。css

系列文章:react

樹形組件

實現一個可摺疊、無限層級、支持數組和對象的樹組件。git

  • 使用對象解構來設置某些傳入屬性的默認值。
  • 使用傳入的 toggled 屬性來肯定內容的初始狀態(摺疊/展開)。
  • 使用React.setState() hook 來建立isToggled狀態變量,並在最初爲它賦予傳入的 toggled的值。
  • 返回一個<div>來包裝組件的內容和用於改變組件的isToggled狀態的<span>元素。
  • 根據data上的isParentToggledisTogglednameArray.isArray()肯定組件的外觀。
  • 對於data中的每一個子節點,肯定它是對象仍是數組,並遞歸渲染子樹。
  • 不然,使用適當的樣式渲染一個<p>元素。

樣式:github

/* 樹節點的基本樣式 */
.tree-element {
  margin: 0;
  position: relative;
}
div.tree-element:before {
  content: '';
  position: absolute;
  top: 24px;
  left: 1px;
  height: calc(100% - 48px);
  border-left: 1px solid gray;
}

/* 切換顯示、隱藏的按鈕元素 */
.toggler {
  position: absolute;
  top: 10px;
  left: 0px;
  width: 0;
  height: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 5px solid gray;
  cursor: pointer;
}
.toggler.closed {
  transform: rotate(90deg);
}

/* 隱藏節點內容 */
.collapsed {
  display: none;
}
複製代碼

樹組件,組件內容較多,在學習過程當中我也對其中的內容,分別進行了註釋:數組

import styles from "./TreeView.css";

function TreeView({ // 使用對象解構來設置某些傳入屬性的默認值 data, toggled = true, // 摺疊按鈕,是否處於摺疊狀態 name = null, // 當前屬性名,若是子元素是對象顯示 isLast = true, // 是否最後一個 isChildElement = false, // 是否子元素 isParentToggled = true // 是否被父節點摺疊 }) {
  const [isToggled, setIsToggled] = React.useState(toggled);

  return (
    <div
      style={{ marginLeft: isChildElement ? 16 : 4 + "px" }}
      // 若是父摺疊就隱藏
      className={isParentToggled ? styles["tree-element"] : styles.collapsed}
    >
      {/* 摺疊按鈕,點擊設置反狀態 */}
      <span
        className={
          isToggled ? styles.toggler : `${styles.toggler} ${styles.closed}`
        }
        onClick={() => setIsToggled(!isToggled)}
      />
      {name ? <strong>&nbsp;&nbsp;{name}: </strong> : <span>&nbsp;&nbsp;</span>}
      {/* 開始符 */}
      {Array.isArray(data) ? "[" : "{"}
      {/* 子元素被摺疊 */}
      {!isToggled && "..."}
      {/* 渲染對象的子元素 */}
      {Object.keys(data).map((v, i, a) =>
        // 是對象,遞歸調用自身
        typeof data[v] == "object" ? (
          <TreeView
            data={data[v]}
            key={i}
            isLast={i === a.length - 1}
            // 子元素的屬性名,對象須要顯示屬性名,數組不顯示
            name={Array.isArray(data) ? null : v}
            isChildElement
            isParentToggled={isParentToggled && isToggled}
          />
        ) : ( // 不是對象,顯示內容便可
          <p
            key={i}
            style={{ marginLeft: 16 + "px" }}
            className={isToggled ? styles["tree-element"] : styles.collapsed}
          >
            {Array.isArray(data) ? "" : <strong>{v}: </strong>}
            {data[v]}
            {i === a.length - 1 ? "" : ","}
          </p>
        )
      )}
      {/* 結束符 */}
      {Array.isArray(data) ? "]" : "}"}
      {/* 不是最後元素,加個逗號 */}
      {!isLast ? "," : ""}
    </div>
  );
}
複製代碼
例子
export default function() {
  let data = {
    lorem: {
      ipsum: "dolor sit",
      amet: {
        consectetur: "adipiscing",
        elit: [
          "duis",
          "vitae",
          {
            semper: "orci"
          },
          {
            est: "sed ornare"
          },
          "etiam",
          ["laoreet", "tincidunt"],
          ["vestibulum", "ante"]
        ]
      },
      ipsum: "primis"
    }
  };
  return <TreeView data={data} name="data" />; } 複製代碼

ps:post

相關文章
相關標籤/搜索