用套路寫頁面(第二節)不定高邊欄,子元素高度動態且相鄰聯動

目錄:css

  • 五、左側邊欄(難度:3.5顆星)
  • 5.一、原型分析
  • 套路5:當高度/寬度爲動態獲取,且相鄰聯動的兩個區域
  • 5.二、左邊欄上下區域劃分
  • 套路6:無痕滾動
  • 5.三、按鈕的 CSS
  • 5.四、歷史記錄
  • 5.五、總結

五、左側邊欄(難度:3.5顆星)

前文參照:前端

手把手教你用套路寫頁面(HTML、CSS初中級前端教學)(第一節):juejin.im/post/5d4a6f…git

5.一、原型分析

咱們先看原型圖:github

分析:後端

  • 總體結構爲上下兩部分;
  • 上方由不定數量的單行按鈕組成,從上到下延伸(所以須要考慮若是數量比較多,超出顯示區域怎麼辦);
  • 下方由不定數量個歷史操做組成;

整體考慮,我認爲,這個佈局有兩種方法。瀏覽器

第一種(簡單版):bash

  • 上下期中一個高度是固定的,另外一個自適應(一般來講,下最大高度不高,因此下應是固定的,上自適應);
  • 自適應部分 overflow-y: auto

第二種(困難版):微信

  • 上不定高;
  • 下不定高但有最大高度限制;
  • 上的最大高度根據下的最大高度變化;
  • 上超出最大高度時,出現滾動條(或能夠拖動滑動);
  • 下超出最大高度時,只顯示最新的;

咱們採用第二種方式進行開發(第一種太簡單)。less

第二種狀況,純css一般是沒法解決的,所以咱們須要js介入。ide

注:雖然說flex能夠,flex在某些老版本瀏覽器(非IE678)或者手機瀏覽器,好比IOS10之前,是可能出現bug的。我以前在阿里時,接到過來自客戶反饋。所以不採用flex。

下方歷史記錄的代碼思路:

  1. 歷史記錄總體爲絕對定位,bottom: 0; width: 100%
  2. 設置下方的最大高度,最大高度爲 h_max = dear的高度 + 單行歷史記錄的高度 * 最大顯示歷史記錄的個數
  3. 下方理論高度爲 h_count = dear的高度 + 單行歷史記錄的高度 * 歷史數目個數
  4. 實際高度爲 h = h_count > h_max ? h_max : h_count
  5. 下方默認有一條,當實際沒有的時候,顯示爲【無】(佔位使用);

上方按鈕的代碼思路:

  1. 絕對定位,top: 0
  2. 拿到下方的實際高度 h, 設置本身的 bottom 的值爲 h;
  3. 設置 overflow-y: auto

套路5:當高度/寬度爲動態獲取,且相鄰聯動的兩個區域

這是一個常見場景,一般見於其中一個區域數據來自於後端,另一個區域填充以配合前者。

場景:

  • 父容器不定寬不定高(但肯定能夠容納兩個子元素);
  • 兩個子元素共同填滿父容器,且左右/上下相鄰(爲了方便分析,這裏假設其上下相鄰);
  • 【假設上下相鄰】;
  • 兩個子元素都不定高,但其中一個有最大高度(主次之分);
  • 有最大高度的子元素,其高度是動態獲取的;

解決思路:

方法一(簡單,但在極少數狀況下會出現兼容性問題):

  • 假設兩個子元素上下相鄰,高度彈性;
  • 採用彈性佈局: flex;
  • 配置子元素的彈性方向: flex-direction;
  • 兩個子元素都不設置高度,但寬度爲100%;
  • 設置有最大高度限制的子元素,其最大高度:max-height;
  • 設置無最大高度限制的子元素(即另外一個子元素),得到所有的剩餘彈性空間分配: flex-grow;
  • 因而受高度限制的子元素,其高度被填充內容的高度撐開;
  • 而剩下的區域,被另一個子元素拿走;

方法二(複雜,可靠,可配置性強):

  • 假設兩個子元素上下相鄰,高度彈性;
  • 父容器不定寬高,所以子容器須要寫爲絕對定位,位置經過 left, top, bottom, right 來實現;
  • 兩個子元素設置寬度爲100%;
  • 受限制一方的高度,經過js計算得出,而後寫在標籤的 style 屬性的 height 值;
  • 另外一方的高度,其不設置 height 的值,而是經過設置 bottom 的值等於 style 屬性的 height 值;
  • 此時,兩個元素的位置和高度,都已經被設置完畢了;

5.二、左邊欄上下區域劃分

參考【套路五、當高度/寬度爲動態獲取,且相鄰聯動的兩個區域】的方法二的思想。

HTML代碼很簡單,總體來看是兩層DOM結構,代碼以下:

<div className="aside">
    <div className='aside-nav'
         style={navStyle}>

    </div>

    <div className='aside-my-dear'
         style={my-dearStyle}>

    </div>
</div>
複製代碼

上下兩部分的樣式也很簡單,標準的位置固定但高度不固定(注意,下面代碼,我沒有寫兩個子元素的高度)

.aside-nav {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  // 測試用,查看顯示效果是否正常
  //background-color: red;
}

.aside-dear {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  // 測試用,查看顯示效果是否正常
  //background-color: green;
}
複製代碼

如今,核心問題在於如何配置其高度,方法以下(見註釋和上面的分析):

// 歷史記錄的數量,最小爲1(爲0時,該位置爲佔位符)
let dearLength = asideData.asideDear.length < 1 ? 1 : asideData.asideDear.length
        
// 最大隻容許顯示【10】行
const MAXDEARCOUNT = 10;
if (dearLength > MAXDEARCOUNT) {
    dearLength = MAXDEARCOUNT
}

// 歷史記錄的高度 =  dear的高度34px(24px字體+5*2px上下部分行間距)
//                  + 歷史記錄單行高度22px(12px字體高度+5*2上下行間距)
//                  + 最下方留白5px
const dearHeight = 34 + 22 * dearLength + 5;
const navStyle = {
    bottom: `${dearHeight}px`
}
const dearStyle = {
    height: `${dearHeight}px`
}
複製代碼

此時咱們已經配置好了兩個子元素的高度,而且是動態生成的。

因而,給出 asideData.asideDear 的模擬數據:

asideDear: [
    {
        // 跳轉url
        url: '#01',
        // 歷史文字顯示
        text: 'gfdsbfdsbdfsb'
    },
    {
        url: '#02',
        text: 'hrtnhr12'
    },
    {
        url: '#03',
        text: 'mythn13rfe'
    }
]
複製代碼

此時,咱們更改 asideDear 的元素個數,會發現 dear 區域的高度發生變化。

【缺點】

該方案是沒問題的,硬要說缺點的話,就是上方區域按鈕比較多的時候,默認出現滾動條比較醜。

解決方案也不難,提供幾個參考:

  1. 考慮手寫一個滾動條,樣式和總體風格保持一致;
  2. 不顯示滾動條,但提供拖拽功能(即相似觸摸屏的操做方式),而後給是否達到最上、最小的提示;
  3. 隱藏滾動條,但依然可使用滾動功能(即按鈕和上分欄之間插入一層父級div,該級div比顯示區域更寬,滾動條即位於這更寬的區域以內,但受到其父級div overflow:hidden的約束,沒法顯示);

我這裏採用第三種解決方案,方法參考【套路6:無痕滾動】

套路6:無痕滾動

場景描述:

  • 假如父容器只有 100px 高,每一個元素高 30px,可能有超過 3 個元素,但不容許超出父容器範圍;
  • 所以通常狀況下,設置父容器 overflow:auto; 顯示滾動條;
  • 默認滾動條太難看,但不須要寫自定義滾動條;
  • 所以須要支持鼠標滾動,但不顯示鼠標滾動;

解決思路:

  1. 父容器和子元素之間加一層 div#box;
  2. 假設父容器和子元素的寬度爲 100px, 默認滾動條寬度爲 25px;
  3. div#box 的高度設爲 100%(同父容器),寬度設爲 125px(100+25)。假如元素過多,則 div#box 出現滾動條;
  4. 父容器設置 overflow:hidden,那麼 div#box 出現滾動條的時候,將在父容器顯示範圍以外;
  5. 子元素設置 max-width:100px,確保不管是否有滾動條,子元素的顯示效果都是一致的。

5.三、按鈕的 CSS

這個太簡單了,無非就是按鈕裏面一圖標一文字,就只說一下思路吧。

  1. 按鈕的大小是固定的(不固定也無所謂,確定有參考位置),添加定位屬性,好比相對定位 relative;
  2. 圖標設置爲絕對定位,上下居中(參考【套路2:定高不定寬,內有居中和相對最右側的元素】),而後再設置相對左側距離(left屬性);
  3. 文字一樣絕對定位,上下居中,經過 left 相對左側的距離。惟一區別是,須要經過 right 屬性設置最右側的寬度,防止文字超出其應該顯示的區域;

須要注意的是:

  • 這個樣式按鈕hover狀態是 45px 高,所以認爲一個按鈕的高度爲45px;
  • 但經過PS量實際兩個按鈕實際間距是50px(醉了!+1),無視,認爲是原型圖的問題,認爲按鈕與按鈕的實際間距是45px(即按鈕是連續的,不存在額外的間距);
  • 但又發現第一個按鈕的高度是65px(醉了+2,這種設計很奇怪);
  • 推定按鈕的父容器有額外 padding-top: 20px;

代碼參照:

src/components/aside/index.jsx
src/components/aside/style.less
複製代碼

5.四、歷史記錄

解決了高度問題後,這個就更簡單了。

  • Dear 文字所在 div 寬度 100%,
  • 每一個歷史記錄 div 寬度 100%,高度、行高等於實際高度;
  • 父級 div 設置 padding-bottom 下方留出應有的空隙;

完事。

5.五、總結

此時效果圖以下:(假設按鈕比較多的極端狀況效果圖)

相關文章
相關標籤/搜索