家好,今天我們將一起實踐下如何手寫固定表頭,那么什么是固定表頭呢?就類似 Excel 表格有個鎖定表頭的功能,方便用戶查閱數據進行數據項的對比。雖然有不少相關插件提供了類似的功能,比如 ScrollMagic.js,但是今天的實例,我們將用純原生的方式進行實現,當滾動條滾動至表格位置,固定表頭位置,表格內容查看完后,取消固定表頭的功能。
功能對比是一個很常用的功能,尤其是當網站服務越來越多時,就需要一個類似的功能,讓用戶能夠直觀的感受到各種服務的差異,幫助用戶選擇適合自己的方案。今天我們將通過一個界面十分漂亮功能價格對比的表格,展示固定表頭的功能,實例操作展示如視頻所示,當滾動條滾動至表格位置,添加表頭固定樣式,當滾動至表格底部,移除固定表頭樣式:
<script src="https://lf6-cdn-tos.bytescm.com/obj/cdn-static-resource/tt_player/tt.player.js?v=20160723"></script>
這篇案例我們是通過JS代碼,判斷滾動條的位置,動態添加和移除表頭的固定樣式(fix屬性),這里就需要運用幾個和位置相關 DOM API 才能順利完成本案例,相關 API 介紹如下所示:
1、Window pageXOffset 和 pageYOffset 屬性
pageXOffset 和 pageYOffset 屬性返回文檔在窗口左上角水平和垂直方向滾動的像素。
pageXOffset 設置或返回當前頁面相對于窗口顯示區左上角的 X 位置。pageYOffset 設置或返回當前頁面相對于窗口顯示區左上角的 Y 位置。
pageXOffset 和 pageYOffset 屬性相等于 scrollX 和 scrollY 屬性。
2、clientHeight、offsetHeight、scrollHeight、offsetTop、scrollTop
clientHeight:包括 padding 但不包括border、水平滾動條、margin的元素的高度。對于inline的元素這個屬性一直是0,單位px,只讀元素。
offsetHeight:包括padding、border、水平滾動條,但不包括margin的元素的高度。對于inline的元素這個屬性一直是0,單位px,只讀元素。
scrollHeight: 因為子元素比父元素高,父元素不想被子元素撐的一樣高就顯示出了滾動條,在滾動的過程中本元素有部分被隱藏了,scrollHeight代表包括當前不可見部分的元素的高度。而可見部分的高度其實就是clientHeight,也就是scrollHeight>=clientHeight恒成立。在有滾動條時討論scrollHeight才有意義,在沒有滾動條時scrollHeight==clientHeight恒成立。單位px,只讀元素。
scrollTop: 代表在有滾動條時,滾動條向下滾動的距離也就是元素頂部被遮住部分的高度。在沒有滾動條時scrollTop==0恒成立。單位px,可讀可設置。
offsetTop:當前元素頂部距離最近父元素頂部的距離,和有沒有滾動條沒有關系。單位px,只讀元素。
本部分內容摘自
https://imweb.io/topic/57c5409e808fd2fb204eef52
作者:IMWeb
吳浩麟
3、getBoundingClientRect
getBoundingClientRect 用于獲得頁面中某個元素的左,上,右和下分別相對瀏覽器視窗的位置。getBoundingClientRect是DOM元素到瀏覽器可視范圍的距離(不包含文檔卷起的部分)。
3.1、該函數返回一個Object對象,該對象有6個屬性:top,lef,right,bottom,width,height;
3.2、這里的top、left和css中的理解很相似,width、height是元素自身的寬高;
3.3、但是right,bottom和css中的理解有點不一樣。right是指元素右邊界距窗口最左邊的距離,bottom是指元素下邊界距窗口最上面的距離。
本部分內容摘自:
https://juejin.im/entry/59c1fd23f265da06594316a9
作者:左鵬飛
1、創建三個基礎的 sections 的區域
<section>...</section>
<section>...</section>
<section>...</section>
第一部分為頁面標題內容,第三部分為內容介紹區域,這兩部分非核心內容,只是用于內容占位,方便第二部分表格區域的展示,滾動此區域表頭固定。
2、表格內容結構
我們將第二部分的表格放置在 container 的容器內,方便我們做響應式相關的設置,表格基礎結構的內容如下:
<div class="container">
<div class="table-wrapper">
<table>
<thead>
<tr>
<th>...</th>
<th>...</th>
<th>...</th>
<th>...</th>
</tr>
</thead>
<tbody>
<tr>
<td>...</td>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
<!-- more rows here -->
</tbody>
</table>
</div>
</div>
該表格包含4列,代表產品服務的對比項目和服務的級別,服務級別包含:入門級,基礎級和專業級。
3、表頭內容結構
表頭部分應該很清楚的展示服務項目的介紹,讓用戶有購買服務計劃的沖動,界面展示如下所示:
相關的 HTML 結構如下所示:
<tr>
<th>
<div>
Select your plan
<div class="svg-wrapper">
<svg viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm1 17v-4h-8v-2h8v-4l6 5-6 5z"/></svg>
</div>
</div>
</th>
<th>
<div class="heading">...</div>
<div class="info">
<div class="amount">...</div>
<div class="billing-msg">...</div>
<button type="button">...</button>
</div>
</th>
<th>
<div class="heading">...</div>
<div class="info">
<div class="popular">...</div>
<div class="amount">...</div>
<div class="billing-msg">...</div>
<button type="button">...</button>
</div>
</th>
<th>
<div class="heading">...</div>
<div class="info">
<div class="amount">...</div>
<div class="billing-msg">...</div>
<button type="button">...</button>
</div>
</th>
</tr>
4、表格相關的行
每行內容描述服務內容中相關的功能是否能用,這里用 SVG圖標(對號,叉號)進行直觀展示,界面展示如下圖所示:
相關的 HTML 結構如下所示:
<tr>
<td>...</td>
<td>
<svg class="starter" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z"/></svg>
</td>
<td>
<svg class="essential" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z"/></svg>
</td>
<td>
<svg class="professional" viewBox="0 0 24 24"><path d="M12 0c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.959 17l-4.5-4.319 1.395-1.435 3.08 2.937 7.021-7.183 1.422 1.409-8.418 8.591z"/></svg>
</td>
</tr>
1、定義基礎樣式
HTML結構準備好后,接下來我們定義相關基礎的 CSS 樣式,比如定義 CSS 自定義變量和常見的重置樣式,示例代碼如下:
:root {
--white: white;
--gray: #999;
--lightgray: whitesmoke;
--popular: #ffdd40;
--starter: #f73859;
--essential: #00AEEF;
--professional: #FF7F45;
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
button {
background: none;
border: none;
cursor: pointer;
}
table {
border-collapse: collapse;
}
body {
font: 18px/1.5 'Noto Sans', sans-serif;
background: var(--lightgray);
}
由于文章篇幅有限,這里不會將所有的 CSS 代碼進行羅列,這里只介紹最核心的樣式內容。
2、定義表格樣式
首先定義表格最大寬度,然后讓其水平居中:
.container {
max-width: 850px;
padding: 0 10px;
margin: 0 auto;
}
table {
width: 100%;
}
接下來讓行的容器為 flex 彈性盒子布局
table tr {
display: flex;
}
然后讓每列保持相同寬度,示例代碼如下:
table th,
table td {
width: 25%;
min-width: 150px;
}
最后為了讓單元格區域便于識別,我們用灰色邊框進行區分,示例代碼如下:
--lightgray: whitesmoke;
table th .info,
table td:not(:first-child) {
border-left: 1px solid var(--lightgray);
}
HTML結構和CSS完成后,接下來我們編寫腳本固定表頭。
1、定義DOM變量
首先我們先定義一些關鍵DOM元素的變量,比如獲取表格、表頭等元素,示例代碼如下:
const body=document.body;
const firstSection=document.querySelector("section:nth-child(1)");
const lastSection=document.querySelector("section:nth-child(3)");
const table=document.querySelector("table");
const thead=document.querySelector("table thead");
const mq=window.matchMedia("(min-width: 780px)");
const stickyClass="sticky-table";
const sticky2Class="sticky2-table";
2、獲取一些元素相關的值
基于這些我們定義相關的變量,獲取相關的值:
let tableWidth=table.offsetWidth;
let tableOffsetTop=table.getBoundingClientRect().top;
let theadHeight=thead.offsetHeight;
你可能注意到了這里我們使用 let 定義變量,之所以用 let ,我們改變窗口的大小,這些相關的值也會發生變化,需要進行動態更新。
3、編寫滾動的相關邏輯
每次我們滾動時,就會執行我們定義的 scrollHandler 函數,我們這個函數只會在窗口寬度大于 780px 才會執行固定表頭的邏輯,小屏設備則沒有相關效果。
基于以上邏輯我們實現相關的代碼邏輯:
window.addEventListener("scroll", scrollHandler);
function scrollHandler() {
if (mq.matches) {
// 1
const scrollY=window.pageYOffset;
// 2
const lastSectionOffsetTop=lastSection.getBoundingClientRect().top;
// 3
if (scrollY >=tableOffsetTop) {
// 4
thead.style.width=`${tableWidth}px`;
// 5
if (lastSectionOffsetTop > theadHeight) {
// 6
body.classList.remove(sticky2Class);
body.classList.add(stickyClass);
thead.style.top=0;
body.style.paddingTop=`${theadHeight}px`;
} else {
// 7
body.classList.remove(stickyClass);
body.classList.add(sticky2Class);
thead.style.top=`calc(100% - ${theadHeight}px)`;
}
} else {
// 8
body.classList.remove(stickyClass, sticky2Class);
body.style.paddingTop=0;
thead.style.width="100%";
thead.style.top="auto";
}
}
}
編寫相關的樣式代碼,stickyClass 和 sticky2-table 控制表頭的固定和取消表頭的固定
table thead {
transition: box-shadow 0.2s;
}
.sticky-table table thead {
position: fixed;
left: 50%;
transform: translateX(-50%);
}
.sticky-table table thead {
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.12);
}
.sticky2-table table thead {
position: absolute;
left: 0;
}
由于窗口大小并非固定,我們會經常會拖動或調整窗口的大小,因此相關元素的寬度和視口高度都要重新計算,這里我們需要添加 resize 事件進行監聽,示例代碼如下:
window.addEventListener("resize", resizeHandler);
function resizeHandler() {
if (mq.matches) {
tableWidth=firstSection.offsetHeight;
tableOffsetTop=table.offsetTop;
theadHeight=thead.offsetHeight;
} else {
body.classList.remove(stickyClass, sticky2Class);
body.style.paddingTop=0;
thead.style.width="100%";
thead.style.top="auto";
}
}
最終的效果體驗,大家可以點擊文末 了解更多 鏈接進行體驗(手機橫屏體驗),由于文章篇幅有限,完整的源碼大家可以私信“表頭”獲取源碼鏈接。
到此,我們一起完成了這個案例,通過本案例,我們學會了如何使用原生的方式動態實現固定元素,并在一定的時機取消固定。感謝你的閱讀,如果你喜歡我的分享,麻煩給個關注、點贊加轉發哦,你的支持,就是我分享的動力,后續會持續分享更實用的案例,歡迎持續關注。
文章來源:
作者:George Martsoukos
網站:tutsplus
非直譯
動手練一練,用 CSS Checkbox Hack 技術制作一個響應式圖片幻燈
動手練一練,做一個現代化、響應式的后臺管理首頁
動手練一練,使用 Flexbox 創建一個響應式的表單
動手練一練,用純 CSS 制作一款側滑顯示留言面板的網頁組件
使用 Vanilla JavaScript 框架創建一個簡單的天氣應用
使用 CSS Checkbox Hack 技術制作一個手風琴組件
lt;thead>標簽定義HTML中<table>元素的標題;
<thead>標簽與<tbody>和<tfoot>標簽一起使用,它們定義HTML表格中的表頭,表主體和表腳。
<thead>標簽作為<table>標簽的子元素,需出現在<caption>、<colgroup>元素之后;<tbody>,<tr>或<tfoot>元素之前。
<thead>標記內應至少包含一行<tr>元素。
提示:<thead>、<tbody>和<tfoot>元素默認不會影響表格的布局。不過可以使用CSS來為這些元素定義樣式,從而改變表格的外觀。
<thead>
<tr>……</tr>
<thead>
<table border="1">
<caption>圖書大廈書目價格單</caption>
<thead>
<tr>
<th>書名</th>
<th>單價</th>
</tr>
</thead>
<tr>
<td>HTML入門教程</td>
<td>79.00元</td>
</tr>
<tr>
<td>JavaScript基礎教程</td>
<td>46.00元</td>
</tr>
<tr>
<td>Python精品教程</td>
<td>99.00元</td>
</tr>
</table> 123456789101112131415161718192021復制代碼類型:[html]
圖書大廈書目價格單 | |
書名 | 單價 |
HTML入門教程 | 79.00元 |
JavaScript基礎教程 | 46.00元 |
Python精品教程 | 99.00元 |
在HTML5中,不再支持HTML4.01中<thead>標簽的任何屬性。
所有主流瀏覽器都支持<thead>標簽。
屬性 | 值 | 描述 |
align | right | HTML5 不支持。定義 <thead> 元素中內容的對齊方式。 |
char | character | HTML5 不支持。規定 <thead> 元素中內容根據哪個字符來對進行文本對齊。 |
charoff | number | HTML5 不支持。規定 <thead> 元素中內容的第一個對齊字符的偏移量。 |
valign | top | HTML5 不支持。規定 <thead> 元素中內容的垂直對齊方式。 |
<thead>標簽支持HTML的全局屬性。
<thead>標簽支持HTML的事件屬性。
開課吧廣場-人才學習交流平臺
emo代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>el-table動態表頭</title>
<link rel="stylesheet" type="text/css" href="./lib/element-ui/theme-chalk/index.css" />
</head>
<body>
<div id="app">
<el-table
:data="tableBody"
:header-cell-style="{ background: '#F3F4F7' }"
:header-row-style="{ fontWeight: 500, color: '#909399' }"
>
<el-table-column align="center" :label="tableHeadItem" v-for="(tableHeadItem, idx) in tableHead" :key="idx">
<template scope="scope">
<i class="el-icon-platform-eleme" style="font-size: 16px"></i>
{{tableBody[scope.$index][idx]}}
</template>
</el-table-column>
</el-table>
</div>
<script src="./lib/vue/vue.js"></script>
<script src="./lib/element-ui/index.js"></script>
<script type="text/javascript">
new Vue({
el: "#app",
data() {
return {
res: [
{
NAME: "王二",
VALUE: 1,
SEX: 2,
},
{
NAME: "張三",
VALUE: 1,
SEX: 1,
},
{
NAME: "李四",
VALUE: 2,
SEX: 1,
},
],
tableBody: [],
tableHead: [],
};
},
created() {
this.tableHead=Object.keys(this.res[0]); // 表頭 [ "NAME", "VALUE", "SEX" ]
this.res.forEach((item)=> {
this.tableBody.push(Object.values(item)); // 表體 [ ["王二", 1, 2], ["張三", 1, 1], ["李四", 2, 1] ]
});
},
});
</script>
</body>
</html>
動態表格是生成列,也就是每一個<el-table-column>然后再根據所有列去遍歷生成行,這樣一個過程,知道這些,要做的就是根據這么一個過程去生成這樣一個數據格式就行了。
實現動態表格的延伸:
element-ui官方推薦的CDN引入使用element的任務組件都是沒有問題的,但是如果將樣式和組件庫代碼下載下來改為本地引入,icon組件將不能使用!
CDN引入:
<!-- 引入樣式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入組件庫 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
請求資源:
請求的網絡資源中多了一個element-icons.woff文件,原因:查看element中index.css中的icon的引入方式。
@font-face {
font-family: element-icons;
src: url(fonts/element-icons.woff) format("woff"), url(fonts/element-icons.ttf) format("truetype");
font-weight: 400;
font-display: "auto";
font-style: normal;
}
解決方法:
復制字體圖標資源鏈接下載下來,然后在element的index.css文件夾同級目錄中新建fonts文件夾放入下載好的element-icons.woff和element-icons.ttf字體圖標文件。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。