根据sitemap配置生成无限级跨frame菜单的实现方式(含100%脚本源码参考

用 C# 和 .NET 10 手搓一个内网穿透(附极简示例 + 可试用客户端) 最近在折腾内网穿透,用 C# 写了一套小东西,服务端跑在一台公网小机器上,客户端一行命令就能把家里的 3389、8080 之类的端口暴露到公网。整个过程基于 .NET 10,代码量不大,原理也简单,写篇博文记录一下。 阅读详情
在E8.Net平台中已经包含了根据Sitemap生成outlook风格菜单的全部源代码. 不过还有一些客户提出另一种下拉菜单的样式需求. 于是在E8.Net 上扩展了一种新的菜单实现模式.

如图例:

 

此菜单跟之前提供的outlook菜单一样来自于sitemap设置

由于菜单是放在FrameSet中的一个frame上,因此弹出的子菜单不能用DIV的方式来实现,而是采用window.createpopup()的方式弹出一个窗口,并且在窗口中输出HTML来实现菜单内容的展现和行为.

采用此方法用到的基本知识点:

       弹出窗口:

           var oPopup= window.createPopup();

           oPopup.innerHTML = "";

           oPopup.document.write(sHTML);   //写入输出内容

           oPopup.show(left,top,width,height,document.body);

      隐藏窗口:

          oPopup.hide();

     

采用createpopup的方式来实现无限级别的弹出菜单需要注意以下细节和设计技巧:

   1. 一个window同时只能弹出一个窗口,弹出另一个窗口的时候之前的窗口会自动关闭.

          解决思路: E8.Net中菜单输出的脚本为一个类文件,类中设置了一个数组对象,保存每一级窗口创建的createpopup,用数组方式保存,在不同级别的弹出时用到对应窗口位置的弹出对象.

               oPopup=E8MenuConfig.WindowsList[deep];   //deep为深度
                if(null==oPopup)
                { 
                    oPopup=obj.document.parentWindow.window.createPopup();                    
                } 

          这样可以保证每一级菜单弹出窗口不受影响

   2.如何计算弹出窗口的位置,会遇到上级菜单已经靠近屏幕的情况.

         解决思路:由于弹出窗口的位置是相对位置,需要考虑到相对屏幕有效位置的计算参考,把最上一级相对屏幕宽度(screen.availWidth)的计算结果带入到递归调用中去,无论哪一级的菜单均可比较到屏幕相对宽度(screen.availWidth)

            if(deep > 1)
                {
                    left += obj.offsetWidth - 3;
                   
                //如果到了屏幕的右边,则从左边开始
                    if(topLeft + width * 2 > screen.availWidth)
                    {
                        left = left - obj.offsetWidth - width + 3;
                    }
                }

   3.如何设计无限级菜单的数据源已保证递归调用的可行性.

          解决思路:菜单采用2维数组作为数据源,由于不知道可能会产生的层次数量,需要采用递归调用中根据一个参数不同执行相同的代码能找到当前弹出窗口内容.

              数组参考:

                 arrOperateMenu: MenuCode, SupMenuCode, MenuName, MenuUrl, Level, HasChild

              menuCode 和SupMenuCode 为父子关系链接,弹出窗口函数 以SupMenucode为入口,下一级以MenuCode参数为入口,保证到循环的可行性

< script type = " text/javascript "  src = " E8Netmenu.js " >
</ script >< script language = " javascript " >
var arrOperateMenu 
=   new  Array();
.
arrOperateMenu[
17 =   new  Array( " 50202 " " 502 " " 常用类别管理 " " /NewITSM/Forms/frmCatalogMng.htm " 2 false );
arrOperateMenu[
18 =   new  Array( " 50203 " " 502 " " 服务单位管理 " " /NewITSM/AppForms/frmBr_MastCustomerMain.aspx " 2 false );
arrOperateMenu[
19 =   new  Array( " 50204 " " 502 " " 供应商管理 " " /NewITSM/Provide/frmPro_ProvideManageMain.aspx " 2 false );
arrOperateMenu[
20 =   new  Array( " 50205 " " 502 " " 桌面项管理 " " /NewITSM/mydestop/frmEa_DefineMainPageMain.aspx " 2 false );
arrOperateMenu[
21 =   new  Array( " 50206 " " 502 " " 通用表单配置 " " /NewITSM/AppForms/frmappfieldconfig.aspx " 2 false );
arrOperateMenu[
22 =   new  Array( " 50207 " " 502 " " 所有管理流程 " " /NewITSM/Forms/form_all_flowmodel.aspx " 2 false );
arrOperateMenu[
23 =   new  Array( " 50208 " " 502 " " 常用流程配置 " " /NewITSM/Forms/form_flowmodel_set.aspx " 2 false );
arrOperateMenu[
24 =   new  Array( " 502 " " 5 " " 基础资料 " "" 1 true );
arrOperateMenu[
25 =   new  Array( " 503 " " 5 " " 客户管理 " " /NewITSM/AppForms/frmBr_ECustomerMain.aspx " 1 false );
arrOperateMenu[
26 =   new  Array( " 504 " " 5 " " 资产管理 " " /NewITSM/EquipmentManager/frmEqu_Main.htm " 1 false );
arrOperateMenu[
27 =   new  Array( " 505 " " 5 " " 资产配置项管理 " " /NewITSM/EquipmentManager/frmEqu_SchemaItemsMain.aspx " 1 false );
arrOperateMenu[
28 =   new  Array( " 506 " " 5 " " 资产类别管理 " " /NewITSM/EquipmentManager/frmSubject.htm " 1 false );

E8MenuConfig.Items 
=  arrOperateMenu; </ script >

        创建数组的脚本为后台代码根据sitemap内容和权限管理输出的

 

   4.设计弹出窗口的自动隐藏逻辑,保证用户的使用便利性.

      解决思路:  弹出窗口输出的HTML中加入一段自动隐藏的代码.

             

  strTemp  +=   " <script>var blnSubShow = false; " ;
                        strTemp 
+=   " function HidPopup(){if(blnSubShow==false){if(parent.blnSubShow!=null) parent.blnSubShow=false;if( "   +  parentTreeNode  +   " .E8MenuConfig.WindowsList[ "   +  deep  +   " ]!=null) "   +  parentTreeNode  +   " .E8MenuConfig.WindowsList[ "   +  deep  +   " ].hide();}} " ;
                        strTemp 
+=   " </script> " ;
                       strTemp 
+=   " <body leftmargin=/ " 0 / "  topmargin=/ " 0 / "  scroll=/ " no/ "  style=/ " border:solid menu 0pxpx;/ "   onmouseover=/ " clearTimeout(parent.popt); if (parent.blnSubShow != null ) parent.blnSubShow = true ;/ "  onmouseout=/ " parent.popt = setTimeout( ' HidPopup() ' , 10 );/ "  >/n " ;

      此代码中使用到一些技巧, 当有下一级菜单弹出时, blnSubShow = true, 则自动执行的代码中不会隐藏窗口,一旦下级菜单隐藏后,上级菜单的 blnSubShow 为true,自动执行的代码会隐藏当前窗口.

 

  5. siteMap内容如何与脚本文件结合

       为了保证与OUTLOOK风格菜单的兼容性( 登陆时可以选择), E8.Net中做了特殊的处理方式.根据SiteMap内容,权限及是否超级管理员专门做了后台代码进行输出,主要内容是一级菜单的HTML脚本和生成数组的脚本.

      (非E8.Net用户使用这个E8NetMenu.js的时候可以根据数组格式自行开发相应代码和一级菜单的HTML脚本)

 

  6. 其它注意事项不一一描述,此代码经过将近3天及加班的调试和完善,全部的脚本文件E8NetMenu.js 文件内容如下,供大家参考

     

if ( null == window.random)
{
    
if ( null == window.fe005e9f_e51b_4307_88ff_b4b150368fd4)
    {
        window.fe005e9f_e51b_4307_88ff_b4b150368fd4
= 0 ;
    }
    window.random
= function()
    {
        var s
= " RID " ;
        var d
= new  Date();
        s
+= d.getYear();
        s
+= d.getMonth();
        s
+= d.getDate();
        s
+= d.getHours();
        s
+= d.getMinutes();
        s
+= d.getSeconds();
        s
+= d.getMilliseconds();
        s
+= parseInt(Math.random() * 1000000000000 );
        s
+= (window.fe005e9f_e51b_4307_88ff_b4b150368fd4 ++ );
        
return  s;
    }
}
if ( null == window.absoluteLocation)
{
    window.absoluteLocation
= function(element, offset) 
    { var c 
=   0 while  (element) {  c  +=  element[offset];  element  =  element.offsetParent; }  return  c; 
    } 
}

if ( null == window.$)
{
    window.$
= function() 
    {
      var elements 
=   new  Array();
      
for  (var i  =   0 ; i  <  arguments.length; i ++
      {
        var element 
=  arguments[i];
        
if  ( typeof  element  ==   ' string ' )
          element 
=  document.getElementById(element);
        
if  (arguments.length  ==   1 )
          
return  element;
        elements.push(element);
      }
      
return  elements;
    }
}
if ( null == window.E8MenuConfig)
{
    window.E8MenuConfig
= function()
    {
        
this .id = random();        
    }
    window.FrameMenu
= new  E8MenuConfig(); // create a new instance
    E8MenuConfig.Items = new  Array();
    E8MenuConfig.WindowsList
= new  Array();
    E8MenuConfig.TopWindow
= window.createPopup();
    
    
    E8MenuConfig.ShowSubMenu
= function(MenuId,obj,img,deep,topLeft)
    {
     
            var strTemp 
=   "" ;
            var MenuUrl;
            var blnHasAdd 
=   false ;
            var topL 
=  topLeft;

            var LineCount 
=   0 // 菜单行数
            var MaxCharCount  =   0 // 每行字数

            
if (obj != selectObj  &&  deep  ==   1 )
            {
            
// 第一层改变背景
                obj.background = " images/ " + img;
            }

            var parentTreeNode
= " parent " ;
            
for (var i = 0 ;i < (deep - 1 );i ++ )
            {
                parentTreeNode
+= " .parent " ;

            }
            var left 
=  absoluteLocation(obj, ' offsetLeft ' );  
            var top 
=   absoluteLocation(obj, ' offsetTop ' );
            
if (deep <= 1 )
            {
               
                
if ((obj == document || obj == document.body ) && event != null )
                {
                    left
= event .x;
                    top
= event .y;
                }
                
else
                {
                    top
+=   obj.offsetHeight  -   4 ;;
                }
                oPopup
= E8MenuConfig.WindowsList[deep];    
                
if ( null == oPopup)
                {    
                    oPopup 
=  window.createPopup();
                    
                }    
                topL 
=  left;   // 记录最上层的left         
            }
            
else
            {
                oPopup
=  E8MenuConfig.WindowsList[deep];
                
if ( null == oPopup)
                {
                    oPopup
= obj.document.parentWindow.window.createPopup();
                }
            }    
            E8MenuConfig.WindowsList[deep]
= oPopup;
            E8MenuConfig.hideAllWindows(deep); 
// 关闭后面的窗口

            
for  (var i  =   0 ; i  <  E8MenuConfig.Items.length; i ++ )
            {
                
if  (E8MenuConfig.Items[i][ 1 ==  MenuId)
                {
                    MenuUrl 
=  E8MenuConfig.Items[i][ 3 ];
                    
if (blnHasAdd  ==   false )
                    {
                        strTemp 
+=   " <script>var blnSubShow = false; " ;
                        strTemp 
+=   " function HidPopup(){if(blnSubShow==false){if(parent.blnSubShow!=null) parent.blnSubShow=false;if( "   +  parentTreeNode  +   " .E8MenuConfig.WindowsList[ "   +  deep  +   " ]!=null) "   +  parentTreeNode  +   " .E8MenuConfig.WindowsList[ "   +  deep  +   " ].hide();}} " ;
                        strTemp 
+=   " </script> " ;
                       strTemp 
+=   " <body leftmargin=/ " 0 / "  topmargin=/ " 0 / "  scroll=/ " no/ "  style=/ " border:solid menu 0pxpx;/ "   onmouseover=/ " clearTimeout(parent.popt); if (parent.blnSubShow != null ) parent.blnSubShow = true ;/ "  onmouseout=/ " parent.popt = setTimeout( ' HidPopup() ' , 10 );/ "  >/n " ;
                       strTemp 
+=   " <table width=/ " 100 % / "  height=/ " 100 % / "  style=/ " border - collapse:collapse;/ " >/n " ;
                    }
                    blnHasAdd 
=   true ;
                    LineCount
++ ;
                    
if  (E8MenuConfig.Items[i][ 2 ].length  >  MaxCharCount) MaxCharCount  =  E8MenuConfig.Items[i][ 2 ].length;
                    
if  (E8MenuConfig.Items[i][ 5 ])  // 有下级菜单
                    {
                       strTemp 
+=   " <tr><td bgcolor=/ " #C2D2E5/ "   style=/ " border - top:#cccccc 1px solid;border - bottom:# 666666  1px solid;border - left:#cccccc 1px solid;border - right:# 666666  1px solid;mouse:hand; font - size:12px; color:# 000000 ;text - align:left;vertical - align:center;CURSOR:hand/ "  onmouseover=/ " this .bgColor = ' #dfdfdf ' ; "  + parentTreeNode +  " .E8MenuConfig.ShowSubMenu( ' " + E8MenuConfig.Items[i][0] + " ' , this , '' , "  + (deep+1) + " , "  + topL +  " );/ "   onmouseout=/ " this .blnSubShow = false ; this .bgColor = ' #C2D2E5 ' ;/ "  height=/ " 20 / "  onclick=/ ""  + parentTreeNode +  " .E8MenuConfig.GoToUrl( ' " + MenuUrl + " ' );/ " > "   +  E8MenuConfig.Items[i][ 2 ]   +   " &gt;&gt;</td></tr> " ;
                       MaxCharCount 
+=   2 ;    // 多了 两个 >符号
                    }
                    
else
                    {
                       strTemp 
+=   " <tr><td bgcolor=/ " #C2D2E5/ "  style=/ " border - top:#cccccc 1px solid;border - bottom:# 666666  1px solid;border - left:#cccccc 1px solid;border - right:# 666666  1px solid;mouse:hand; font - size:12px; color:# 000000 ;text - align:left;vertical - align:center;CURSOR:hand/ "  onmouseover=/ " this .bgColor = ' #dfdfdf ' ;/ "  onmouseout=/ " this .blnSubShow = false ; this .bgColor = ' #C2D2E5 ' ;/ "  height=/ " 20 / "  onclick=/ ""  + parentTreeNode +  " .E8MenuConfig.GoToUrl( ' " + MenuUrl + " ' );/ " > "   +  E8MenuConfig.Items[i][ 2 +   " </td></tr> " ;
                    }
                }

            }

            
if (blnHasAdd  ==   true )
            {
                strTemp 
+=   " </table>/n " ;
                strTemp 
+=   " </body>/n " ;
            }

            oPopup.document.body.innerHTML
= "" ;
            
if  (strTemp.length  >   0 )
                oPopup.document.write(strTemp);

            
// 显示子菜单
             if  (strTemp.length  >   0 )
            {
                var LineHeight 
=   20 // 行高
                
// 定义打开的oPopup的宽度,高度
                var width  =  (MaxCharCount  +   1 *   12 ;    // 一般为中文

                
if  (width  <   90 ) width  =   90 ;
                
// 如果是2层或以上,初始位置
               
                
if (deep  >   1 )
                {
                    left 
+=  obj.offsetWidth  -   3 ;
                    
                
// 如果到了屏幕的右边,则从左边开始
                     if (topLeft  +  width  *   2   >  screen.availWidth)
                    {
                        left 
=  left  -  obj.offsetWidth  -  width  +   3 ;
                    }
                }

                var height 
=  LineCount  *  LineHeight; 
                oPopup.show(left,top, width, height, document.body); 
            }

    }
    
    E8MenuConfig.hideAllWindows
= function(deep)
    {
        
for (var n = deep; null != E8MenuConfig.WindowsList  &&  n < E8MenuConfig.WindowsList.length;n ++ )
        {
            
if ( null != E8MenuConfig.WindowsList[n]  &&   null != E8MenuConfig.WindowsList[n].hide)
            {
                E8MenuConfig.WindowsList[n].hide();
            }
        }
    }
    
    E8MenuConfig.GoToUrl
= function(url)
    {
        E8MenuConfig.hideAllWindows(
0 );
        
if (url  !=   "" )
           window.top.MainFrame.location
= url;
    }
    
}

       

 

采用createpopup实现无限级别的弹出菜单的技术遗憾.

    由于IE缺省安全设置中禁用了 "允许由脚本初始化窗口,不受大小位置的限制",如果遇到三级以上菜单时可能会出现窗口位置不受控制的情况. 需要打开此设置.

为产品推广应用增加了一些阻力.

 

    在这里感谢E8.Net合作伙伴的朋友提供的参考资料和建议.

 

    E8.Net 工作流平台提供了此功能全部的源代码,用户可以直接使用或参考,并在此基础上更加的完善。欢迎E8.Net工作流平台的老客户索取相关技术及全部代码

 

   E8.Net工作流架构大量节约用户的开发成本为企业应用开发提供起点,提升软件生产力,欢迎访问:http://www.feifanit.com.cn/productFlow.htm

E8.Net工作流平台 提升企业战略执行力
ITIL与ITSM QQ4号群:1260249
.NET企业应用开发与工作流QQ 4号群:41553575

http://www.feifanit.com.cn/

sitemap 生成工具 生成 sitemap 生成工具 生成器 自动生成 可以生成5000条以上比一般的要强大 立即下载

相关推荐

ASTM D4583-21(2025).pdf

ASTM D4583-21(2025)

Sitemap在线生成器,网站地图在线生成工具

Sitemap是一个网站的全部URL列表,应该自动不定期更新这个列表,以使得使用sitemap的第三方搜索引擎、订阅软件可以即时发现你网站中的新的URL。 Sitemap是SEO中的首要任务,网站站长应向搜索引擎定期提交更新的URL列表,这就是网站地图(Sitemap),以让搜索引擎可以全面获得网站的网址信息和即时更新信息。 因此sitemap对于一个网...

每天都有新发现 6977

根据sitemap配置生成无限级frame菜单实现方式(100%脚本源码参考)

        在E8.Net平台中已经包根据Sitemap生成outlook风格菜单的全部源代码. 不过还有一些客户提出另一种下拉菜单的样式需求. 于是在E8.Net 上扩展了一种新的菜单实现模式. 如图例:   此菜单跟之前提供的outlook菜单一样来自于sitemap设置 由于菜单是放在FrameSet中的一个frame上,因此弹出的子菜单不能用DIV的方式实现,而是采...

weixin_33827590的博客 101

开启所有activex等Internet选项的批处理bat

方法(1) REM 添加信任站点ip reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges\Range10" /v ":Range" /t REG_SZ /d 222.222.222.222 /f reg add "HKCU\Software\Microsoft\W

2844

.NET新特性·第17篇】EF Core 10 与 Aspire 13.1

EFCore 10 引入复杂类型JSON映射、命名查询过滤器、批量操作增强等特性,提升数据访问效率与灵活性;Aspire 13.1深化Azure/AWS集成,支持Redis作为LLM缓存,Dashboard可观测性升级,助力云原生与AI应用开发。

hanzhixintianxia的博客 247

微软技术日报 2026-09-10:Project Zenith 开发者设备亮相,.NET 11 RC1 可投产

今天的微软把重心放在「开发者的一公里」:设备端(Project Zenith)、运行时(.NET 11 RC1)、模型层(Copilot 多模型矩阵)三层同时发力,开发者环境从"自己搭"走向"买来就能写"。参考来源:微软官方博客(Project Zenith)、.NET 官方发布说明、TechRepublic、腾讯新闻科技频道、第一财经、IT之家。本文由 AI 辅助整理,仅覆盖技术动态,不财务信息。

海盗Sharp的博客 445

基于.NET的Windows窗体编程之WinForms自定义控件(1)

本文介绍在.NET WinForms开发中如何创建自定义控件,重点讲解用户控件(UserControl)的实现。通过封装一个可清除文本框(ClearableTextBox),演示了属性公开、事件转发与逻辑封装的完整流程。该控件包标题、输入框和清除按钮,支持外部访问属性与事件响应,实现复用性与维护性提升。示例展示了控件在窗体中的应用及联动逻辑,适用于复杂界面组件的模块化设计,为后续扩展控件与自定义控件学习奠定基础。

绳锯木断,水滴石穿,专心写文,无问西东!!! 412

.NET 9.0 项目升级到 .NET 10.0

关于.NET项目升级到.NET10的步骤,包括改目标框架、重新生成、升级NuGet包、处理版本冲突等。 本文介绍.NET项目升级至.NET10.0的完整流程:修改目标框架、重新生成、升级NuGet包,并处理包版本依赖冲突问题。提供详细操作指南与参考文章,帮助开发者顺利完成升级。

csdn_aspnet的专栏,请点击博客主页右上角三个点中的私信联系 428

找不到指定的SDK(“Microsoft.NET.Sdk.Web“)

应对既将开始的U9客开始的工作,重新安装主机的操作系统,配套了U9的demo环境。不小心装成了x86 32位的系统,带来2个问题。1、网卡驱动有问题。2、VS在创建新项目时,竟然出现标题所示的错误提示,项目也不能正常创建成功。如果 PATH 中 x86 路径排在前面,系统会调用 x86 版本的 dotnet.exe,而该目录下可能没有 SDK,就会报找不到 SDK。如果 PATH 中 x86 路径排在前面,系统会调用 x86 版本的 dotnet.exe,而该目录下可能没有 SDK,就会报找不到 SDK。

yujunl的专栏 175

Newtonsoft.Json (Json.NET) 常用方法汇总

本文系统总结了Newtonsoft.Json(Json.NET)核心用法:通过JsonConvert实现实体与JSON字符串互转,支持格式化、空值忽略等配置;利用JObject/JArray进行动态解析与操作,支持嵌套读取、增删改查及紧凑输出;结合特性如[JsonProperty]定制序列化字段;重点提醒常见坑点,如列表转对象需用JArray.FromObject、安全读取避免空引用,并提供快速对照表,助力高效处理接口数据。

温故而知新,可以为师矣。 227

Spread .NET V19.1新特性

Spread.NET V19.1 正式发布,全面升级 Spread for Windows Forms 与 WPF 版本。新特性涵盖 PivotTable 样式优化、字段分组对话框、焦点高亮、.NET 10 与 Visual Studio 2026 支持,WinForms 增强数据粘贴与层级滚动,WPF 新增拖拽填充与数据可视化函数,显著提升数据处理效率与用户体验。立即下载体验。

葡萄城技术团队博客 229

.NET 报表控件选型对比:Stimulsoft 与 FastReport 怎么选

.NET 报表控件选型怎么落地?以 Stimulsoft 与 FastReport 两款主流引擎为案例,本文不评优劣,只做场景分流:用 5 个自测问题加一张 2026 年官方能力对照表,把「实时大屏 / AI 集成」与「打印归档 / 合规发票 / 开源起步」两类需求分别对号入座,并附自研、Power BI、RDLC 三个参照系的边界说明。

励志做最业余的专业博主,控件产品可以私我~ 166

基于 C# / .NET 8 + Windows Forms + SQLite 的桌面银行业务演示系统——华夏示范银行管理系统

华夏示范银行管理系统是一款基于C#/.NET8+WindowsForms+SQLite的桌面端业务演示系统,采用分层架构设计,支持超级管理员、管理员与客户三类角色。系统集成登录认证、顶部导航、客户/产品管理、持仓价值计算、操作日志双写(SQLite+文本)、空闲自动登出及数据导出功能。通过“内容控件+按钮栏”组合模式实现页面动态扩展,支持自定义页配置与灵活功能开关,具备高可维护性与可拓展性,适用于银行业务流程教学与原型验证。

weixin_66547608的博客 195

.NET 8 升级至 .NET 10 而不破坏 API 的契约

.NET 8升级至.NET 10需视作一次关键的API契约迁移,而非简单修改项目文件。鉴于.NET 8/9将于2026年11月停止支持,而.NET 10为当前LTS版本,升级势在必行。应先盘点所有项目、SDK版本、依赖项与CI配置,确保环境清晰。通过独立分步迁移(目标框架、NuGet包、运行时基础设施),并以契约测试保障核心行为不变——如状态码、内容类型、关键JSON字段等,避免因序列化细节变化导致误报。使用WebApplicationFactory和Microsoft.AspNetCore.Mvc.Te

204

GcExcel 服务端 Excel 组件:无需安装 Office 的 Java/.NET 报表方案

服务端生成 Excel 一定要装 Office 吗?GcExcel 给出了另一种答案:不依赖 Microsoft Office 即可完成工作簿创建、公式计算与多格式导出;支持 Excel 模板 + 数据源绑定,把版式调整从代码里剥离。本文完整 Java 示例代码,并列出选型前值得实测的 6 个验证维度。

励志做最业余的专业博主,控件产品可以私我~ 155
上一篇: 控件包含代码块(即 ),因此无法修改控件集合解决方法!
下一篇: 技术高速发展的今天中国软件企业将面临的困惑和选择
spring888
博客等级 码龄21年 1粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值