<template>
<!--overflow:auto为超出tableDiv的宽高才显示滚动条,宽高可以是通过动态计算得到的 -->
<div id="tableDiv" style="width:500px; height:400px;overflow:auto;margin:0 auto;margin-top:50px;">
<!-- table必须加transform这个样式,否则垂直滚动的时候,会有问题 -->
<table style="transform-style:preserve-3d;">
<thead>
<tr>
<th style="width:50px">Num</th>
<th style="width:120px">Name</th>
<th style="width:100px">Age</th>
<th style="width:300px">Address</th>
<th style="width:50px">Opt</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>张三</td>
<td>10</td>
<td>这是一条很长很长很长很长很长很长很长很长的文字</td>
<td>
<a href="">编辑</a>
</td>
</tr>
.......
<tr>
<td>12</td>
<td>张三12</td>
<td>10</td>
<td>这是一条很长很长很长很长很长很长很长很长的文字</td>
<td>
<a href="">编辑</a>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
data () {
return {}
}
methods: {
// 因为要操作dom元素,在mounted中调用没问题,但是为避免在其他地方调用时dom还未加载,加个$nextTick()
this.$nextTick(() => {
fixtable () {
//这是外层div
var tableDiv = document.querySelector("#tableDiv");
//这是水平可滚动距离
var diff = tableDiv.scrollWidth - tableDiv.clientWidth;
//获取最后一列单元格,在这个例子里,最后一列是第5列
var lasts = tableDiv.querySelectorAll("tr td:nth-last-child(1),tr th:nth-last-child(1)");
//获取第一列列单元格
var firsts = tableDiv.querySelectorAll("tr td:nth-child(1),tr th:nth-child(1)");
//如果水平有滚动条,那一开始就需要让最后一列偏移
if (diff > 0) {
for (var i = 0; i < lasts.length; i++) {
lasts[i].style.transform = "translateX(-" + diff + "px)";
}
}
/*******固定的逻辑基本就下面这些*********/
var scroll_x = 0;
var scroll_y = 0;
tableDiv.addEventListener("scroll", function (e) {
//垂直滚动固定头
if (this.scrollTop != scroll_y) {
scroll_y = this.scrollTop;
this.querySelector("thead").style.transform = "translate3d(0," + this.scrollTop + "px,.1px)";
}
//水平滚动固定前两列和最后一列
if (this.scrollLeft != scroll_x) {
scroll_x = this.scrollLeft;
for (var i = 0; i < lasts.length; i++) {
lasts[i].style.transform = "translateX(-" + (diff - scroll_x) + "px)";
}
for (var i = 0; i < firsts.length; i++) {
firsts [i].style.transform = "translateX(" + scroll_x + "px)";
}
}
})
}
})
mounted() {
this.fixtable ()
}
}
}
</script>
<style>
table {
/*给table标签添加border-collapse: collapse属性,用于合并表格边框*/
border-collapse: collapse;
/*使用fixed实现th固定宽度,一般情况我们会让列宽自适应,可不设table-layout*/
table-layout: fixed;
/*在使用fixed的时候,必须指定width,否则还是自适应宽度*/
width: 100%;
border-spacing: 0;
}
th {
background: #888;
/*设个outline不然滚动会看着不协调*/
outline: 1px solid #333;
}
table th:nth-last-child(1){
background: #fff;
outline: 1px solid #333;
}
table th:nth-child(1){
background: #fff;
outline: 1px solid #333;
}
th,
td {
border: 1px solid #333;
background: #fff;
}
</style>
自己写的页面
<container-comm class="wrap contantBox">
<div class="table-box box fixedBox" id="table-box"
style="height:600px;overflow: auto;margin: 0;padding-top: 50px;"
>
<!-- 操作栏 -->
<div class="rows fixed" >
<btn-blue btnTxt="新增" styleCpt="margin-right:10px;" @click="addFn"/>
<btn-blue btnTxt="批量新增" styleCpt="margin-right:10px;" @click="batchAdd"/>
<btn-blue btnTxt="批量下载推荐报告" @click="filesUploadPL"/>
</div>
<table class="table">
<thead>
<tr>
<th style="width:30px;">
<img v-if="isSltAll" @click="applyId=[], isSltAll=false"
src="../../assets/img/fxk_ygx.png">
<img v-else @click="trSltHandler('',true,true)" src="../../assets/img/fxk_wgx.png">
</th>
<th style="width:120px;">研究员</th>
<th style="width:150px;">推荐时间</th>
<!-- <th>交易市场</th> -->
<th style="width:70px;">股票名称</th>
<th style="width:70px;">股票代码</th>
<th style="width:70px;">投资评级</th>
<th style="width:80px;">短期目标价</th>
<th style="width:80px;">长期目标价</th>
<th>推荐理由</th>
<th>短期操作建议</th>
<th>晨会汇报日期</th>
<th>推荐报告</th>
<th>终止推荐时间</th>
<th>终止推荐理由</th>
<th style="width:70px;">是否豁免</th>
<th style="width:260px;">操作</th>
</tr>
</thead>
<tbody>
<template v-if="dataList.length>0">
<tr v-for="(item,key) in dataList" :key="key" >
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
<img v-if="applyId.includes(item.id)" @click="trSltHandler(item,false)"
src="../../assets/img/fxk_ygx.png">
<img v-else @click="trSltHandler(item,true)" src="../../assets/img/fxk_wgx.png">
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.researcher}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.recommendDate}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.stockName}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.stockCode}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.investmentRate}}
</td>
<td :class="{'redTd':item.tpriceShortMark==true, 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.tpriceShort}}
</td>
<td :class="{'redTd':item.tpriceLongMark==true, 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.tpriceLong}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.recommendReason}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.operationSuggest}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.mornReportDate}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
<div class="downSpan" v-if="item.file" @click="fileApply(item.file.fileId)" style="width: 9rem !important;word-break: break-word;white-space: normal;padding: 0 !important;margin: 0 !important;border:none !important;">
<span>{{item.file.fileName?item.file.fileName:''}}</span>
</div>
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.stopDate}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.stopReason}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
{{item.isExempt=='0'?'否':'是'}}
</td>
<td :class="{ 'gray-row': item.stopStatus=='1'||item.stopStatus=='2'}">
<!-- <el-button size="mini" type="primary">修改</el-button>
<el-button size="mini" type="danger">终止</el-button>
<el-button size="mini" type="warning">操作记录</el-button> -->
<btn-blue v-if="item.stopStatus=='0'" btnTxt="修改" @click="editFn(item)"/>
<btn-blue
v-if="item.stopStatus=='0'"
style="background: #FF6600;border:.05rem solid #FF6600; margin:0 0.2rem;"
btnTxt="终止"
@click="stopFn(item)"
/>
<btn-blue btnTxt="操作记录" @click="recodeFn(item)"/>
<!-- v-if="item.stopStatus=='0'" -->
</td>
</tr>
</template>
</tbody>
</table>
<!-- 暂无数据 -->
<no-data v-if="!dataList.length" table/>
<!-- 分页 -->
<div class="rows flex-jf-center " style="margin-top: 20px" v-else>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPager"
:page-sizes="pageSizes"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="totalCount">
</el-pagination>
</div>
<!-- 滚动条 -->
<scorll-bar ref="scrollRef" id="table-box"/>
</div>
</container-comm>
css
.contantBox{
position: relative;
width:100vw;
height:100vh;
// overflow: hidden;
.fixedBox{
.fixed{
position: fixed;
top:321px;
left:16px;
z-index: 99;
}
}
.table{
position: relative;
table-layout: fixed;
width: 100%;
// 设置头部的所有单元格为粘性定位 以及其它属性
thead tr th {
position: sticky;
left: 0;
top: 0;
height: 30px;
min-width: 100px;
z-index: 2;
background-color: lightblue;
}
// 设置头部的第一个单元格
thead tr th:first-child {
z-index: 2;
// background-color: lightblue;
}
// 设置内容区的第一列单元格
tbody {
tr {
text-align: center;
}
tr td:first-child {
position: sticky;
left: 0;
z-index: 0;
height: 27px;
background-color: #ffffff;
}
td:not(:last-child){
overflow: hidden;
text-overflow: ellipsis;
min-width: 80px;
/*将对象作为弹性伸缩盒子模型显示*/
// display: -webkit-box;
/*限制文本行数*/
-webkit-line-clamp: 4;
white-space: pre-line; //不保留空白符序列,进行换行。
height: auto !important;
/*子元素的排列方式*/
-webkit-box-orient: vertical;
/*将对象作为弹性伸缩盒子模型显示*/
}
}
}
}