整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          微信小程序切圖之列表折疊展開效果

          圖網專注于各種pc、手機、h5、小程序切圖,經常會遇到一些問題,做個筆記供后來者參考。

          列表的折疊效果用處很多,經常都會有遇到,特別是html5手機版,pc版的切圖的時候,小程序切圖也不例外,不過小程序的寫法和html的略有不同,和vue的邏輯更為相似,下面附關鍵代碼片段,親測有用。

          wxml文件

          <view class="fold__panel">
          <block wx:for="{{dataList}}" wx:key="LMF_ID" wx:for-item="dataInfo" wx:for-index="dataIndex">
          <view class="fold__items" data-index="{{dataIndex}}" catchtap="listDataClick">
          <!-- 標題 -->
          <view class="fold__item--head">
          <view class="fold__head--l">
          <text class="fold__head--tag">一對一</text>
          <text class="fold__head--title ellipsis">TOEFL 一對一規劃</text>
          </view>
          <view class="fold__head--r {{showIndex==dataIndex?'on':''}}">
          <i-icon type="arrow-down" size="24" color="#EBEBEB" />
          </view>
          </view>
          <!-- 展開內容 -->
          <view wx:if="{{showIndex==dataIndex}}" class="fold__item--content">
          展開展開展開展開展開展開展開展開展開展開展開展開展開
          </view>
          </view>
          </block>
          </view>

          js文件

          個教程的最終效果如下:



          reactMenu.gif

          特點:

          • 支持小紅點,
          • 支持菜單互斥,
          • 支持消息數量顯示、
          • 支持暗黑暗模式
            廢話少說,下面開擼

          環境設置

          基于這篇文章,你應該首先已經了解了如何創建react項目,用create-react-app也好,用vite也罷。首先你要會創建項目。我的組件UI采用的是MUI, 所以要安裝MUI,當然你也可以使用其它的UI組件。當你學習完這個小節并且充分理解后,你就可以隨心所欲的做出修改。

          安裝環境

          ## npm安裝方式
          ## MUI
          npm install @mui/material @emotion/react @emotion/styled
          ## 字體
          npm install @fontsource/roboto
          ## 圖標
          npm install @mui/icons-material
          ## 動畫
          npm install react-transition-group --save
          
          ## yarn安裝方式
          yarn add @mui/material @emotion/react @emotion/styled
          yarn add @fontsource/roboto
          yarn add @mui/icons-material
          yarn add react-transition-group
          

          布局樣式部份使用了bootstrap中的布局樣式。所以還要導入bootstrap的樣式。

          npm i bootstrap@5.3.2
          

          或者你直接把bootstrap布局包放到項目文件下直接引用也是一樣的。其實我就是這么干的。
          我寫了一個CssBaseLine組件,把要引用的樣式在這個組件里引用進來就OK了。

          import CssBaseline from '@mui/material/CssBaseline';
          import '../SCSS/public.css';
          import '../SCSS/components.css';
          import '../SCSS/bootstrap5.3.0/css/bootstrap-utilities.min.css';
          import '../SCSS/bootstrap5.3.0/css/bootstrap-grid.min.css';
          
          export default function AdapterCss() {
            return <CssBaseline />
          }

          這樣,你只要在你的App進口組件中引用這個CSSBaseline就OK了

          數據準備

          為了減少對第三方組件的依賴,這個部件的內部狀態我采用useReact來進行管理。這省去了寫一大堆代碼的麻煩。
          菜單的配置當然越簡單越好,能用Json的格式最好,萬一你想把配置信息放在服務器上呢,這就方便許多了。我們以JSON數組的方式來進行配置管理。菜單最多可以配置二級菜單。也就是二級菜單以上的菜單就沒必要支持了,如果你有二級以的需要,通過這個篇幅學習以后我想你弄個三級四級的支持也不是什么難事。

          示例

          const sideMenuDataTest = [
              { id: "init", title: "系統初始化", icon: DataUsageIcon },
              { id: "management", title: "用戶管理", icon: GroupAddIcon },
          
              {
                  id: "userMsg", title: "角色管理", icon: PersonIcon, children: [
                      { id: "", title: "權限管理", icon: VerifiedUserIcon },
                      { id: "pwdMsg", title: "密碼管理", icon: PasswordIcon },
                      { id: "keyMsg", title: "私鑰管理", icon: VpnKeyIcon },
                      { id: "agentMsg", title: "權限管理", icon: HealthAndSafetyIcon },
                  ]
              },
          
              { id: "advMsg", title: "廣告管理", icon: FeaturedVideoIcon },
              { id: "plyMsg", title: "評論管理", icon: ReplyAllIcon },
          
              {
                  id: "title", title: "文章管理", icon: null, children: [
                      { id: "caogaoMsg", title: "草稿件", icon: null },
                      { id: "newFile", title: "新建文章", icon: null },
                      { id: "firstMsg", title: "置頂管理", icon: null },
                      { id: "recMsg", title: "推薦管理", icon: null },
                      { id: "classMsg", title: "類型管理", icon: null },
                      { id: "emailMsg", title: "郵箱管理", icon: null },
                  ]
              },
          
              { id: "system", title: "系統設置", icon: null },
              { id: "userCenter", title: "個人中心", icon: null }
          ];

          通過對上面的數據分析,我想你應該不難看出其數據結構的邏輯。有二級菜單的就包含children項,反之則沒有,就這么簡單。

          狀態管理器

          這么個相對較復雜組件,還要有高度自定義的特性,我們肯定不能直接封裝在一個組件文件里面,肯定要解耦。那么各級組件的狀態的流通就直接關系到封裝的成敗及性能高低了。通過啟篇的Gif圖可以看到,菜單組成可能分成以下幾個大的部分:
          1. 主菜單頭,里面包含logo 及 項目標題
          2. 一菜單欄,包含功能圖標及菜單功能標題
          3. 二級菜單欄,也稱組菜單。含有子菜單
          4. 收縮按鈕
          以上各個組件里還是若干小組件,而菜單的實時狀態也是要求無障礙貫穿的。這就需要一系列的狀態提供器(provider),但這之前我們要理解
          useReducer的相關使用方法:

          使用Reducer

          useReducer是一個 React Hook 語法如下:

          const [state, dispatch] = useReducer(reducer, initialArg, init?)

          具體的用法及介紹請參考我的下一篇技術文章:React之useReducer

          定義SideMenuProvider.jsx文件

          import { useReducer, createContext, useState } from 'react';
          import React from 'react';
          
          /**
           * 獲取菜單項的id集合, 菜單項的ID必須唯一,用于初始化菜單項的徽章,本菜單的每個Item都有一個id屬性,用于唯一標識菜單項。
           * @param menuConfig 
           * @returns 
           */
          function getIdSet(menuConfig){
              let ids = {};
              menuConfig.forEach((element) => {
                  const name = element.id;
                  ids = { ...ids, [name]: 0 };
          
                  if (element.children) {
                      const children = element.children;
                      children.forEach(el => {
                          const name1 = el.id;
                          ids = { ...ids, [name1]: 0 };
                      })
                  }
              });
          
              return ids;
          }
          
          //菜單的內部狀態的初始值,用react的reducer來管理, 用context來向子組件傳遞通信。
          const initState = {
              activeItemId: null, //當點擊一個菜單項時記錄活動菜單項
              hoverItemId: null, //當點擊一個菜單項組標題時,記錄打開的GroupMenu的名稱。
              open: true, //菜單項的展開模式,true為展開,false為折疊
              showDivider: true, //菜單項的分割線模式,true為顯示,false為不顯示
          }
          
          const reducer = (state, action) => {
              return {
                  ...state,
                  ...action
              }
          }
          
          export const SideMenuState = createContext(initState); //菜單的內部狀態
          export const SideMenuBadge = createContext(null); //菜單的徽章
          export const DispatchMenuState = createContext(null); //菜單的內部狀態的更新函數
          export const DispatchMenuBadge = createContext(null); //菜單的徽章的更新函數
          export const SideMenuData = createContext([]); //菜單的數據
          
          /**
           * 菜單的上下文Context
           * @param children 
           * @param menuData 
           * @returns 
           */
          function SideMenuProvider({ children, menuData }) {
              const [badge, updateBadge] = useState(getIdSet(menuData));
              const [menuState, updateMenuState] = useReducer(reducer, initState);
          
              const updateBadgeHandler = (id, count) => {
                  updateBadge((state) => {
                      return {
                          ...state,
                          [id]: count
                      }
                  })
              }
              return (
                  <SideMenuState.Provider value={ menuState }>
                      <SideMenuBadge.Provider value={badge}>
                          <DispatchMenuState.Provider value={updateMenuState}>
                              <DispatchMenuBadge.Provider value={updateBadgeHandler}>
                                  <SideMenuData.Provider value={menuData}>
                                      {
                                          children
                                      }
                                  </SideMenuData.Provider>
                              </DispatchMenuBadge.Provider>
                          </DispatchMenuState.Provider>
                      </SideMenuBadge.Provider>
                  </SideMenuState.Provider>
              )
          }
          
          export default SideMenuProvider;

          規定每個菜單項的id必須唯一,這個應該不難理解吧。
          getIdSet()函數的功能是根據配置菜單數據返回所有菜單項的ID集合,用于確定你單擊了哪一項菜單。
          initState是reducer的初始狀態。 其內部數據項在上面代碼的備注中我已經寫的很清楚了。
          狀態定義好了,那么Hook當然也要提供上,要不然有什么意義呢。

          定義_SMenuHooks.jsx文件

          import { useContext } from 'react';
          import { DispatchMenuBadge, DispatchMenuState, SideMenuBadge, SideMenuData, SideMenuState } from './SideMenuProvider'; 
          
          //獲取邊欄菜單的狀態
          export function useSideMenuState() {
              return useContext(SideMenuState);
          }
          
          //獲取邊欄菜單的小紅點狀態
          export function useSideMenuBadge() {
              return useContext(SideMenuBadge);
          }
          
          //更新邊欄菜單小紅點的工具,用法:
          // const update = useSideMenuBadgeUpdate();
          // update("menuItemId", 50)
          export function useSideMenuBadgeUpdate() {
              return useContext(DispatchMenuBadge);
          }
          
          //更新邊欄菜單工具
          export function useSideMenuStateUpdate() {
              return useContext(DispatchMenuState);
          }
          
          //獲取菜單配置項
          export function useSideMenuData() {
              return useContext(SideMenuData);
          }

          現在狀態有了,引用狀態的Hooks也有了,其它的就是如何定義組件了,是不是容易了許多。

          菜單頭的定義

          直接上代碼:_SideMenuHeader.jsx

          import Box from '@mui/system/Box';
          import Avatar from '@mui/material/Avatar';
          import Typography from '@mui/material/Typography';
          import Stack from '@mui/system/Stack';
          import { useSideMenuState } from './_SMenuHooks';
          
          //菜單頭
          const SideMenuHeader = ({
              logo, //圖標
              title, //標題
              onClick //單擊事件
          }) => {
              const { open } = useSideMenuState();
              const clickEvent = () => {
                  onClick && onClick();
              }
              return (
                  <Box
                      onClick={clickEvent}
                      className="p-3">
                      <Stack
                          spacing={2}
                          direction={"row"}
                          justifyContent="start"
                          alignItems={"center"}
                          className="w-100"
                      >
                          <Avatar
                              sx={{
                                  width: 35,
                                  height: 35,
                                  cursor: "pointer",
                                  transition: '0.2s',
                                  transform: open ? 'scale(1)' : 'scale(1.2)',
                              }}
                              src={logo}
                              variant="rounded"
                              alt={title}
                          >
                              {
                                  title && title.substring(0, 1).toUpperCase()
                              }
                          </Avatar>
          
                          <Typography className="text-truncate" variant="h5" sx={{pl: 0.5}} > {title} </Typography>
                      </Stack>
                  </Box>
              )
          };
          
          export default SideMenuHeader;

          菜單項

          _SideMenuItem.jsx

          import PropTypes from 'prop-types';
          import Tooltip from '@mui/material/Tooltip';
          import Badge from '@mui/material/Badge';
          import ListItemIcon from '@mui/material/ListItemIcon';
          import ListItemButton from '@mui/material/ListItemButton';
          import ListItemText from '@mui/material/ListItemText';
          import Avatar from '@mui/material/Avatar';
          import SvgIcon from '@mui/material/SvgIcon';
          import { useSideMenuBadge, useSideMenuState, useSideMenuStateUpdate } from './_SMenuHooks';
          
          /**
           * 主菜單項組件
           * @param title: 菜單項標題
           * @param id: 菜單項ID
           * @param icon: 菜單項圖標
           * @param onClick: 菜單項單擊事件 
           * @returns 
           */
          const SideMenuItem = ({
              title, 
              id,
              icon = null,
              onClick,
          }) => {
              const {activeItemId, open} = useSideMenuState();
              const badgeCount = useSideMenuBadge();
              const updateMenuState = useSideMenuStateUpdate();
          
              //單擊事件
              const itemClickeEvent = () => {
                  updateMenuState({ activeItemId: id });
                  onClick(id, title, [id], [title]);
              }
           
              return (
                  <ListItemButton
                      selected={ activeItemId == id }
                      onClick={itemClickeEvent}
                  >
                      <Tooltip title={open ? null : title} arrow placement="right">
                          <Badge badgeContent={badgeCount[id]} color="error">
                              <ListItemIcon
                                  sx={{
                                      '& svg': {
                                          transition: '0.2s',
                                          transform: open ? 'scale(1)' : 'scale(1.2)',
                                      },
          
                                      '&:hover, &:focus': {
                                          '& svg:first-of-type': {
                                              transform: open ? 'scale(1)' : 'scale(1.3)',
                                          }
                                      },
                                  }}>
                                  {
                                      icon == null ? 
                                          <Avatar
                                              sx={{
                                                  width: 30,
                                                  height: 30,
                                                  fontSize: 18,
                                                  transition: '0.2s',
                                                  transform: open ? 'scale(1)' : 'scale(1.2)'
                                              }}
                                              variant="rounded">
                                              {title.substring(0, 1).toUpperCase()}
                                          </Avatar> :
                                          <SvgIcon component={icon} />
                                  }
                              </ListItemIcon>
                          </Badge>
                      </Tooltip>
          
                      <ListItemText primary={title} />
                  </ListItemButton>
              );
          };
          export default SideMenuItem;

          子菜單項

          _SideMenuSubItem.jsx

          import ListItemButton from '@mui/material/ListItemButton';
          import ListItemIcon from '@mui/material/ListItemIcon';
          import ListItemText from '@mui/material/ListItemText';
          import Typography from '@mui/material/Typography';
          import Avatar from '@mui/material/Avatar';
          import Tooltip from '@mui/material/Tooltip';
          import Badge from '@mui/material/Badge';
          import SvgIcon from '@mui/material/SvgIcon';
          import CssBaseline from '@mui/material/CssBaseline';
          
          import { useSideMenuBadge, useSideMenuState, useSideMenuStateUpdate } from './_SMenuHooks';
          
          /**
           * 子菜單項組件
           * @param icon: 菜單項圖標
           * @param title: 菜單項標題
           * @param id: 菜單項ID
           * @param groupId: 菜單項組ID
           * @param groupTitle: 菜單項組標題
           * @param onClick: 菜單項單擊事件 
           * @returns 
           */
          function SideMenuSubItem({
              icon = null,
              title,
              id,
              groupId,
              groupTitle,
              onClick
          }) {
              const { activeItemId, open } = useSideMenuState();
              const updateMenuState = useSideMenuStateUpdate();
              const badgeCount = useSideMenuBadge();
          
              const handleClick = () => {
                  updateMenuState({ activeItemId: id });
                  onClick(id, title, [groupId, id], [groupTitle, title])
              };
          
              return (
                  <ListItemButton
                      onClick={handleClick}
                      selected={ activeItemId == id }
                      sx={{
                          transition: "padding 0.3s",
                          pl: open ? 5 : 2.5,
                      }}>
                      <CssBaseline />
                      <Tooltip title={open ? null : title} arrow placement="right">
                          <Badge badgeContent={badgeCount[id]} color="error">
                              <ListItemIcon
                                  sx={{
                                      '& svg': {
                                          transition: '0.2s',
                                          transform: open ? 'scale(1)' : 'scale(1.2)',
                                      },
          
                                      '&:hover, &:focus': {
                                          '& svg:first-of-type': {
                                              transform: open ? 'scale(1)' : 'scale(1.3)',
                                          }
                                      },
                                  }}>
                                  {
                                      icon == null ?
                                          <Avatar
                                              sx={{
                                                  width: 24,
                                                  height: 24,
                                                  fontSize: 16,
                                                  transition: '0.2s',
                                                  transform: open ? 'scale(1)' : 'scale(1.2)',
                                              }}
                                          variant="rounded"
                                          > {title.substring(0, 1).toUpperCase()} </Avatar> :
                                      <SvgIcon component={icon} sx={{ fontSize: 16 }} />
                                      
                                  }
                              </ListItemIcon>
                          </Badge>
                      </Tooltip>
                      <ListItemText
                          primary={
                              <Typography
                                  sx={{ display: 'inline' }}
                                  component="span"
                                  variant="body1"
                                  color="text.secondary"
                              >
                                  { title }
                              </Typography>
                          }
                      />
                  </ListItemButton>
              );
          }
          
          export default SideMenuSubItem;

          菜單組項

          _SideMenuGroup.jsx

          import React from 'react';
          import List from '@mui/material/List';
          import ListItemButton from '@mui/material/ListItemButton';
          import ListItemIcon from '@mui/material/ListItemIcon';
          import ListItemText from '@mui/material/ListItemText';
          import Collapse from '@mui/material/Collapse';
          import ExpandLess from '@mui/icons-material/ExpandLess';
          import ExpandMore from '@mui/icons-material/ExpandMore';
          import Avatar from '@mui/material/Avatar';
          import Badge from '@mui/material/Badge';
          import Tooltip from '@mui/material/Tooltip';
          import SvgIcon from '@mui/material/SvgIcon';
          
          import { useSideMenuState, useSideMenuStateUpdate, useSideMenuBadge } from './_SMenuHooks';
          import SMenuSubItem from './_SideMenuSubItem';
          
          /**
           * 含有子菜單的菜單項
           * @param props 
           * @returns 
           */
          function SideMenuGroup({
              id, //菜單項的ID名稱
              icon = null, //圖標
              title, //標題
              childrenData, //子菜單 
              onClick, //單擊事件
          }) {
              const { hoverItemId, open } = useSideMenuState();
              const updateMenuState = useSideMenuStateUpdate();
              const badgeCount = useSideMenuBadge();
              const handleClick = () => {
                  updateMenuState({hoverItemId: hoverItemId === id ? null : id})
              };
          
              return (
                  <React.Fragment>
                      <ListItemButton onClick={handleClick}>
                          <Tooltip title={open ? null : title} arrow placement="right">
                              <Badge badgeContent={badgeCount[id]} color="error">
                                  <ListItemIcon
                                      sx={{
                                          '& svg': {
                                              transition: '0.2s',
                                              transform: open ? 'scale(1)' : 'scale(1.2)',
                                          },
          
                                          '&:hover, &:focus': {
                                              '& svg:first-of-type': {
                                                  transform: open ? 'scale(1)' : 'scale(1.3)',
                                              }
                                          },
                                      }}>
                                      {
                                          icon == null ?
                                              <Avatar
                                                  sx={{
                                                      width: 30,
                                                      height: 30,
                                                      fontSize: 18,
                                                      transition: '0.2s',
                                                      transform: open ? 'scale(1)' : 'scale(1.2)'
                                                  }}
                                              variant="rounded"
                                              >
                                                  {title.substring(0, 1).toUpperCase()}
                                              </Avatar> :
                                              <SvgIcon component={icon} />
                                      }
                                  </ListItemIcon>
                              </Badge>
                          </Tooltip>
          
                          <ListItemText primary={title} />
                          {hoverItemId === id ? <ExpandLess /> : <ExpandMore />}
                      </ListItemButton>
                      <Collapse in={ hoverItemId === id } timeout="auto" unmountOnExit>
                          <List component="div" dense={true} disablePadding>
                              {
                                  childrenData === undefined ? null :
                                  childrenData.map(function (itemData, index) {
                                      return <SMenuSubItem
                                          icon = { itemData.icon }
                                          title = { itemData.title }
                                          id = {itemData.id}
                                          groupId = {id}
                                          groupTitle={title}
                                          onClick={onClick}
                                          key={index} />
                                  })
                              }
                          </List>
                      </Collapse>
                  </React.Fragment>
              );
          }
          
          export default SideMenuGroup;

          菜單收縮按鈕

          _SToggleButton.jsx

          import IconButton from '@mui/material/IconButton';
          import { useSideMenuState, useSideMenuStateUpdate } from './_SMenuHooks';
          
          /**
           * 菜單的展開/收起按鈕
           * @param {*} param0 
           * @returns 
           */
          function SToggleButton({icon}) {
              const menuState = useSideMenuState();
              const updateMenuState = useSideMenuStateUpdate();
              const clickHandler = () => {
                  updateMenuState({ open: !menuState.open})
              }
              return (
                  <IconButton onClick={clickHandler}>
                      { icon }
                  </IconButton>
              )
          }
          
          export default SToggleButton;

          一口氣所有組件就擼完了。也不是太難對不對。接下來就是組裝了。把上面的狀態及組件有機的組件起來就完美了。注意看我的手勢,我是有手勢的。

          菜單組件

          SideMenu.jsx

          import { ReactNode } from 'react';
          import Box from '@mui/system/Box';
          import SideMenuItem from './_SideMenuItem';
          import Divider from '@mui/material/Divider';
          import SideMenuGroup from './_SideMenuGroup';
          import { useSideMenuData, useSideMenuState } from './_SMenuHooks';
          import { List } from '@mui/material';
          import Paper from '@mui/material/Paper';
          
          /**
           * 菜單的主體組件
           * @returns 
           */
          function SideMenu({
              header,
              footer,
              onClick
          }) {
              const menuData = useSideMenuData();
              const { open } = useSideMenuState();
              const openWidth = 300;
              const minWidth = 65;
              return (
                  <Paper
                      className="d-flex overflow-hidden h-100"
                      elevation={1}
                      sx={{
                          transition: "width 0.3s",
                          width: open ? openWidth : minWidth,
                      }}
                  >        
                      <Box className='d-flex flex-column'>
                          {
                              header == null ?
                                  null : 
                                  <>
                                      { header }
                                      <Divider />
                                  </>
                          }
          
                          <Box sx={{ flex: 1, overflowY: "auto",  overflowX:"hidden", width: open ? openWidth : minWidth}}>
                              <List sx={{width: openWidth}}>                    
                                  { 
                                      menuData.map((item, index) => {
                                          const subItemsData = item.children || null;
                                          if (subItemsData == null) {
                                              return <SideMenuItem
                                                  id={item.id}
                                                  title={item.title}
                                                  icon={item.icon}
                                                  onClick={onClick}
                                                  key={index}
                                              />
                                          }
          
                                          return <SideMenuGroup
                                              icon={item.icon}
                                              id={item.id}
                                              title={item.title}
                                              childrenData={item.children}
                                              onClick={onClick}
                                              key={index} />
                                      })
                                  }
                              </List>
                          </Box>
          
                          {
                              footer == null ?
                                  null :
                                  <>
                                      <Divider />
                                      {footer}
                                  </>
                          }
                      </Box>
                  </Paper>
              );
          }
          
          export default SideMenu;

          好了,我們剛擼了一個相當棒的布局菜單。擼得我一手的油。怎么用呢,簡單:

          菜單項測試

          SideMenuTest.jsx

          import DataUsageIcon from '@mui/icons-material/DataUsage';
          import PersonIcon from '@mui/icons-material/Person';
          import GroupAddIcon from '@mui/icons-material/GroupAdd';
          import VerifiedUserIcon from '@mui/icons-material/VerifiedUser';
          import FeaturedVideoIcon from '@mui/icons-material/FeaturedVideo';
          import PasswordIcon from '@mui/icons-material/Password';
          import VpnKeyIcon from '@mui/icons-material/VpnKey';
          import HealthAndSafetyIcon from '@mui/icons-material/HealthAndSafety';
          import ReplyAllIcon from '@mui/icons-material/ReplyAll';
          import VerticalSplitIcon from '@mui/icons-material/VerticalSplit';
          import Box from '@mui/material/Box';
          import SideMenuHeader from "../framework-kakaer/SMenu/_SideMenuHeader";
          import SideMenu from "../framework-kakaer/SMenu/SideMenu";
          import SideMenuProvider from "../framework-kakaer/SMenu/SideMenuProvider";
          import SToggleButton from '../framework-kakaer/SMenu/_SToggleButton';
          
          //菜單的測試數據
          const sideMenuDataTest = [
              { id: "init", title: "系統初始化", icon: DataUsageIcon },
              { id: "management", title: "用戶管理", icon: GroupAddIcon },
          
              {
                  id: "userMsg", title: "角色管理", icon: PersonIcon, children: [
                      { id: "", title: "權限管理", icon: VerifiedUserIcon },
                      { id: "pwdMsg", title: "密碼管理", icon: PasswordIcon },
                      { id: "keyMsg", title: "私鑰管理", icon: VpnKeyIcon },
                      { id: "agentMsg", title: "權限管理", icon: HealthAndSafetyIcon },
                  ]
              },
          
              { id: "advMsg", title: "廣告管理", icon: FeaturedVideoIcon },
              { id: "plyMsg", title: "評論管理", icon: ReplyAllIcon },
          
              {
                  id: "title", title: "文章管理", icon: null, children: [
                      { id: "caogaoMsg", title: "草稿件", icon: null },
                      { id: "newFile", title: "新建文章", icon: null },
                      { id: "firstMsg", title: "置頂管理", icon: null },
                      { id: "recMsg", title: "推薦管理", icon: null },
                      { id: "classMsg", title: "類型管理", icon: null },
                      { id: "emailMsg", title: "郵箱管理", icon: null },
                  ]
              },
          
              { id: "system", title: "系統設置", icon: null },
              { id: "userCenter", title: "個人中心", icon: null }
          ];
          
          
          function SideMenuTest() {
              const onClickHandler = (id, title, idPath, titlePath) => {
                  console.log("ClickedItem => ", idPath);
              }
          
              return (
                  <SideMenuProvider menuData={sideMenuDataTest}>
                      <Box
                          className='d-flex overflow-hidden position-absolute w-100 h-100 p-0 m-0'
                          sx={{ top: 0, left: 0, bottom: 0, right: 0 }}>
                          <Box className='h-100'>
                              <SideMenu
                                  header={<SideMenuHeader title="側邊菜單測試系統" />}
                                  onClick={onClickHandler} />
                          </Box>
          
                          <Box className='d-flex overflow-hidden position-relative flex-grow-1'>
                              <Box className="d-flex flex-column overflow-auto p-0 m-0 position-relative flex-grow-1 flex-nowrap">
                                  <Box className="p-0 w-100 h-100">
                                      <SToggleButton icon={<VerticalSplitIcon />} />
                                  </Box>
                              </Box>
                          </Box>
                      </Box>
          
                  </SideMenuProvider>
              )
          }
          
          export default SideMenuTest;

          這下總會了吧。什么,還不會?不知道怎么進?我擦!!!我這都一件不剩了,你還不知道下一步:

          入口

          _SideMenuItem

          // import SideMenuProvider from "../kakaer/SMenu/SideMenuProvider";
          import SideMenuTest from "./SideMenuTest";
          
          function App() {
              return <SideMenuTest />
          }
          
          export default App;

          完美!!
          大家還可以加入一個暗模式功能,想想看,構思一下怎么實現,看下圖:這個就當是留給自己的作業吧。



          帶有暗模式的布局界面

          ascadea for Mac是Mac平臺上的一款開發編程工具。Cascadea Mac版可以輕松地安裝自定義樣式,從而改變您想要的任何網站的外觀和感覺。

          Cascadea Mac版軟件介紹

          介紹Cascadea,這是第一個設計為Safari應用程序擴展和本機macOS應用程序的自定義樣式管理器。Cascadea使安裝自定義樣式變得容易,該樣式可以更改您想要的任何網站的外觀。無論您是想讓社交媒體Feed充滿色彩,還是希望您的眼睛以深色風格來休息,Cascadea都可以讓您自由地用顏色繪制網絡。安裝樣式很容易-您可以輕松地從流行的自定義樣式網站導入樣式,或者從URL或本地文件導入任何CSS文件。安裝后,Cascadea將具有干凈,簡單的用戶界面,可快速切換或刪除樣式。由于Cascadea是用快速,流暢的本機UI構建的,因此可以很容易地批量切換或批量刪除樣式,將它們拖動以組織樣式列表,或者導出和導入整個樣式數據庫。無論您是編寫自己的自定義樣式還是將其用作Web開發工作流的一部分,Cascadea都是CSS開發人員的強大工具。Cascadea包括一個功能齊全的代碼編輯器,用于編寫自定義樣式表,并支持自動完成,語法突出顯示,自動縮進,代碼折疊,美化,多光標支持等。在編輯器的多個顏色主題之間進行選擇,在選項卡中打開多個樣式,并在保存更改時實時觀看Safari更新。另外,如果您更喜歡自己的代碼編輯器,則可以輕松地將標準CSS文件導出和導入Cascadea或從Cascadea導入。

          Cascadea for Mac下載功能介紹

          描繪你的世界

          Cascadea使您可以根據自己的喜好自定義任何網站的外觀。從流行的自定義樣式網站或任何CSS文件輕松導入現有樣式,或使用Cascadea強大的內置編輯器自行編寫。Cascadea使您能夠以自己的顏色繪畫網絡。

          風格和實質

          Cascadea包含功能強大的CSS編輯器,用于編寫或編輯自定義樣式。Cascadea具有語法高亮,自動完成,代碼折疊,美化以及支持在多個選項卡中打開樣式的功能,是編寫樣式表的一站式商店。

          專為macOS和Safari打造

          Cascadea是第一個利用Safari的現代App Extension框架從頭開始構建的,作為macOS本地應用程序的自定義樣式管理器。這使Cascadea能夠快速,高效地與Mac集成,這是以前沒有任何用戶風格的擴展。使用觸控欄瀏覽代碼,在帶有Safari的Split View中獲取樣式以進行實時編輯,并通過支持macOS Mojave的Dark Mode休息一下。

          Cascadea for Mac下載更多功能

          ?所有自定義樣式管理器中最快,最簡潔的UI。

          ?完全支持macOS Mojave中的暗模式。 ?將樣式與您的macOS(10.14.4+)系統外觀相關聯-可以在需要時以暗模式(Dark Mode)修飾網站,并在不需要時無縫更改主題。 ?自動更新從URL導入的樣式。

          ?輕松復制導入的樣式以編輯本地副本,而不會被更新覆蓋。 ?以UserCSS格式的自定義樣式自定義變量。 ?從樣式中排除網站,以防止沖突或覆蓋全局樣式。

          ?只需拖放樣式列表中的條目即可更改樣式的注入順序。 ?將整個樣式集導出到單個數據庫文件中,然后將其輕松導入。 ?快速打開Cascadea或通過單擊Safari工具欄中的按鈕來切換樣式。

          ?配備的MacBook Pro型號上的Touch Bar支持。 ?沒有用戶跟蹤。完全沒有 曾經 除了Apple通過App Store提供的可選匿名匿名崩潰報告之外,Cascadea絕對不會從您那里收集任何數據。

          發行說明

          固定:?修復了從Cascadea的菜單中切換“啟用樣式”復選框時性能/不穩定的問題Safari中的工具欄彈出窗口。?修復了導入UserCSS樣式時拆分部分的問題(又名“ SO Dark”修復)

          https://www.macdown.com/mac/7035.html


          主站蜘蛛池模板: 在线观看精品一区| 国精产品一区一区三区MBA下载| 一本大道在线无码一区| 多人伦精品一区二区三区视频| 精品免费国产一区二区| 成人午夜视频精品一区| 亚欧免费视频一区二区三区| 亚洲a∨无码一区二区| 美女AV一区二区三区| 日韩精品国产一区| 人妻激情偷乱视频一区二区三区| 国产午夜精品一区二区三区极品| 色一乱一伦一区一直爽| 久久久无码一区二区三区 | 精品国产免费一区二区三区| 亚洲人AV永久一区二区三区久久| 精品一区二区三区波多野结衣| 无码毛片一区二区三区中文字幕 | 国产成人久久精品一区二区三区| 国产福利一区二区在线视频 | 在线播放偷拍一区精品| eeuss鲁片一区二区三区| 亚洲啪啪综合AV一区| 国产一区二区三区亚洲综合| 老熟妇仑乱一区二区视頻| 精品深夜AV无码一区二区| 精品深夜AV无码一区二区老年| 无码人妻一区二区三区在线视频| 色婷婷AV一区二区三区浪潮| 免费精品一区二区三区第35| 精品人无码一区二区三区 | 无码人妻少妇色欲AV一区二区| 国产一区二区三区免费观在线| 日韩精品无码人妻一区二区三区 | 日本精品一区二区三区四区| 国产肥熟女视频一区二区三区| 国产一区风间由美在线观看| 国产一区二区电影在线观看| 久久毛片免费看一区二区三区| 中文字幕一区在线| 日韩国产精品无码一区二区三区 |