Umi4選單欄將collapse按鈕放置底部

Karle發表於2024-08-14

背景

Umi@4中選單欄的collapse按鈕預設不在選單欄底部,需求要將該按鈕放回選單底部並且改變預設icon

一開始做法

  • 直接修改元件樣式,將其放置到選單元件底部
  • 但是無法修改icon
    • 不想使用偽元素去重寫icon,而且無法做到不同狀態不同icon
  • .ant-pro-sider-collapsed-button {
        bottom: 0;
        left: 0;
        width: 100%;
        height: 44px;
        padding: 0 !important;
        border-radius: unset;
        border-top: 1px solid #e8eaeb;
        box-shadow: none;
        inset-block-start: unset;
    
        svg {
            color: #999;
            font-size: 18px;
        }
    }

於是希望能在配置項裡面進行更改,但是沒有提供僅更改icon的屬性,只有提供collapsedButtonRender這個屬性去渲染元素。

但是下面這種做法無效❌

  1. 在app.tsx layout這個函式里面寫元件。(但是這個函式是umi在執行時讀取的配置項屬性,該函式返回一個配置項物件)
  2. 透過useState定義變數去控制collapse屬性和onCollapse,然後用該變數條件渲染不同icon或者不同class

正確做法

參考了這篇部落格,然後稍作修改https://blog.csdn.net/qq_41595144/article/details/120985948

  1. 編寫一個元件作為collapsedButtonRender屬性傳入值
    1. 接收引數collapse和onCollapse回撥函式
    2. 設定本地響應式資料collapsed,用來控制節點或者樣式
    3. 當本地的collapsed改變後,呼叫onCollapse,通知呼叫者collapse狀態改變
import { MenuUnfoldOutlined } from '@ant-design/icons';
import { FC, memo, useEffect, useState } from 'react';
import './index.less';

interface Props {
  collapse?: boolean;
  onCollapse?: (collapsed: boolean) => void;
}
export const Index: FC<Props> = memo(({ collapse, onCollapse }) => {
  const [collapsed, setCollapsed] = useState<boolean>(collapse ?? false);

  useEffect(() => {
    if (collapse) {
      setCollapsed(collapse);
    }
  }, [collapse]);

  useEffect(() => {
    if (onCollapse) {
      onCollapse(collapsed);
    }
  }, [collapsed]);

  return (
    <div
      className={
        collapsed
          ? 'menu-collapsed-button menu-collapsed-button-active'
          : 'menu-collapsed-button'
      }
      onClick={() => setCollapsed(!collapsed)}
    >
      <MenuUnfoldOutlined />
    </div>
  );
});
export default Index;

2. 修改app.tsx getInitialState()方法,增加collapse型別

3.修改app.tsx layout()方法

  1. 對入參進行解構,獲取到initialState和setInitialState兩個引數
  2. 定義collapse狀態改變時的回撥函式onCollapse,透過setInitialState來改變狀態
  3. 將相關內容寫入配置項
export const layout: RunTimeLayoutConfig = ({
  initialState,
  setInitialState,
}) => {
  const onCollapse = (collapsed: boolean) => {
    setInitialState({ ...initialState, collapsed } as any).then();
  };
  return {
    ...
    collapsed: initialState?.collapsed,
    onCollapse: onCollapse,
    collapsedButtonRender: () => (
      <MenuCollapseButton
        collapse={initialState?.collapsed}
        onCollapse={onCollapse}
      />
    ),
  };
};

相關文章