家好,今天我们将一起实践下如何手写固定表头,那么什么是固定表头呢?就类似 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小时内与您取得联系。