Bootstrap 5 - 侧边栏导航
2023年11月13日 2024年2月13日
Offcanvas
说明
因为笔记本很多, 侧边导航栏需要支持折叠
是否可以不固定, 有待观察
侧边栏样式
添加到头部
1<head> 2 <!-- 其他逻辑 --> 3 <style>body{min-height:100vh;min-height:-webkit-fill-available}html{height:-webkit-fill-available}main{display:flex;flex-wrap:nowrap;height:100vh;height:-webkit-fill-available;max-height:100vh;overflow-x:auto;overflow-y:hidden}.b-example-divider{flex-shrink:0;width:1.5rem;height:100vh;background-color:rgba(0,0,0,.1);border:solid rgba(0,0,0,.15);border-width:1px 0;box-shadow:inset 0 .5em 1.5em rgba(0,0,0,.1),inset 0 .125em .5em rgba(0,0,0,.15)}.bi{vertical-align:-.125em;pointer-events:none;fill:currentColor}.dropdown-toggle{outline:0}.nav-flush .nav-link{border-radius:0}.btn-toggle{display:inline-flex;align-items:center;padding:.25rem .5rem;font-weight:600;color:rgba(0,0,0,.65);background-color:transparent;border:0}.btn-toggle:hover,.btn-toggle:focus{color:rgba(0,0,0,.85);background-color:#d2f4ea}.btn-toggle::before{width:1.25em;line-height:0;content:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e");transition:transform .35s ease;transform-origin:.5em 50%}.btn-toggle[aria-expanded="true"]{color:rgba(0,0,0,.85)}.btn-toggle[aria-expanded="true"]::before{transform:rotate(90deg)}.btn-toggle-nav a{display:inline-flex;padding:.1875rem .5rem;margin-top:.125rem;margin-left:1.25rem;text-decoration:none}.btn-toggle-nav a:hover,.btn-toggle-nav a:focus{background-color:#d2f4ea}.scrollarea{overflow-y:auto}.fw-semibold{font-weight:600}.lh-tight{line-height:1.25}.bd-placeholder-img{font-size:1.125rem;text-anchor:middle;-webkit-user-select:none;-moz-user-select:none;user-select:none}@media (min-width:768px){.bd-placeholder-img-lg{font-size:3.5rem}}</style> 4</head>
图片信息
1<body> 2 <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> 3 <symbol id="grid" viewBox="0 0 16 16"> 4 <path d="M1 2.5A1.5 1.5 0 0 1 2.5 1h3A1.5 1.5 0 0 1 7 2.5v3A1.5 1.5 0 0 1 5.5 7h-3A1.5 1.5 0 0 1 1 5.5v-3zM2.5 2a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zm6.5.5A1.5 1.5 0 0 1 10.5 1h3A1.5 1.5 0 0 1 15 2.5v3A1.5 1.5 0 0 1 13.5 7h-3A1.5 1.5 0 0 1 9 5.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zM1 10.5A1.5 1.5 0 0 1 2.5 9h3A1.5 1.5 0 0 1 7 10.5v3A1.5 1.5 0 0 1 5.5 15h-3A1.5 1.5 0 0 1 1 13.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3zm6.5.5A1.5 1.5 0 0 1 10.5 9h3a1.5 1.5 0 0 1 1.5 1.5v3a1.5 1.5 0 0 1-1.5 1.5h-3A1.5 1.5 0 0 1 9 13.5v-3zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5h-3z"/> 5 </symbol> 6 </svg> 7</body>
框架
1<body> 2 <!-- 图片信息 --> 3 4 <div class="flex-shrink-0 p-3 bg-white" style="width: 280px;"> 5 <a href="/notebook" class="d-flex align-items-center pb-3 mb-3 link-dark text-decoration-none border-bottom"> 6 <svg class="bi me-2" width="30" height="24"><use xlink:href="#grid"/></svg> 7 <span class="fs-5 fw-semibold">类别</span> 8 </a> 9 <ul class="list-unstyled ps-0"> 10 <!-- TODO: 遍历notebook下级分区 --> 11 </ul> 12 </div> 13</body>
嵌套分区
最外层框架: 遍历notebook下级分区
notebook分区下没有博文, 全是节点, 为第1级分区
1{{ range where .Site.Sections "Section" "notebook"}} 2{{ range .Sections }} 3 4<!-- 分区逻辑 --> 5<li class="mb-1 my-1 ms-3"> 6 7 <!-- 显示第1级分区 --> 8 <button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#section-{{ md5 .Title }}" aria-expanded="false"> 9 {{ .Title }} 10 </button> 11 12 <!-- TODO: 遍历第1级分区下级 --> 13</li> 14{{ end }} 15{{ end }}
遍历第1级分区下级
1<!-- 注意此处id值 --> 2<div class="collapse" id="section-{{ md5 .Title }}"> 3 <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small"> 4 5 <!-- 第1级分区中第2级分区和博文混合 --> 6 {{ range .Pages }} 7 {{ if .IsNode }} 8 <!-- 如果是节点, 则为第2级分区 --> 9 10 <!-- TODO: 第2级分区框架 --> 11 {{ else }} 12 <!-- 如果是博文, 显示博文标题 --> 13 <li><a href="{{ .Permalink }}" class="link-dark rounded">{{ .Title}} </a></li> 14 {{ end }} 15 {{ end }} 16 </ul> 17</div>
第2级分区框架
1<li class="mb-1 my-1 ms-3"> 2 3 <!-- 显示第2级分区 --> 4 <button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#section-{{ md5 .Title }}" aria-expanded="false"> 5 {{ .Title }} 6 </button> 7 8 <!-- TODO: 遍历第2级分区下级 --> 9</li>
遍历第2级分区下级
1<div class="collapse" id="section-{{ md5 .Title }}"> 2 <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small"> 3 4 <!-- 第2级分区中第3级分区和博文混合 --> 5 {{ range .Pages }} 6 {{ if .IsNode }} 7 <!-- 如果是节点, 则为第3级分区 --> 8 9 <!-- TODO: 第3级分区框架 --> 10 {{ else }} 11 <!-- 如果是博文, 显示博文标题 --> 12 <li><a href="{{ .Permalink }}" class="link-dark rounded">{{ .Title}} </a></li> 13 {{ end }} 14 15 {{ end }} 16 </ul> 17 </div>
第3级分区框架
1<li class="mb-1 my-1 ms-3"> 2 3 <!-- 显示第3级分区 --> 4 <button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#section-{{ md5 .Title }}" aria-expanded="false"> 5 {{ .Title }} 6 </button> 7 8 <!-- TODO: 遍历第3级分区下级 --> 9</li>
遍历第3级分区下级
认为全是博文页
1<div class="collapse" id="section-{{ md5 .Title }}"> 2 <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small"> 3 {{ range .Pages }} 4 <li><a href="{{ .Permalink }}" class="link-dark rounded">{{ .Title}} </a></li> 5 {{ end }} 6 </ul> 7</div>
完整实现
1<div class="flex-shrink-0 p-3 bg-white" style="width: 280px;"> 2 <a href="/notebook" class="d-flex align-items-center pb-3 mb-3 link-dark text-decoration-none border-bottom"> 3 <svg class="bi me-2" width="30" height="24"><use xlink:href="#grid"/></svg> 4 <span class="fs-5 fw-semibold">类别</span> 5 </a> 6 <ul class="list-unstyled ps-0"> 7 {{ range where .Site.Sections "Section" "notebook"}} 8 {{ range .Sections }} 9 <li class="mb-1 my-1 ms-3"> 10 <button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#section-{{ md5 .Title }}" aria-expanded="false"> 11 {{ .Title }} 12 </button> 13 <div class="collapse" id="section-{{ md5 .Title }}"> 14 <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small"> 15 {{ range .Pages }} 16 {{ if .IsNode }} 17 <li class="mb-1 my-1 ms-3"> 18 <button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#section-{{ md5 .Title }}" aria-expanded="false"> 19 {{ .Title }} 20 </button> 21 22 <div class="collapse" id="section-{{ md5 .Title }}"> 23 <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small"> 24 {{ range .Pages }} 25 26 {{ if .IsNode }} 27 <li class="mb-1 my-1 ms-3"> 28 <button class="btn btn-toggle align-items-center rounded collapsed" data-bs-toggle="collapse" data-bs-target="#section-{{ md5 .Title }}" aria-expanded="false"> 29 {{ .Title }} 30 </button> 31 32 <div class="collapse" id="section-{{ md5 .Title }}"> 33 <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small"> 34 {{ range .Pages }} 35 36 <li><a href="{{ .Permalink }}" class="link-dark rounded">{{ .Title}} </a></li> 37 38 {{ end }} 39 </ul> 40 </div> 41 </li> 42 {{ else }} 43 <li><a href="{{ .Permalink }}" class="link-dark rounded">{{ .Title}} </a></li> 44 {{ end }} 45 46 {{ end }} 47 </ul> 48 </div> 49 </li> 50 {{ else }} 51 <li><a href="{{ .Permalink }}" class="link-dark rounded">{{ .Title}} </a></li> 52 {{ end }} 53 {{ end }} 54 </ul> 55 </div> 56 </li> 57 {{ end }} 58 {{ end }} 59 </ul> 60</div>
可以优化的地方
- 高亮选中项
- 保持选中项在正中位置
- 折叠展开逻辑