门户定制案例-双层功能树

运行效果

定制门户页菜单为双层功能树

图 0

实现方法

  • 定制企业门户应用,参考《门户定制
  • 在门户页 /entry/pcxapp/pcx/index.w 中,使用 @replace 重新定义菜单渲染方法 menuRender,左边用 a 显示一个个一级菜单,右边用 menus 组件显示一级菜单的子菜单
  • menuRender 的参数 props.menus 是当前用户的完整菜单

添加扩展点

桌面端门户的扩展点方法写在 /UI2/comp/portalConfig/components/portalConfig/portalConfig.config.pc.js 文件的 onConfigContextInit 方法中,如果没有 portalConfig.config.pc.js 文件,将 portalConfig.config.js 文件复制为 portalConfig.config.pc.js 文件

添加门户页 /entry/pcxapp/pcx/index.w 渲染功能树方法 menuRender 的 replace 扩展点,代码如下

    async onConfigContextInit(configContextProcessor) {
        //获取当前页面
        let _this = configContextProcessor.page;
        let portalConfig = {
            "config": {
                "/entry": {
                    "/pcxapp": {
                        "/pcx": {
                            "/index.w": {
                                //菜单渲染方法执行后定制
                                "menuRender": {
                                    "@replace": (props, defaultDom) => {                  
                                    }
                                }
                            }
                        }
                    }
                }
            }
        };
        merge(_this.configContext, portalConfig);
        ConfigContextProcessor.enhancePageAdvice(_this);
    }

获取当前用户菜单

    "@replace": (props, defaultDom) => {                  
        let { menus } = props;
        ...
    }

完整代码

/UI2/comp/portalConfig/components/portalConfig/portalConfig.config.pc.js 文件的完整代码如下


import { merge } from "lodash";
import ConfigContextProcessor from 'core/framework/ConfigContextProcessor';
import React from 'react';
import Icon, { LeftOutlined ,RightOutlined } from '@ant-design/icons';
import { Menu } from 'antd';
import "./layout.css";

export default {

    processConfigContext(configContext) {
    },

    async onConfigContextInit(configContextProcessor) {
        //获取当前页面
        let _this = configContextProcessor.page;
        let portalConfig = {
            "config": {
                "/entry": {
                    "/pcxapp": {
                        "/pcx": {
                            "/index.w": {
                                //菜单渲染方法执行后定制
                                "menuRender": {
                                    "@replace": (props, defaultDom) => {                  
                                        let { menus } = props;
                                        let mainMenu = [];
                                        //一级菜单点击事件
                                        let onMainMenuClick=(e,item)=>{
                                            //删除选择calss
                                            document.querySelectorAll(".definedMenu-mainMenu").forEach(item=>{                          
                                                let classVal= item.getAttribute("class").replace("selected","");
                                                item.setAttribute("class",classVal);
                                            })
                                            //新增选择class
                                            let _a=e.currentTarget;
                                            let className=_a.getAttribute("class")+" selected";
                                            _a.setAttribute("class",className);
                                            //设置子菜单数据
                                            _this.setState({childItemMenus:item.children})
                                        }
                                        //获取一级菜单信息                  
                                        menus.forEach(item => {
                                            //默认展示第一个一级菜单下子菜单内容                      
                                            if(!_this.state.childItemMenus){                          
                                                _this.state.childItemMenus=item.children;   
                                            }                     
                                            let menu =
                                                <a className={`definedMenu-mainMenu`} onClick={(e)=>{onMainMenuClick(e,item)}} title={item.title}>
                                                    <span className={"icon"}>{item.icon}</span>
                                                    <span className={"title"}>{item.title}</span>
                                                </a>
                                            mainMenu.push(menu);                     
                                        });  
                                        //设置第一个菜单为选中                
                                        let fitsrMenu=mainMenu?.[0];
                                        if(fitsrMenu){
                                            fitsrMenu.props.className+=" selected";
                                        }                  
                                        //转化数据为menu需要的数据格式
                                        let changeMenuData=(menuData)=>{
                                            menuData.map(item=>{
                                                item.label=item.title;   
                                                //控制菜单是否显示
                                                if(item.hidden!="all"){                            
                                                    delete item.hidden;
                                                }                       
                                            });
                                            menuData.forEach(item=>{
                                                if(item.children){
                                                    changeMenuData(item.children);
                                                }
                                            })
                                        }
                                        //转换数据为menu组件支持的数据格式
                                        changeMenuData(_this.state.childItemMenus);
                                        //过滤无效的菜单
                                        _this.state.childItemMenus=_this.state.childItemMenus.filter(item=>item.hidden!="all");
                                        //二级菜单点击事件
                                        let onChildMenuClick=({ item:{props}})=>{
                                            //调用原菜单单击事件
                                            _this.menuItemClick(props);
                                        }   
                                        //控制子菜单展开与隐藏
                                        const onClickOpenChildrenMenu=()=>{
                                            let {hideChildrenMenu=true}=_this.state;
                                            _this.setState({hideChildrenMenu:!hideChildrenMenu});
                                        }
                                        const showChildMenu=_this.state.hideChildrenMenu!==false;

                                        //建议在元素上新增key属性,用于判断当前元素是否已存在,需注意key的唯一性
                                        let hasChildren=_this.state.childItemMenus?.length>0;
                                        let defineMenu =
                                            <div className={`definedMenu ${hasChildren ? "normal" : "noChildren"} ${showChildMenu?"":"hideChildMenu"}`}>
                                                <div className={"definedMenu-icon"} onClick={onClickOpenChildrenMenu}>
                                                    <Icon component={showChildMenu?LeftOutlined:RightOutlined} />
                                                </div>
                                                <div className={"definedMenu-menuBox"}>
                                                    <div className={"definedMenu-mainMenuBox"}>{mainMenu}</div>
                                                    {hasChildren&&showChildMenu && (<>
                                                        <div className={"definedMenu-subMenuBox"}>                                                        
                                                            <Menu items={_this.state.childItemMenus} mode="inline" onClick={onChildMenuClick} style={{ width: 250 }} />
                                                        </div>
                                                    </>)}
                                                </div>
                                            </div>;
                                        return defineMenu;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        };
        merge(_this.configContext, portalConfig);
        ConfigContextProcessor.enhancePageAdvice(_this);
    }
}

对应的css样式请参考如下代码

.definedMenu {
    flex: 0 0 330px;
    position: relative;
}

.definedMenu.hideChildMenu{  
    flex: 0 0 80px;
}

.definedMenu.noChildren{
    flex: 0 0 75px;
}
.definedMenu.noChildren .definedMenu-icon{
    display: none;
}
.definedMenu-icon{
    position: absolute;
    top:100px;
    right:-15px;
    width: 30px;
    height: 30px;
    overflow: hidden;
    border:1px solid rgba(5, 5, 5, 0.06);
    border-radius: 20px;
    background-color: #fff;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color:#ccc;
}
.definedMenu-icon:hover{
    color:#333;
}

.definedMenu * {
    box-sizing: border-box;
}

.definedMenu [hidden] {
    display: none;
}

.definedMenu-mainMenu {
    display: flex;
    align-items: center;
    flex-direction: column;
    margin: 5px;
    padding: 5px 0px;
    color: #ffffffa6;
}

.definedMenu-mainMenu:hover {
    color: #fff;
}

.definedMenu-mainMenu .icon {
    padding: 8px 0px;
    font-size: 16px;  
    width: 16px;
    color: #fff;
    fill: #ffffffa6;
    stroke: #ffffffa6;
}

.definedMenu-mainMenu.selected {
    border-radius: 5px;
    color: var(--ant-color-primary);   
}

.definedMenu-mainMenu.selected .icon{
    color: var(--ant-color-primary);
    fill: var(--ant-color-primary);
    stroke: var(--ant-color-primary);
}

.definedMenu-mainMenu .title {
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
    width: 100%;
    text-align: center;
    padding: 0px 3px;
}

.definedMenu-menuBox {
    position: fixed;
    inset-block-start: 56px;
    display: flex;
    height: calc(100% - 56px);
}

.definedMenu-mainMenuBox {
    width: 80px;
    height: 100%;
    border-right: 1px solid #e5e5e5;
    background-color: #001529;
    overflow-y: auto;
}

.definedMenu-subMenuBox {
    flex: 1;
    height: 100%;
    border-inline-end: 1px solid rgba(5, 5, 5, 0.06);
    overflow: auto;
    position: relative;
}

.definedMenu-subMenuBox .iconAction {
    position: absolute;
    font-size: 22px;
    z-index: 100;
    right: -11px;
    top: 13px;
    cursor: pointer;
}

results matching ""

    No results matching ""