手把手帶你打造自己的UI樣式庫(第三章)之常用樣式組件的設計與開發

常用樣式組件的設計與開發

Search搜索框樣式的設計與開發

搜索組件的需求

搜索框的功能比較簡單,最基本的就是輸入和提交兩個邏輯。但是我們這個搜索框要額外的加一些細節,輸入框分爲輸入狀態和非輸入狀態,兩種狀態下輸入框表現要有所不同。我們對這個搜索框組件會有以下要求

  • 在搜索框輸入後,可以直接點擊鍵盤上的搜索按鈕進行查詢。這樣整個搜索工作都可以在屏幕底部的鍵盤中完成,不用再去頁面頂部點擊提交按鈕,可以減小操作範圍。
  • 在輸入狀態中,當輸入框有內容時,提供一鍵清空的功能。
  • 在輸入狀態中,要有輸入提示,且整個搜索區域要遮蓋住整個內容區,這樣在搜索的時候不會受到內容部分的影響。
  • 在輸入狀態中,提供取消按鈕,在非輸入狀態下隱藏取消按鈕。

在非輸入狀態下,只有一個輸入框樣式,在輸入框中有一個搜索圖標和“搜索”兩個提示用的文本。

當在輸入的狀態時,顯示取消按鈕和搜索提示,並且在輸入框不爲空的時候提供一鍵清空的按鈕。

搜索組件的設計與開發

首先建立 /demo/search.html 文件:

<div class="tt-content">
    <!-- 帶suggest的搜索框 -->
    <div class="tt-search">
        <!-- 搜索框 -->
        <form class="tt-search-form" action="#">
            <div class="tt-search-input-wrap">
                <i class="fa fa-search tt-search-icon"></i>
                <input type="text" class="tt-search-input" placeholder="搜索" autocomplete="off" required/>
                <i class="fa fa-close tt-search-clear"></i>
            </div>
            <span class="tt-search-cancel">取消</span>
        </form>
        <!-- 搜索建議 --> 
        <ul class="tt-search-suggest">
            <li class="tt-suggest-item">手機</li>
            <li class="tt-suggest-item">iPhone XS Max</li>
            <li class="tt-suggest-item">華爲P30</li>
            <li class="tt-suggest-item">小米 MIX3</li>
            <li class="tt-suggest-item">諾基亞1110</li>
        </ul>
    </div>
    <p class="content">內容區</p>
</div>

搜索組件的容器一共有兩個狀態,分爲輸入狀態和非輸入狀態。我們使用“on-focus”這個類來區分搜索框是不是在輸入狀態。在非輸入狀態下,搜索組件就是文檔流裏一個普通的盒子,可以隨着頁面進行滾動,而在輸入狀態下搜索組件需要覆蓋住整個頁面,所以我們要給 .tt-search 如下的樣式:

/* 搜索框 */
.tt-search{
    max-width: 640px;
    margin: 0 auto;
    background: #f8f8f8;
}
/* 搜索狀態中,覆蓋內容區 */
.tt-search.on-focus{
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    overflow-y: auto;
}
/* 處理有標題欄的情況 */
.tt-header ~ .tt-content .tt-search.on-focus{
    top: 2.3rem;
}
/* 處理有導航欄的情況 */
.tt-navbar ~ .tt-content .tt-search.on-focus{
    bottom: 2.5rem;
}

搜索框裏,我們使用了 form 做了最外層的容器,這是因爲之前提到想在鍵盤上直接提交搜索操作,如果想達到這種效果,就必須使用下面這種結構:

<form action="#">
    <input type="text" />
</form>

也就是帶有 action 屬性的表單裏包含的 input 元素,這樣的結構就會被輸入法認定爲表單的功能,會在鍵盤上顯示出“前往”的按鈕.

@ Tips:
如果 input 的類型是 H5 中的搜索類型,也就是 ,那麼在有些輸入法中表單的提交按鈕的文本就可以變成“搜索”。

在這裏插入圖片描述

/* 搜索欄中的表單 */
.tt-search > .tt-search-form{
    display: flex;
    height: 2.3rem;
    align-items:center;
}

@ Tips:
align-items 屬性就是用來標記彈性佈局裏的元素在側軸(也就是和 flex-direction 方向相垂直的軸)上的對齊方式,form 裏所有元素都是水平排列的,所以想豎直居中,就可以直接使用“align-items:center;”來實現。align-items 有以下可取的值:

  • stretch(默認),元素進行抻拉來填滿,如果盒子有指定大小,那麼以指定的大小爲準。
  • center,元素會佈局在容器側軸的中間位置。
  • flex-start,元素位於容器的開頭。
  • flex-end,元素位於容器的結尾。
  • baseline,元素位於第一行文本的基準線位置,這裏要注意是第一行的文本,而不是第一個元素。

接下來是 form 容器裏的 4 個元素,因爲搜索和一鍵清空的圖標都是和 input 關聯的,所以做了個 .tt-search-input-wrap 容器把這三個放了進去,最後的取消按鈕和這個容器在同一層。先來處理 .tt-search-input-wrap 和取消按鈕的關係:

/* 輸入框的容器 */
.tt-search > .tt-search-form > .tt-search-input-wrap{
    flex: 1;
    position: relative;
    padding: 0 .5rem;
}
/* 取消按鈕 */
.tt-search > .tt-search-form > .tt-search-cancel{
    flex: 0 0 2.2rem;
    padding-right: .5rem;
    text-align: center;
    font-size: .7rem;
    display: none;
}
/* 對取消按鈕的控制 */
.tt-search.on-focus > .tt-search-form > .tt-search-cancel{
    display: block;
}

這裏面有幾個點要注意下:

  • 沒有取消按鈕的時候,.tt-search-input-wrap 容器是撐開全寬,然後使用左右的 padding 來保證裏面的輸入框可以在左右留下一點空閒。
    有取消按鈕的時候,爲了保證取消按鈕在空閒區域是居中的,所以會給取消按鈕一個“padding-right: .5rem;”來和 .tt-search-input-wrap 右邊+ 留下的空間對稱,這樣取消按鈕只要是文本居中就可以了。
  • .tt-search-cancel 在默認情況下是隱藏的,只有在搜索狀態中才會顯示。
  • 取消按鈕使用固定的 2.2rem 的寬度,不做拉伸和收縮。
/* 搜索圖標 */
.tt-search .tt-search-icon{
    position: absolute;
    height: .8rem;
    line-height: .8rem;
    font-size: .7rem;
    left: 1rem;
    top: 0;
    bottom: 0;
    margin: auto;
    color: #ccc;
}
/* 輸入框的樣式 */
.tt-search .tt-search-input{
    box-sizing: border-box;
    width: 100%;
    height: 1.6rem;
    border: none;
    font-size: .8rem;
    padding-left: 1.5rem;
    background: #fff;
    border-radius: .2rem;
}
/* 清空按鈕的樣式 */
.tt-search .tt-search-clear{
    position: absolute;
    height: .8rem;
    line-height: .8rem;
    width: .8rem;
    font-size: .6rem;
    top: 0;
    bottom: 0;
    margin: auto 0;
    right: 1rem;
    border-radius: 50%;
    color: #fff;
    background: #ccc;
    display: none;
}
/* 對清空按鈕的控制 */
.tt-search.on-focus .tt-search-input:valid + .tt-search-clear{
    display: block;
}

上面的代碼中,圖標的默認樣式是沒什麼問題的,就是前面搜索圖標的用法,只不過把位置放在了右邊。這裏面要注意的是第二條樣式只有在搜索狀態下並且輸入框有內容的時候才讓這個清空按鈕出現,所以使用了一個 :valid 選擇器來判斷和它相鄰的輸入框的狀態。這個 :valid是和 input 中的“required”屬性對應的,input 元素有內容時“required”驗證條件就會通過,這時候 :valid 選擇器就會選中這個 input,從而後面的兄弟選擇器纔會選中 .tt-search-clear 元素。這種用法就可以直接使用 CSS 來控制清空按鈕的顯示了,省去了 JS 的工作。

List列表樣式的設計與開發

列表組件的需求

一、簡單列表

簡單列表的設計就很簡單了,比如在表單元素中存放每一條表單的容器。
在這裏插入圖片描述
這個列表的樣式很好實現,這裏面只需要注意爲了和複雜列表共用每一行的容器,我們不要對每一行的元素做高度和行高的限制。

二、複雜列表
複雜列表的每一行因爲要呈現多個信息,所以內容區要重新佈局。公司的業務裏主要是商品展示,所以在 UI 裏我們使用商品信息作爲複雜列表的填充內容,樣式如下:

在這裏插入圖片描述
在這個複雜列表中,我們會有如下要求:

  • 複雜列表和簡單列表可以使用相同的內邊距撐開內容區和邊界的距離。
  • 每一行的內容區分左右結構,左邊圖片固定寬度,右側文字區充滿剩餘區域。
  • 內容區分多行,其中要保證第一行和內容區上邊對齊,最後一行和內容區底邊對齊。
  • 第一行爲標題,限制最多顯示兩行內容,可以自動隱藏超長部分,並在文本末尾追加省略號。

列表組件的設計與開發

我們先來開發簡單列表,簡單列表的樣式比較簡單,我們之前也做過類似的樣式,所以這裏就直接貼代碼了。

<!-- 簡單列表 -->
<ul class="tt-list">
    <li class="tt-list-item">北京</li>
    <li class="tt-list-item">上海</li>
    <li class="tt-list-item">天津</li>
    <li class="tt-list-item">重慶</li>
    <li class="tt-list-item">廈門</li>
    <li class="tt-list-item">廣州</li>
    <li class="tt-list-item">...</li>
</ul>

這裏我們以城市列表爲例,使用 ul 元素來實現這個列表。這個列表的樣式也是給 .tt-list-item 加上一些簡單樣式就可以實現了,我們可以在 /src/list.css 中添加下列樣式:

/* 列表裏每一行的容器 */
.tt-list > .tt-list-item{
    position: relative;
    padding: .5rem 1rem;
    font-size: .8rem;
    background: #fff;
    color: #333;
    border-bottom: 1px solid #eee;
}

複雜列表中,每一行的外層容器可以和簡單列表共用,比較麻煩的就是處理每一行裏內容區的佈局。按着示意圖裏的樣式,圖片和文本區域左右排列,如下圖:
在這裏插入圖片描述
這個結構裏,左側圖片固定寬度,右側文本區域需要填充剩餘空間的需求,所以這又是一個特別適合彈性佈局的場景。左邊的圖片區域可以直接使用一個 img 元素,但我們這裏會在 img 外層加一層容器,這樣如果需要在圖片位置加一些標籤的話會更容易定位。右側區域就是三個文本段落依次排列。

<!-- 複雜列表 -->
<ul class="tt-list">
    <li class="tt-list-item">
        <div class="item-img-wrap">
            <img class="item-img" src="img/list-img.jpg" alt="機械鍵盤">
        </div>
        <div class="item-content-wrap">
            <h1 class="item-title">FILCO斐爾可 機械鍵盤87遊戲無線聖手忍者二代紅軸茶青黑藍牙雙模</h1>
            <p class="item-price">¥998</p>
            <p class="item-desc">已售1834件</p>
        </div>
    </li>
    <li class="tt-list-item">
        <div class="item-img-wrap">
            <img class="item-img" src="img/list-img.jpg" alt="機械鍵盤">
        </div>
        <div class="item-content-wrap">
            <h1 class="item-title">FILCO斐爾可 機械鍵盤87遊戲無線聖手忍者二代紅軸茶青黑藍牙雙模</h1>
            <p class="item-price">¥998</p>
            <p class="item-desc">已售1834件</p>
        </div>
    </li>
    <!-- ...其他多個列表項 -->
</ul>

爲了縮短篇幅,這個列表裏只包含了兩條列表數據。在實現列表裏內容區樣式的時候,左右結構的處理和圖片的處理都比較常規,只有右側文本區的要求有些多。文本區分爲標題、價格和銷量這三部分內容,這三個元素要佔滿文本區域的高度,並且標題要靠頂,銷量描述要貼底。對於這種需求能想到最簡單的做法就是先固定每個元素的高度,然後通過計算出的內邊距或外邊距來撐開整個區域。但是我們這裏準備用彈性佈局裏的 “justify-content” 屬性來實現這個效果。下面先來介紹一下 “justify-content”。

@ Tips:
justify-content 屬性是在彈性佈局中,用來定義主軸上元素的排列方式的,這個屬性要作用於彈性佈局中的容器上。這個屬性有以下可取的值:
flex-start:彈性盒子裏的所有元素從容器起始位置開始依次排列。這個起始位置並不是固定的,它會受到 “flex-direction” 的影響。比如 “flex-direction” 的值如果是 “column-reverse”,那起始位置就在容器的最下面;如果 “flex-direction” 的值是默認的 “row”,那麼起始位置就是容器的最左邊。效果如下:
在這裏插入圖片描述在這裏插入圖片描述

/* 列表裏每一行的容器 */
.tt-list > .tt-list-item{
+   display: flex;
    position: relative;
    padding: .5rem 1rem;
    font-size: .8rem;
    background: #fff;
    color: #333;
    border-bottom: 1px solid #eee;
}
/* 列表項的圖片容器 */
.tt-list .item-img-wrap{
    flex: 0 0 5rem;
    height: 5rem;
    margin-right: .5rem;
    border-radius: .2rem;
    overflow: hidden;
}
/* 列表項的圖片 */
.tt-list .item-img-wrap > .item-img{
    width: 100%;
    height: 100%;
}
/* 列表項的文字區域 */
.tt-list .item-content-wrap{
    position: relative;
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

再下來就是文本區域裏三個元素的樣式了,這裏面標題部分需要兩行的高度,並且超長的時候要截斷,這裏我們會使用下面這個固定的搭配來實現多行的折行截斷效果:

div{
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

這三條固定的搭配就可以實現文本多行的截斷,並且在截斷處自動追加省略號。但需要注意的是,這幾個屬性並不是 CSS3 中標準的屬性,並且只有在 webkit 內核的瀏覽器中且加上 - webkit - 前綴纔有效。我們最需要的是對多行文本超出的部分做隱藏,而對添加省略號的需求不是很強,所以這幾個元素可以配合 height 和 line-height 來使用,這樣哪怕這三個屬性失效了,也能保證正常的顯示效果。

/* 列表項的標題 */
.tt-list .item-content-wrap > .item-title{
    height: 2rem;
    line-height: 1rem;
    font-size: .8rem;
    font-weight: normal;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
/* 列表項的價格字段 */
.tt-list .item-content-wrap > .item-price{
    font-size: .8rem;
    font-weight: 600;
    color: #e0652f;
}
/* 列表項的描述字段 */
.tt-list .item-content-wrap > .item-desc{    
    color: #999;
    font-size: .6rem;
}

Grid網格樣式的設計與開發

網格組件的需求

在實現網格組件的時候,我們把它分成兩部分來設計。一部分是最常用的標準九宮格,另一部分就是在九宮格的基礎上再延伸出其他多列的網格。

一、九宮格

我們先來分析九宮格的需求,我們需要做的九宮格樣式如下:
在這裏插入圖片描述
對於這個九宮格,我們有如下的要求:

  • 九宮格中多個盒子分組排列,每行三個,可以排列多行。
  • 九宮格每兩個盒子中間都是用邊框區分,整個容器上下有邊框,左右不需要邊框。
  • 每個盒子內容區水平豎直居中。
  • 每個格子之間的邊框也可以去掉。

二、多列網格

在九宮格的基礎上,我們要實現多列網格,樣式如下:
在這裏插入圖片描述
對多列網格我們有如下要求;

  • 可以通過 class 直接指定網格的列數,列數可以從 2 列一直到 5 列。
  • 多列網格左右兩側也沒有邊框。
  • 格子的高度能根據列數的不同自行調整。

網格組件的設計與開發

在實現九宮格的時候,我們要考慮的就是多個格子怎麼分行排布。這種多行多列並且要在水平方向上平分空間的佈局,和 table 元素的特點十分吻合。但是,如果使用 table 佈局的話,那麼網格的列數要固定下來的,這樣在後面做多列表格的時候就需要再去改動 HTML 的結構,不是很方便。

接下來可以考慮使用 float 來實現這個效果,這樣可以給格子定義好寬度,然後每行排滿了就會自動從下一行開始排列。這種方案是可以的,唯一的不好就是定義盒子的寬度上,如果是 3 格或者 6 格這種非整數的百分比,就有可能出現不能佔滿全屏的情況,另外寬度的比值也要自己去計算。

最後還有一種選擇,就是使用彈性佈局。我們之前用的彈性佈局的例子都是排布在同一行,但是彈性佈局也是支持多行排列的,使用彈性佈局的 flex-wrap 即可實現。

@ Tips:
flex-wrap 屬性是彈性佈局中用來指定彈性盒子裏的元素換行方式的,它有以下三個可取的屬性值:
nowrap:這個屬性表示彈性盒子裏的元素在放不下的時候不換行,如果元素總寬度超過容器寬度,就會根據 flex-shrink 屬性指定的方式進行壓縮。
wrap:這個屬性表示彈性盒子裏的元素在放不下的時候自動進行折行。
wrap-reverse:這個屬性也表示彈性盒子裏的元素放不下時進行折行,但是這種折行方式比較特殊,折出來的多行是從下向上排列的。

關於 flex-wrap 屬性要注意的是,它可以和 flex-grow 屬性配合使用,能對盒子進行拉伸,保證每一行都是充滿的。但是 flex-wrap 屬性和 flex-shrink 屬性是衝突的,當彈性盒子指定了可以換行的情況下,容器空間不足的情況下就會折行,而不會再去壓縮盒子裏的元素。

<!-- 九宮格 -->
<div class="tt-grid">
    <div class="tt-grid-item">
        <i class="fa fa-area-chart tt-grid-icon"></i>
        <p class="tt-grid-label">格子1</p>
    </div>
     <div class="tt-grid-item">
        <i class="fa fa-area-chart tt-grid-icon"></i>
        <p class="tt-grid-label">格子2</p>
    </div>
    <div class="tt-grid-item">
        <i class="fa fa-bar-chart tt-grid-icon"></i>
        <p class="tt-grid-label">格子3</p>
    </div>
    <div class="tt-grid-item">
        <i class="fa fa-area-chart tt-grid-icon"></i>
        <p class="tt-grid-label">格子4</p>
    </div>
     <div class="tt-grid-item">
        <i class="fa fa-area-chart tt-grid-icon"></i>
        <p class="tt-grid-label">格子5</p>
    </div>
    <div class="tt-grid-item">
        <i class="fa fa-bar-chart tt-grid-icon"></i>
        <p class="tt-grid-label">格子6</p>
    </div>
    <div class="tt-grid-item">
        <i class="fa fa-area-chart tt-grid-icon"></i>
        <p class="tt-grid-label">格子7</p>
    </div>
    <div class="tt-grid-item">
        <i class="fa fa-area-chart tt-grid-icon"></i>
        <p class="tt-grid-label">格子8</p>
    </div>
    <div class="tt-grid-item">
        <i class="fa fa-bar-chart tt-grid-icon"></i>
        <p class="tt-grid-label">格子9</p>
    </div>
</div>

這裏總共放上 9 個格子,每個格子裏的包括了一個圖標和一個格子的名稱。在排布格子的時候,要注意的一個是剛纔提到的 flex-wrap 的用法,另外一個就是盒子邊框的設計。

首先在垂直方向上,每兩個格子間的邊框可以給每個格子下邊框來實現。然後在水平方向上格子間的邊框可以給每個盒子右邊框來實現。但是這樣九宮格最右側就會多出一格邊框,再把最右側一列格子的邊框取消。最後,就是給整個盒子容器加一個上邊框,也就是黃色的邊框部分,就可以實現需求裏要求的邊框樣式。

/* 網格組件 */
.tt-grid{
    display: flex;
    flex-wrap: wrap;
    border-top: 1px solid #ddd;
}
/* 網格中的格子 */
.tt-grid > .tt-grid-item{
    position: relative;
    flex: 1 1 33%;
    box-sizing: border-box;
    padding: 1.2rem 0;
    text-align: center;
    border-right: 1px solid #ddd;
    border-bottom: 1px solid #ddd;
    background: #fff;
}
/* 默認是3列 */
.tt-grid .tt-grid-item:nth-child(3n){
    border-right: none;
}
/* grid內容區 */
.tt-grid > .tt-grid-item > .tt-grid-icon{
    font-size: 1.5rem;
    color: #aaa;
    margin-bottom: .5rem;
}
.tt-grid > .tt-grid-item > .tt-grid-label{
    font-size: .6rem;
    color: #333;
} 
/* 不需要邊框時取消容器上的border */
.tt-grid.no-border{
    border: none;
}
/* 不需要邊框時取消格子上所以的border */
.tt-grid.no-border > .tt-grid-item{
    border: none;
}

這裏有幾點要注意:

  • 這個格子的容器 .tt-grid 上加了 “flex-wrap: wrap;” 屬性,然後在格子上加入 “flex: 1 1 33%;” 屬性即可完成格子的排布要求,這裏分三列所以我們選一個比 1/3 稍小的百分比,然後通過彈性讓每行的三個格子撐滿整行。
  • 每個格子要有邊框,所以每個格子都是用 “border-box” 形式的盒模型。
  • 我們給每個格子右邊框和下邊框,然後再通過 “:nth-child (3n)” 這個僞類選擇器來取消掉最右一排格子的右邊框。
  • 通過垂直方向的 padding 值撐開了盒子的內容。

在實現多列網格的時候,只需要在剛纔的九宮格上進行改動就可以。這裏我們要變動的地方有:

  • 改變折行的位置。假如要製作兩列網格的時候,就可以把格子寬度設置成 50%,這樣每行就正好能放下 2 個格子
  • 改變邊框的情況。假如要製作兩列網格的時候,就要把默認情況下所有第 3n 個格子的右邊框恢復,然後再把所有 2n 個格子的右邊框去掉。
  • 改變 .tt-grid-item 的內邊距,來調整整個格子的高度。

根據這些要求,我們就可以寫出多列網格的樣式了。2 列網格就可以用如下代碼來實現:

/* 兩列網格 */
.tt-grid.tt-grid-2 .tt-grid-item{
    border-right: 1px solid #ddd;
    flex-basis: 50%;
    padding: 1.8rem 0;
}
.tt-grid.tt-grid-2 .tt-grid-item:nth-child(2n){
    border-right: none;
}
/* 四列網格 */
.tt-grid.tt-grid-4 .tt-grid-item{
    border-right: 1px solid #ddd;
    flex-basis: 25%;
    padding: .9rem 0;
}
.tt-grid.tt-grid-4 .tt-grid-item:nth-child(4n){
    border-right: none;
}
/* 五列網格 */
.tt-grid.tt-grid-5 .tt-grid-item{
    border-right: 1px solid #ddd;
    flex-basis: 20%;
    padding: .6rem 0;
}
.tt-grid.tt-grid-5 .tt-grid-item:nth-child(5n){
    border-right: none;
}

Menu菜單樣式的設計與開發

Menu菜單組件的需求

在 PC 端中,因爲頁面空間充足,菜單和操作可以處在同一個頁面中,所以 PC 端的菜單通常只是充當頁面或者功能的引導。但是在移動端,有些複雜的操作會被放進菜單項引導的二級頁面來做,爲了方便查看操作結果,通常會把操作信息也展示在菜單上。而對於簡單的操作,也可以直接放在菜單上來完成,比如上面的開關功能。所以移動端的菜單除了基本的引導作用以外,還要承擔信息展示和完成簡單操作的作用。下面我們來分析一下移動端的菜單組件都會有什麼需求:

  • 菜單項左右留出空間,不能緊貼邊框。
  • 菜單名稱佔滿一行的剩餘空間,超長以後自動截斷,不能折行。
  • 菜單信息部分可以是文本或者圖標,要有最大寬度限制,超寬後自動截斷,不能折行。
  • 需要進入下級頁面的菜單項要有引導圖標,引導圖標位於菜單項的最右側。
  • 有開關功能的菜單項,開關按鈕位於菜單項的最右側,且有開和關兩種狀態。
  • 開關的狀態切換時,要有過渡效果。

Menu菜單組件的設計與開發

根據前面的需求,基礎菜單裏的分爲菜單名稱、菜單信息、菜單引導圖標這三個內容。我們先按着這個要求把基本的 html 結構做出來:

<div class="tt-menu">
    <a class="tt-menu-item">
        <p class="tt-menu-name">用戶ID</p>
        <span class="tt-menu-value">33581893</span>
    </a>
    <a class="tt-menu-item">
        <p class="tt-menu-name">用戶名</p>
        <span class="tt-menu-value">推推UI</span>
        <i class="fa fa-chevron-right tt-menu-icon"></i>
    </a>
    <a class="tt-menu-item">
        <p class="tt-menu-name">二維碼</p>
        <i class="fa fa-qrcode tt-menu-value"></i>
        <i class="fa fa-chevron-right tt-menu-icon"></i>
    </a>
    <a class="tt-menu-item">
        <p class="tt-menu-name">隱私設置</p>
        <i class="fa fa-chevron-right tt-menu-icon"></i>
    </a>
</div>

這裏我們做了四個菜單,分別展示了菜單的不同用法;

  • 第一個菜單項只展示信息,沒有引導作用,所以只有菜單名稱和菜單信息兩個內容。
  • 第二個和第三個菜單項有展示帶信息和引導到下級頁面的作用,所以會有菜單名稱、菜單信息和引導圖標這三個內容。只不過第二個菜單6 項使用了文本,而第三個菜單項使用了一個二維碼圖標作爲菜單信息。
  • 最後一個菜單項需要引導到下一級的菜單,沒有具體的菜單信息,所以只有菜單名稱和引導圖標。

根據這幾種菜單的類型我們可以知道,菜單名稱是一定有的,後面的菜單信息和引導圖標都不是必須的。根據需求,我們要求菜單名稱靠左,菜單信息和菜單引導圖標在最右側,且都和頁面的邊界有一定的空間。這種需求一看就應該很熟悉了,與前面完成的列表和輸入框的樣式又很相似,直接用彈性佈局解決。

/* 菜單項 */
.tt-menu > .tt-menu-item{
    display: flex;
    height: 2.3rem;
    padding: 0 1rem;
    align-items: center;
    border-bottom: 1px solid #eee;
    font-size: .8rem;
}
/* 菜單名稱 */
.tt-menu > .tt-menu-item > .tt-menu-name{
    flex: 1;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: #333;
}
/* 菜單信息 */
.tt-menu > .tt-menu-item > .tt-menu-value{
    max-width: 5rem;
    height: 1rem;
    line-height: 1rem;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    color: #999;
}
/* 下級操作引導圖標 */
.tt-menu > .tt-menu-item > .tt-menu-icon{
    margin-left: .3rem;
    color: #999;
}

在這三個元素中,菜單名稱使用了“flex:1;”用來佔滿剩餘空間,以便把其他元素擠到容器的最右側,如果菜單名稱過長的話會自動截斷。菜單信息這個元素沒有指定寬度,但指定了最大寬度和超出自動截斷,這樣就不會在信息太長的時候擠佔菜單名稱的位置。最後的引導圖標就是簡單的設置了一個左邊距,用來和菜單信息隔開一段距離。

Modal模態框樣式的設計與開發

模態框的需求

一、基礎模態框的需求

對於基礎模態框,我們要有如下要求:

  • 模態框要有半透明的背景遮蓋住整個頁面,保證用戶在模態框中操作的時候不受原有內容的影響。
  • 模態框固定在頁面上,在水平方向上居中。
  • 在豎直方向上比居中位置稍微靠上,可以讓中心點距離頁面上邊緣 45%。因爲屏幕上邊一般都有頭部,所以稍微偏上一點在視覺上會更舒服。
  • 模態框的內容區可以隨着內容的多少來調整高度,當文字太多的時候使用滾動。
  • 內容區的文字和模態框的邊界要留出一定的距離。
  • 操作區裏的按鈕撐開整個模態框的寬度,有多個按鈕時多個按鈕平分模態框寬度,且中間要有分隔線。
  • 可以通過一個類來控制模態框是否顯示。

二、海報形式模態框的需求

對於海報形式模態框的要求,其實會更簡單一些,它只是在基礎模態框的基礎上做了些變動。對海報形式的模態框有以下需求:

  • 圖片佔據整個內容區,不需要和模態框邊緣留空間。
  • 取消操作區。
  • 在彈窗的下方添加關閉按鈕。

基礎模態框的設計與開發

我們先來分析下模態框的結構。根據需求,模態框裏大體上是分爲兩部分,一部分是半透明遮罩,另外一部分就是模態框的窗口部分。而模態框裏面又分爲內容區和操作區,內容區就是一些文本性質的內容,而操作區可以放按鈕。

<div class="tt-modal show">
    <div class="tt-mask"></div>
    <div class="tt-modal-wrap">
        <div class="tt-modal-body">
            <p>您的會員即將到期,請及時續費,以免影響您的權益。</p>
        </div>
        <div class="tt-modal-footer">
            <a class="tt-btn">下次再說</a>
            <a class="tt-btn">立即續費</a>
        </div>
    </div>
</div>
/* 模態框 */
.tt-modal{
    display: none;
}
/* 控制模態框的顯示 */
.tt-modal.show{
    display: block;
}

然後是下一層蒙版和模態框窗口的實現。蒙版層可以直接使用在第三章實現過的通用蒙版,這裏只需要在 tt-modal 里加入一個 class 爲“tt-mask”的 div 元素就可以了。

接下來是窗口的實現,窗口的定位就決定了模態框顯示的位置,按着需求我們希望它中心在距頂部 45% 的位置。對於這種定位要求,我們之前用過的方法只有一種比較接近。就是在做絕對定位元素垂直居中的時候,可以通過設置“top: 45%;”值來定位元素的起始位置,再通過負的 margin-top 值來把整個容器向上移動容器高度的一半,從而達到需求中的要求。這種方法已經很接近了,但遺憾的是這種方式下我們要知道容器的確切高度,才能設置正確的 margin-top 值,而我們這裏有另外一條要求就是彈窗的高度要隨着內容自動調整,所以這種方法就沒法用了。

下來我們要介紹一個新的東西,就是 CSS3 中的 transform 屬性。

@ Tips:
transform 屬性是 CSS3 中用來對盒模型做變化的,可以用它對元素的形狀、大小、位置和旋轉角度等進行更改。 transform 可以取的值有很多,這裏由於篇幅限制只介紹幾種常用的取值,同學們下去可以去w3school上了解下其他的轉換方式。

translate(x,y),這個屬性值是用來改變元素的位置,兩個參數分別是在 x 軸和在 y 軸上的位移。其中 x 和 y 的值就是一般的長度值,可以使用 px、rem 和百分比等單位的值,如:

transform: translate(30px, 50px);
注:如果在 translate 中只有一個值,表示的是在 x 軸上的位移。

scale(x,y), 這個屬性值是用來調整元素大小的。x 和 y 的取值是數字,分別表示在 x 軸和 y 軸上縮放的倍數,如果取值小於 1 就是縮小,大於 1 就是放大,如:

transform: scale(1.2, 1.5);
注:如果在 scale 中只有一個值,表示的是在 x 軸和 y 軸上都進行縮放這個參數指定的倍數。

rotate(angle),這個屬性值用來調整元素的旋轉角度。angle 的值代表的是順時針旋轉的角度,單位是 deg,如:

transform: rotate(45deg);
這裏就介紹這三種最常見的用法。在剛使用 transform 屬性的時候可能會有點不習慣,個人覺得應該把各種轉換方法拿出來作爲單獨的屬性使用會更方便。
在這裏插入圖片描述

有了 transform 屬性,剛纔的問題就能解決了。前面講的那種方法裏,margin-top 的值是以外層 .tt-modal 的高度爲參照物的,所以沒法使用百分比。但是現在有了 translate,這個屬性做位移的時候參照物是盒子本身的高度,這樣通過向上移動盒子自身高度的 50%,就可以把盒子的中心移到 top 值設定的地方。這樣無論模態框窗口有多高,都可以保證窗口的中心距頁面上邊緣 45% 的需求。所以關於窗口容器這部分代碼如下:

/* 模態框窗口容器 */
.tt-modal .tt-modal-wrap{
    position: absolute;
    width: 75%;
    max-width: 480px;
    top: 45%;
    transform: translateY(-50%);
    left: 0;
    right: 0;
    margin: auto;
    background: #fff;
    border-radius: .4rem;
    z-index: 301;
}

這裏面我們使用的就是“transform: translateY(-50%);” 這條屬性對窗口容器做的位移。這裏還有一點要注意,我們使用了“max-width: 480px;”限制了模態框窗口的最大寬度,是防止在大屏幕下模態框過大,所以採用了頁面內容區最大寬度 640px 的 75% 作爲窗口的最大寬度。

最後就是窗口容器裏面的樣式了。裏面分爲內容區和操作區,分別用“tt-modal-body”和“tt-modal-footer”這兩個 class 來表示這兩部分,其中操作區爲了在水平方向放多個按鈕,會使用彈性佈局。這兩個容器的樣式就可以按如下方式實現:

/* 模態框內容區 */
.tt-modal .tt-modal-body{
    padding: 1.8rem .8rem 1.5rem;
    text-align: center;
    font-size: .8rem;
    line-height: 1.2rem;
    overflow: hidden;
}
/* 模態框尾部 */
.tt-modal .tt-modal-footer{
    display: flex;
    border-top: 1px solid #ddd;
}
/* 模態框尾部裏按鈕的樣式 */
.tt-modal .tt-modal-footer .tt-btn{
    border: none;
    border-radius: 0;
    width: 100%;
    font-size: .8rem;
}
/* 模態框尾部中的按鈕加上分隔 */
.tt-modal .tt-modal-footer .tt-btn + .tt-btn{
    border-left: 1px solid #ddd;
}

三、海報樣式模態框的設計與開發

<div class="tt-modal show">
    <div class="tt-mask"></div>
    <div class="tt-modal-wrap">
        <div class="tt-modal-body no-padding">
            <img class="tt-modal-img" src="./img/modal-test.jpg" alt="">
        </div>
        <i class="fa fa-close tt-modal-close"></i>
    </div>
</div>

這個 HTML 結構和剛纔基礎模態框很相似,只有以下三處的不同:

  • 給內容區容器加上了“no-padding”這個 class 來消除內容區的內邊距,以便讓圖片撐滿內容區。
  • 內容區的文本換成了一張圖片。
  • 在窗口容器的最後添加了一個關閉按鈕。
/* 控制模態框內容區的內邊距 */
.tt-modal .tt-modal-body.no-padding{
    padding: 0;
}
/* 圖片形式的模態框樣式 */
.tt-modal .tt-modal-body .tt-modal-img{
    display: block;
    width: 100%;
    border-radius: .3rem;
}
/* 純圖片模態框裏的關閉按鈕 */
.tt-modal .tt-modal-close{
    position: absolute;
    left: 0;
    right: 0;
    width: 1.3rem;
    line-height: 1.3rem;
    margin: auto;
    bottom: -3rem;
    text-align: center;
    font-size: .8rem;
    font-weight: 100;
    color: #eee;
    border: 1px solid #eee;
    border-radius: 50%;
}

這裏要注意下,關閉按鈕的位置是在外層容器邊緣以外的,所以千萬不要把外層 tt-modal-wrap 元素設置成“overflow: hidden;”,那樣關閉按鈕就會被隱藏掉了。

Loading加載提示樣式的設計與開發

加載提示組件的需求

一、頁面加載提示工具

加載提示組件並不是只有加載中的狀態下才用的到,在頁面加載出現異常情況下,也可以使用這個組件進行提示。頁面如果加載成功了就會顯示頁面的內容,因此不需要有加載成功的信息的提示。

對於頁面加載提示工具,我們有如下要求:

  • 提示工具分爲圖標和文本兩部分,兩種內容水平居中。
  • 如果是載入中的提示,圖標使用旋轉的loading圖標。
  • 如果是其他類型的提示,使用靜態的圖標即可。
  • 圖標和文字的顏色要淺一些,不會搶佔用戶的視線。

二、列表加載提示工具

對於列表加載提示工具,也是會有幾種狀態。最常見的就是加載中的狀態。此外,還有當拉到頁面底部,可能會用到提示操作的上拉加載更多的提示,還有在沒有更多數據的時候顯示已經到底的信息等。

對於列表中使用的單行加載提示工具,會有以下要求:

  • 提示工具中的文本水平居中。
  • 文本的左右有兩個線條,作爲提示文本的裝飾。
  • 如果是正在加載的提示,左側添加旋轉的加載圖標。
  • 其他情況下,提示信息只包含純文本。
  • 如果是提示上拉加載更多的提示,在右側添加上下振動的上箭頭圖標作爲引導。

加載提示的組件的設計與開發

<!-- 頁面加載提示組件 -->
<h1 class="tt-panel-title">頁面加載提示組件</h1>
<div class="tt-panel-body">
    <div class="tt-loading">
        <i class="fa fa-circle-o-notch fa-spin tt-loading-icon"></i>
        <span class="tt-loading-info">用力載入中...</span>
    </div>
    <div class="tt-loading">
        <i class="fa fa-refresh tt-loading-icon"></i>
        <span class="tt-loading-info">加載出錯,點我重新加載</span>
    </div>
</div>
/* 頁面加載提示組件 */
.tt-loading{
    padding: 1rem 0;
    text-align: center;
}
/* 頁面加載提示組件的圖標 */
.tt-loading > .tt-loading-icon{
    font-size: 4.5rem;
    color: rgba(0, 0, 0, .05);
}
/* 頁面加載提示組件的提示信息 */
.tt-loading > .tt-loading-info{
    display: block;
    margin-top: .6rem;
    font-size: .8rem;
    color: #ccc;
}

單行的列表加載提示工具的結構也很簡單,也是由文本和圖標組成。這裏面唯一要注意的就是文本兩側兩條橫線的實現方式。最直接的做法就是做兩個盒子分別放在文本的左右兩側,但是還有更簡單的方法,就是直接使用當前容器的邊框來實現,再使用文本的背景色把實線中間的部分遮蓋住。

<div class="tt-loading-inline">
    <span class="tt-loading-info">
        <i class="fa fa-circle-o-notch fa-spin tt-loading-icon"></i>
        用力加載中
    </span>
</div>
/* 單行加載提示組件 */
.tt-loading-inline{
    margin: 1.5rem auto 1rem;
    width: 12.5rem;
    position: relative;
    box-sizing: border-box;
    text-align: center;
    color: #999;
    height: 1rem;
    border-top: 1px solid rgba(0, 0, 0, .1);
}
/* 單行加載提示組件的文本信息 */
.tt-loading-inline > .tt-loading-info{
    display: inline-block;
    padding: 0 .5rem;
    position: relative;
    top: -.7rem;
    height: 1rem;
    line-height: 1rem;
    font-size: .7rem;
    background: #fff;
}
/* 單行加載提示組件的圖標 */
.tt-loading-inline > .tt-loading-info > .tt-loading-icon{
    color: rgba(0, 0, 0, .2);
}

根據需求,在提示信息是上拉加載更多時,需要一個一直在上下振動的上箭頭。這個箭頭也是圖標庫裏有現成的,我們只需要讓它動起來就可以了。在實現效果之前,我們先來介紹一下 CSS3 中製作動畫用的 animation 屬性。

@Tips:
CSS3 中定義的 animation 屬性,可以允許用戶自己定義一些簡單的動畫效果。animation 的語法如下:

animation: name duration timing-function delay iteration-count direction;
animation 裏有很多個屬性,如果同學們仔細觀察的話,動畫裏的參數和 transition 屬性很相似。實際上,我們就可以把 animation 理解成更復雜的漸變效果。下面我們先來介紹下這幾個參數:
animation-name(動畫的名稱),這個參數是用來指定使用哪個效果的動畫,這裏的名稱是需要我們使用 @keyframes 定義出來的。我們先把 @keyframes 放一邊,等介紹完 animation 的屬性再來介紹這個東西。
animation-duration(動畫持續的時間),這個就和漸變屬性 transition 裏的 duration 一樣了,就是一輪動畫持續的時間。
animation-timing-function(時間函數),定義了動畫的播放速度曲線。
animation-delay(延遲時間),定義了動畫播放的延遲時間,表示多長時間以後再開始播放。
animation-iteration-count(循環次數),這個參數式之前沒見過的,它定義了動畫執行幾遍。這個值可以取正整數n,表示動畫會播放n遍後停止。如果需要動畫一直重複播放的話,把這個參數值設置成“infinite”就可以了。
animation-direction(動畫播放方向),這個參數定義了動畫播放的模式,它的取值可以是“normal”、“reverse”、“alternate”和“alternate-reverse”這四個值,默認的“normal”表示正常從前到後的播放;“reverse”表示動畫從後往前播放;“alternate”表示先從前往後播放,然後再從後往前到播放;“alternate-reverse”表示的就是先從後往前播放,再從前往後播放。

這些就是關於 animation 的屬性的介紹下來我們回到剛纔的 @keyframes 的用法。如果有細心的同學翻看過 Font Awesome 的源碼,看過 fa-spin 類的實現方法的話,就應該看過 @keyframes 的用法:
在這裏插入圖片描述
上面這種寫法和之前那種百分比的寫法效果是完全一樣的,只有在有多箇中間狀態時,百分比形式的寫法纔有意義。

瞭解了 animation 這個屬性後,就可以直接在圖標的文件中加入需求中要求的動畫效果了。

/* 垂直方向上振動 */
.fa-vibrate-y{
    animation: fa-vibrate-y 1.5s infinite ease-in;
}
/* 振動軌跡 */
@keyframes fa-vibrate-y{
    0% {
        transform: translateY(-10%);
    }
    50% {
        transform: translateY(10%);
    }
    100% {
        transform: translateY(-10%);
    }
}

Toast提示工具的樣式與開發

Toast提示組件的需求

我們對 Toast 組件有如下要求:

  • 彈窗在水平方向居中,豎直方向上在中間偏上的位置。
  • 彈窗包含一個圖標和一個提示信息,且背景半透明。
  • 在彈出時,有向上彈出的入場動畫,整個彈窗透明度逐漸升高。
  • 在消失時,有向下滑動的離場動畫,整個彈窗透明度逐漸降低。

Toast提示組件的設計與開發

    <body>
        <div class="tt-content">
            <h1 class="tt-panel-title">Toast提示組件</h1>
            <div class="tt-panel-body">
                <a class="tt-btn btn-primary" id="js-show-toast-loading">加載中提示</a>
                <br>
                <a class="tt-btn btn-primary" id="js-show-toast-success">成功提示</a>
            </div>
        </div>
        <div class="tt-toast" id="js-toast-loading">
            <i class="fa fa-spinner fa-spin tt-toast-icon"></i>
            <p class="tt-toast-info">操作進行中</p>
        </div>
        <div class="tt-toast" id="js-toast-success">
            <i class="fa fa-check tt-toast-icon"></i>
            <p class="tt-toast-info">操作成功</p>
        </div>
    </body>
/* Toast提示工具 */
.tt-toast{
    position: fixed;
    width: 7rem;
    top: 45%;
    transform: translateY(-40%);
    left: 0;
    right: 0;
    margin: auto;
    padding: 1rem 0;
    opacity: 0;
    color: #fff;
    text-align: center;
    background: rgba(0, 0, 0, .6);
    border-radius: .4rem;
    transition: transform .3s, opacity .3s;
    z-index: 301;
}
/* 顯示Toast組件 */
.tt-toast.show{
    opacity: 1;
    transform: translateY(-50%);
}
/* Toast組件中的圖標 */
.tt-toast > .tt-toast-icon{
    font-size: 2.2rem;
}
/* Toast組件中的文本部分 */
.tt-toast > .tt-toast-info{
    margin-top: .5rem;
    font-size: .7rem;
}

Toast 組件的樣式通過這四組樣式就可以實現了,這個樣式裏的技巧都是我們之前用過的。第 1、3、4 組樣式用來給Toast 添加靜態樣式,然後通過第 2 組 .tt-toast.show 的樣式來控制組件是否顯示。這裏和模態框組件唯一不同的就是這裏的顯示和隱藏使用的 opacity 屬性,而沒有用 display 屬性。這是因爲如果使用“display: none;”屬性,當“show“這個 class 一去掉,組件會立即消失,出場動畫就沒有辦法實現了。所以這個組件在使用的時候會分四步進行:

  • 需要顯示的時候會使用 JS 動態的把組件添加到文檔中。
  • 使用添加“show”這個 class,從而達到入場的效果。
  • Toast 組件需要消失的時候,去掉“show”這個 class,從而達到出場的效果。
  • 等組件完全消失後,再使用 JS 把整個 Toast 的 Dom 移除掉。

這樣做是因爲 Toast 是一個一次性的組件,不使用的時候不需要讓它停留在文檔中。這樣做還能避免當元素是“opacity: 0;”的時候會擋住底層內容區的操作。

Toast組件的效果演示

<script>
    window.onload = ()=>{
        // 顯示加載中的Toast
        document.querySelector('#js-show-toast-loading').onclick = (e) => {
            let toastEle = document.querySelector('#js-toast-loading');
            toastEle.classList.add('show');
            setTimeout(()=> {
                toastEle.classList.remove('show');
            }, 2e3);
        };
        // 顯示操作成功的Toast
        document.querySelector('#js-show-toast-success').onclick = (e) => {
            let toastEle = document.querySelector('#js-toast-success');
            toastEle.classList.add('show');
            setTimeout(()=> {
                toastEle.classList.remove('show');
            }, 2e3);
        };
    };
</script>

ActionSheet彈出式菜單組件的設計與開發

彈出式菜單組件的需求

這個組件的需求,一方面是菜單的靜態效果,另一方面是菜單的進場和離場的效果。

先來說下彈出式菜單的靜態效果:

  • 菜單分爲上中下三部分,頭部用來放菜單的說明。
  • 菜單頭部裏的文字在豎直方向上居中,最多兩行,超長的話自動截斷。
  • 菜單中間的部分是主要操作區,用來放菜單功能按鈕,多個按鈕用邊框隔開。
  • 菜單的尾部和主操作區留有一小段距離,裏面通常只放一個取消按鈕。
  • 菜單顯示的時候,固定在頁面的底部,且在菜單和頁面內容區之間用半透明蒙版隔開。
  • 菜單不顯示的時候,隱藏在頁面的最下面。

然後是菜單一些動態的樣式:

  • 菜單顯示的時候從底部向上滑出,底層的蒙版使用淡入的效果。
  • 菜單消失的時候,向下滑出屏幕,底層的蒙版使用淡出的效果。

彈出式菜單組件的設計與開發

<body>
        <div class="tt-content">
            <h1 class="tt-panel-title">ActionSheet彈出式菜單</h1>
            <div class="tt-panel-body">
                <a class="tt-btn" id="js-show">顯示彈出式菜單</a>
            </div>
        </div>
        <div class="tt-action-sheet">
            <div class="tt-mask"></div>
            <div class="tt-action-sheet-wrap">
                <div class="tt-action-sheet-header">
                    <h1 class="tt-action-sheet-title">你需要做什麼操作?</h1>
                </div>
                <div class="tt-action-sheet-body">
                    <a class="tt-action-sheet-menu">收藏</a>
                    <a class="tt-action-sheet-menu">關注</a>
                    <a class="tt-action-sheet-menu">分享給好友</a>
                </div>
                <div class="tt-action-sheet-footer">
                    <a class="tt-action-sheet-menu" id="js-close">取消</a>
                </div>
            </div>
        </div>
    </body>
/* 彈出菜單容器,默認隱藏在屏幕的下面 */
.tt-action-sheet > .tt-action-sheet-wrap{
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    max-width: 640px;
    margin: auto;
    background: #eee;
    transition: transform .3s ease;
    transform: translateY(100%);
    z-index: 301;
}
/* 菜單彈出的時候,改變容器位移 */
.tt-action-sheet.show .tt-action-sheet-wrap{
    transform: translateY(0);
}

在對容器的定位中,我們使用固定定位來安排菜單的位置,使用 bottom 值把菜單容器放在了頁面的最下面,然後默認情況下又通過 transfrorm 屬性把菜單向下移動了菜單高度,也就把菜單隱藏在了屏幕的下邊緣。當容器顯示的時候,再把位移值歸零,這樣容器就回到了頁面中。這個過程我們還是用了“transition: transform .3s ease;”屬性來添加菜單容器的入場和出場效果。

接下來要實現背景的控制,我們在做 Toast 提示組件的時候,是給元素設置了入場和出場動畫後把元素移除掉了。但是彈出菜單這個組件通常是藏在頁面下方,不會用的時候再加載,所以要讓它一直存在於 DOM 中。這樣就會造成一個問題,後面的蒙版層我們可以用透明度 opacity 屬性來實現淡入淡出效果。當淡出以後蒙版的透明度是 0,但這個元素還是遮蓋着後面的內容區的,導致內容區的操作不能進行。遇到這種情況,就要介紹一下“pointer-events”這個屬性了。

@ Tips:
pointer-events 這個屬性用來指定是否爲某個元素觸發鼠標點擊事件。這個屬性主要用於 SVG,但是在 HTML 中也是可以用的,只不過可以取的值只有“auto”和“none”這兩個,下來說下這兩個取值的含義;
auto,pointer-events 屬性默認的取值就是 auto,使用這個屬性值的情況下,HTML 元素就是正常的觸發點擊事件,通常只有爲了覆蓋不同取值的時候纔會使用這個值。
none,給元素用上這個屬性值的話,這個元素就變成點不中的了,無論這個元素是什麼樣式,點擊事件都會忽略它而去觸發它底層元素的點擊事件。

/* 默認隱藏蒙版 */
.tt-action-sheet > .tt-mask{
    opacity: 0;
    /* 屏蔽元素的點擊事件 */
    pointer-events: none;
    transition: opacity .3s ease;
}
/* 菜單彈出的時候顯示蒙版 */
.tt-action-sheet.show > .tt-mask{
    opacity: 1;
    pointer-events: auto;
}
/* 彈出菜單頭部 */
.tt-action-sheet .tt-action-sheet-header{
    padding: 0 2rem;
    display: flex;
    align-items: center;
    text-align: center;
    height: 3rem;
    background: #fff;
}
/* 頭部標題,用來描述菜單作用 */
.tt-action-sheet .tt-action-sheet-header > .tt-action-sheet-title{
    flex: 1;
    font-size: .7rem;
    line-height: 1rem;
    font-weight: normal;
    color: rgba(0, 0, 0, .3);
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
/* 中間主要內容區 */
.tt-action-sheet .tt-action-sheet-body{
    border-top: 1px solid rgba(0, 0, 0, .1);
    background: #fff;
}
/* 菜單尾部,通常用來放取消按鈕 */
.tt-action-sheet .tt-action-sheet-footer{
    margin-top: .3rem;
    background: #fff;
}
/* 每個菜單項 */
.tt-action-sheet .tt-action-sheet-menu{
    display: block;
    height: 2.8rem;
    line-height: 2.8rem;
    font-size: .8rem;
    text-align: center;
}
/* 菜單項的邊框控制 */
.tt-action-sheet .tt-action-sheet-menu + .tt-action-sheet-menu{
    display: block;
    border-top: 1px solid rgba(0, 0, 0, .1);
}

彈出式菜單的效果演示

    window.onload = ()=>{
        // 彈出菜單
        document.querySelector('#js-show').onclick = (e) => {
            document.querySelector('.tt-action-sheet').classList.add('show');
        }
        // 收回菜單
        document.querySelector('#js-close').onclick = (e) => {
            document.querySelector('.tt-action-sheet').classList.remove('show');
        }
    };

Article文本樣式的設計與開發

文本組件的需求

這個組件中包括文章標題、文章信息和文章內容這三大部分,其中文章內容裏會包含小標題、文本和圖片這幾個主要的元素。下來我們分析一下我們對這個文本組件的要求。

  • 標題部分使用大字號,文本加粗,其上下部分都留下一定的空間。
  • 文章信息部分主要用來展示文章的作者、創作時間等次要信息,所以通常會把這部分內容淡化,使用不太明顯的字體樣式。
  • 內容區的副標題要比正常文本的字體稍大,和前後留下一定得空間。
  • 內容區的文本段落部分留有適當的行距,且段落與段落之間留下一定的空間。
  • 內容區的圖片水平居中顯示,最大寬度不能超過內容區的寬度。
  • 在特殊情況下,需要將文本摺疊,以便顯示文本後面的其他內容
  • 當需要查看全文的時候可以點擊展開文章的按鈕來展開文章內容,這個按鈕我們用漸變色來實現.

文本組件的設計與開發

 <div class="tt-content">
            <div class="tt-article fold">
                <h1 class="tt-article-title">什麼是UI框架</h1>
                <p class="tt-article-info">作者:Rosen</p>
                <div class="tt-article-content">
                    <h2 class="tt-article-subtitle">UI是什麼?</h2>
                    <p class="tt-article-paragraph">先來說下UI,這倆字母是User Interface的縮寫,一般翻譯成“用戶界面”。UI最主要的功能就是建立用戶和系統後臺之間的聯繫,系統後臺通過UI把數據轉換成可視化的內容展示給用戶,同時用戶也要通過UI把操作指令(包括數據)傳給系統後臺。</p>
                    <p class="tt-article-paragraph">對UI不太熟悉的同學一聽到這個概念,可能會覺得它的作用就是怎麼把一個產品做的漂亮,所以UI設計師經常被人叫成美工。而事實上UI應該是負責“交互”和“視覺”這兩方面的工作,這兩部分內容構成了產品的用戶體驗。</p>
                    <p class="tt-article-paragraph">用戶體驗裏最重要的應該是這個產品好不好用,也就是“交互”這部分,這其中包括產品功能是否完善,產品流程是否設計的合理,使用是否方便,操作是否流暢等。在一些大公司裏,爲了保證產品好用,還會專門設置交互設計師這個職位,專門做交互部分的設計工作。</p>
                    <img class="tt-article-img" src="./img/modal-test.jpg" alt="測試圖片">
                </div>
                <div class="tt-article-unfold-btn" id="js-unfold">
                    <i class="fa fa-angle-double-down fa-vibrate-y"></i>
                </div>
            </div>
            <div class="tt-panel">
                <div class="tt-panel-title">其他內容</div>
                <div class="tt-panel-body">
                    其他內容...
                </div>
            </div>
        </div>
/* 文章組件 */
.tt-article{
    position: relative;
    padding: 1rem;
    margin-bottom: 1rem;
    font-size: .8rem;
    line-height: 1.6rem;
    background: #fff;
    border-bottom: 1px solid #eee;
    color: #333;
}
/* 文章被摺疊的情況 */
.tt-article.fold{
    max-height: 100%;
    overflow: hidden;
}

這個容器基礎樣式中就是邊距、邊框和字體的處理,然後在第二條樣式中使用 .fold 來控制容器的高度,從而達到隱藏多餘內容的目的。這裏我們把摺疊的時候的高度最高設置成100%,這樣屏幕稍微往下滑動一點就能看到文本的底邊了。這裏用的 max-height 而沒有用 height 是因爲當文本內容佔不滿整屏高度的話,也不會留出空白。

接下來我們實現按鈕的樣式,這個按鈕不是一般的按鈕樣式,而是一個帶有漸變效果的區域,點擊這個區域都可以達到展開文章的目的。這裏我們要先處理一下這個漸變的效果,下面要介紹一下background-img屬性裏“linear-gradient”這個屬性值的用法。

@ Tips:
linear-gradient是background-img屬性中可取的一個屬性值,也可以直接用於background屬性中。這個屬性值中包含三個主要信息:漸變的方向,漸變的顏色和漸變生效的位置。它完整的格式就是:

background: linear-gradient( angle/direction, color1 position1, color2 position2, …)
在這個結構中,第一個參數是漸變的方向,可以是一個角度值,也可以直接指明哪個方向;color的取值就是平時用的顏色值,position的取值是百分比,表示漸變色的起始或終止的位置。在這一節要實現的文本組件中,我們需要按鈕的背景色從透明向純白色漸變,就可以用如下樣式:

background: linear-gradient(180deg, rgba(255,255,255,0) 0, #fff 100%);
這樣就是豎直方向上,由上至下從白色透明漸變到白色不透明,也就達到了我們需要的樣式。

/* 展開按鈕 */
.tt-article .tt-article-unfold-btn{
    display: none;
    position: absolute;
    box-sizing: border-box;
    left: 0;
    right: 0;
    bottom: 0;
    height: 5rem;
    padding-top: 3rem;
    text-align: center;
    font-size: 1.5rem;
    color: #e0652f;
    background: linear-gradient(180deg, rgba(255,255,255,0) 0, #fff 100%);
}
/* 控制展開按鈕的顯示 */
.tt-article.fold .tt-article-unfold-btn{
    display: block;
}
/* 文章大標題 */
.tt-article .tt-article-title{
    margin: .5rem 0 1rem;
    font-size: 1.4rem;
    line-height: 2rem;
}
/* 文章信息,用來放作者、創作時間等 */
.tt-article .tt-article-info{
    font-size: .8rem;
    color: #aaa;
}
/* 文章小標題 */
.tt-article .tt-article-subtitle{
    font-size: 1.1rem;
    margin-top: 1rem;
}
/* 文章段落 */
.tt-article .tt-article-paragraph{
    margin: .5rem 0 1rem;
}
/* 文章圖片 */
.tt-article .tt-article-img{
    max-width: 100%;
    margin: auto;
}

文本組件的效果演示

    window.onload = ()=>{
        // 展開文章
        document.querySelector('#js-unfold').onclick = (e) => {
            document.querySelector('.tt-article').classList.remove('fold');
        }
    };
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章