首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> JSP 程式設計 >> 關於JSP

JSP+JavaScript實現MSDN風格樹狀導航:懶加載與隱藏幂框架技巧

     編輯:關於JSP

經典的MSDN/CSDN左側樹狀導航,核心在於「按需加載子節點」與「無刷新展開收縮」。本文拆解一套基於JSP+JavaScript的完整實現,巧用隱藏<iframe>異步獲取子樹HTML,再注入主頁DOM——這是在AJAX普及前的經典模式,至今仍具參考價值。

架構設計

  • Tree.jsp:首屏渲染根節點,內嵌id="hiddenframe"隱藏幂
  • SubTree.jsp:接收PID(父節點ID)、PNode(父DOM ID),返回子節點HTML片段
  • JavaScript ExpandNode():控制展開/收縮,首次展開時通過hiddenframe.location.replace()請求SubTree.jsp,拿到HTML後注入對應<div>

Tree.jsp 關鍵代碼

<iframe width="100%" height="100" id="hiddenframe" style="display:none"></iframe>
<script>
function ExpandNode(ParentNode, ParentId) {
  var childDiv = document.getElementById(ParentNode.id + '_0');
  if (childDiv.style.display == 'none') {
    childDiv.style.display = 'block';
    if (childDiv.getAttribute('loaded') == 'no') {
      // 關鍵:通過隱藏iframe異步加載子樹
      document.frames['hiddenframe'].location.replace(
        "SubTree.jsp?PID=" + ParentId + "&PNode=" + ParentNode.id
      );
      childDiv.setAttribute('loaded', 'yes');
    }
  } else {
    childDiv.style.display = 'none';
  }
}
</script>

<%-- 根節點查詢:帶子節點計數 --%>
<% 
  Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
  ResultSet rs = DriverManager.getConnection(
    "jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=tree.mdb","",""
  ).createStatement().executeQuery(
    "SELECT *, (SELECT COUNT(*) FROM tree WHERE parentid = T.id) AS children FROM tree T WHERE parentid = 0"
  );
  int i = 0;
  while (rs.next()) {
    int children = rs.getInt("children");
    int id = rs.getInt("id");
%>
  <div id='Node_<%=i%>'>
    <a href='#' 
       <% if (children > 0) { %> onclick='ExpandNode(Node_<%=i%>,<%=id%>)'>+</a>
       <% } else { %>>-</a> <% } %>
    <a href='#' 
       <% if (children > 0) { %> ondblclick='ExpandNode(Node_<%=i%>,<%=id%>)' <% } %>
    ><%=rs.getString("remark")%></a>
  </div>
  <div id='Node_<%=i%>_0' style='display:none' loaded='no'>正在加載...</div>
<% i++; } %>

SubTree.jsp 關鍵代碼

<% 
  String parentNode = request.getParameter("PNode");
  int pid = Integer.parseInt(request.getParameter("PID"));
  // 計算縮進層級
  int level = parentNode.length() - parentNode.replace("_", "").length();
  String indent = "&nbsp;&nbsp;".repeat(level); // JDK 11+,舊版用循環拼接
  
  ResultSet rs = DriverManager.getConnection(...).createStatement().executeQuery(
    "SELECT *, (SELECT COUNT(*) FROM tree WHERE parentid = T.id) AS children FROM tree T WHERE parentid = " + pid
  );
  
  StringBuilder html = new StringBuilder();
  int i = 0;
  while (rs.next()) {
    int children = rs.getInt("children");
    int id = rs.getInt("id");
    String nodeId = parentNode + "_" + (i+1);
    
    html.append("<div id='").append(nodeId).append("'>")
        .append(indent).append("<a href='#' ");
    if (children > 0) html.append("onclick='ExpandNode(").append(nodeId).append(",").append(id).append(")'>+");
    else html.append(">-");
    html.append("</a><a href='#' ");
    if (children > 0) html.append("ondblclick='ExpandNode(").append(nodeId).append(",").append(id).append(")'");
    html.append(">").append(id).append(": ").append(rs.getString("remark")).append("</a></div>");
    
    if (children > 0) 
      html.append("<div id='").append(nodeId).append("_0' style='display:none' loaded='no'>")
          .append(indent).append("&nbsp;&nbsp;正在加載...</div>");
    i++;
  }
%>
<script>
  var container = eval('parent.' + '<%=parentNode%>_0');
  container.innerHTML = '<%=html.toString().replace("'", "\\'")%>';
</script>

現代化重構建議

  1. 替換隱藏幂為Fetch/AJAX:fetch('SubTree.jsp?...').then(r=>r.text()).then(html=>container.innerHTML=html)
  2. 後端改RESTful:返回JSON,前端用模板引擎(或原生template標籤)渲染,徹底分離
  3. Access→MySQL/PostgreSQL:棄用JDBC-ODBC橋接(Java 8已移除),改用原生驅動
  4. 樹組件化:封裝為Web Component(<tree-nav>),屬性傳遞數據源URL

結語

隱藏幂+DOM注入是Web 1.0時代的智慧結晶。理解其原理,有助於深刻體會AJAX、Fetch、WebSocket等現代技術解決的核心痛點——局部更新與異步交互。重構時,保留「懶加載、按需渲染」的核心體驗即可。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved