Как правильно сделать таблицу vue cli
Использую vue2 cli. Есть таблица. Начала делать ее на плагине vue-tables-2, но уже думаю что без плагина нужно крутится. Проблемы таблицы заключается в том, что tbody имеет кастомный скрол. Немного подумав сделала thead position stiky и через calc вычитала высоту и top что бы скрол не наползал на шапку. Но так же требуется, что бы шапка не обрезалась, а уходила в право, так что бы было видно что там что то есть, а вот боди должно быть обрезано. При чем при скроле все скролится вместе(по горизонтали имею в виду). Прошу подсказать, нужно делить теперче на две таблицы шапка и боди?, тк в таблицу невозможно впихнуть кастомный скролл. Или же есть плагин который позволяет вертеть tbody по вертикали, а по горизонтали tbody и thead не используя позиционирования. На просторах интернета искала, но не нахожу ничего подходящего. Может у кого был опыт в таких таблицах. То что имею сейчас - https://codepen.io/KatushaSan/pen/wvjzYae
Vue.use(VueTables.ClientTable);
Vue.use(vuescroll);
function getData() {
return [
{
modal: 'что то',
checkedId: 'check1',
date: '85.12.3021',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то'
},
{
modal: 'что то',
checkedId: 'check1',
date: '85.12.3021',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то'
},{
modal: 'что то',
checkedId: 'check1',
date: '85.12.3021',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то'
},{
modal: 'что то',
checkedId: 'check1',
date: '85.12.3021',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то'
},{
modal: 'что то',
checkedId: 'check1',
date: '85.12.3021',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то'
},{
modal: 'что то',
checkedId: 'check1',
date: '85.12.3021',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то'
},{
modal: 'что то',
checkedId: 'check1',
date: '85.12.3021',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то'
}
]
}
const BaseTable = new Vue({
el: "#baseTable",
data() {
return {
dataEl: getData(),
ops: {
scrollPanel: {
initialScrollX: 1,
initialScrollY: 1,
},
},
columns: [
'choice',
'status',
'modal',
'dateTime',
'fio',
'floor',
'dateBeathdey',
'area',
'research',
'idPacient',
'quality',
'AETitle',
'direction',
'registrationNumber',
'priority',
'institution',
'appointed',
'nameProtokol',
],
filterable: [
'choice',
'status',
'modal',
'dateTime',
'fio',
'floor',
'dateBeathdey',
'area',
'research',
'idPacient',
'quality',
'AETitle',
'direction',
'registrationNumber',
'priority',
'institution',
'appointed',
'nameProtokol',
],
options: {
headings: {
status: 'что то',
modal: 'что то',
dateTime: 'что то',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то',
},
sortable: [
'status',
'modal',
'dateTime',
'fio',
'floor',
'dateBeathdey',
'area',
'research',
'idPacient',
'quality',
'AETitle',
'direction',
'registrationNumber',
'priority',
'institution',
'appointed',
'nameProtokol',
]
},
}
}
});
.table {
border-collapse: collapse;
background: black;
font-size: calc(100vw * 19/834);
line-height: calc(100vw * 31/834);
letter-spacing: -0.015em;
color: #fff;
width: 100%;
overflow: auto!important;
}
.table thead th{
border-right: 2px solid #3E5266;
}
.VueTables thead tr {
border-bottom: 2px solid #3E5266;
position: relative;
z-index: 1;
background: #597A95;
}
.VueTables thead th {
font-family: 'Inter-SemiBold';
background: linear-gradient(180deg, #3E523F 0%, rgba(67, 91, 114, 0.00520833) 260.84%, #234636 260.87%);
}
.table thead th:last-child {
border-right: none;
}
.VueTables {
border-collapse: collapse;
}
.VueTables th {
white-space: nowrap;
font-weight: normal;
}
.table__edit-img {
padding: 0;
width: calc(100vw * 30/834);
height: calc(100vw * 30/834);
vertical-align: middle;
}
.table__edit-img img {
width: 100%;
height: 100%;
object-fit: cover;
}
.VueTables thead {
z-index: 1;
position: sticky;
top: 0;
}
.VueTables thead th:first-child {
padding-left: calc((100vw - 320px) / (1024 - 320) * (7 - 2) + 2px);
padding-right: calc((100vw - 320px) / (1024 - 320) * (7 - 2) + 2px);
line-height: 0;
}
.VueTables__sortable {
padding: calc(100vw * 5/834) calc(100vw * 6/834);
cursor: pointer;
}
.VueTables__heading {
display: inline-block;
vertical-align: middle;
}
.VueTables__sortable::before {
content: '';
position: absolute;
bottom: 4px;
left: 4px;
background-image: url('../images/marker-sort.svg');
background-repeat: no-repeat;
background-size: contain;
width: calc((100vw - 1024px) / (2560 - 1024) * (18 - 12) + 12px);
height: calc((100vw - 1024px) / (2560 - 1024) * (10 - 8) + 8px);
opacity: 0;
transition: opacity 0.3s;
}
.VueTables__sortable[class*="-sorted-asc"] .table__wrap-sort,
.VueTables__sortable[class*="-sorted-desc"] .table__wrap-sort,
.VueTables__sortable[class*="-sorted-asc"]::before,
.VueTables__sortable[class*="-sorted-desc"]::before {
opacity: 1;
}
.VueTables__sortable[class*="-sorted-asc"] .table__wrap-sort .arrow-up {
fill: #D9D9D9;
}
.VueTables__sortable[class*="-sorted-desc"] .table__wrap-sort .arrow-down {
fill: #D9D9D9;
}
.VueTables td {
padding-left: calc((100vw - 320px) / (1024 - 320) * (4 - 2) + 2px);
padding-right: calc((100vw - 320px) / (1024 - 320) * (4 - 2) + 2px);
text-align: center;
border-right: 2px solid #3E5266;
white-space: nowrap;
height: calc((100vw - 1024px) / (1440 - 1024) * (28 - 24) + 24px);
line-height: calc((100vw - 1024px) / (1440 - 1024) * (28 - 23) + 23px);
padding: calc(100vw * 4/834) calc(100vw * 6/834);
}
.VueTables tbody tr:nth-child(odd) {
background: #6B6D8A;
}
.VueTables tbody tr.active {
background: rgba(255, 147, 80, 0.45);
}
.VueTables--client>.row:first-of-type {
display: none;
}
.VuePagination__pagination {
display: flex;
align-items: center;
}
.VuePagination__pagination-item {
list-style: none;
}
.VuePagination {
display: none;
}
.bottom-table {
width: calc((100vw - 1440px) / (2560 - 1440) * (383 - 340) + 340px);
}
.wrap-table {
position: relative;
overflow: hidden;
border-radius: 0px 0px 4px 4px;
border: 2px solid #3E5266;
/* border-bottom: none; */
height: 100%;
}
.table__wrap-sort {
display: flex;
position: absolute;
width: calc((100vw - 320px) / (1024 - 320) * (19 - 13) + 13px);
height: calc((100vw - 320px) / (1024 - 320) * (16 - 10) + 10px);
top: 50%;
transform: translateY(-50%);
right: 2px;
opacity: 0;
transition: opacity 0.3s;
}
.table__wrap-sort svg {
width: 100%;
height: 100%;
}
.table__wrap-sort .arrow-down,
.table__wrap-sort .arrow-up {
transition: fill 0.3s;
}
.VueTables tr td:last-child {
border-right: none;
}
.table-characteristics thead {
display: none;
}
.table-characteristics.VueTables td {
text-align: left;
}
.__vuescroll.hasHBar .VueTables {
padding-bottom: calc(100vw * 22/834);
}
.table__wrap-sort {
width: calc((100vw - 1024px) / (2560 - 1004) * (19 - 12) + 12px);
height: calc((100vw - 1024px) / (2560 - 1004) * (19 - 12) + 12px);
}
.table__status-item {
width: calc(100vw * 20/834);
height: calc(100vw * 20/834);
margin-right: calc(100vw * 5/834);
padding: 0;
}
.table__status-item:last-child {
margin-right: 0;
}
.table__status-item img {
width: 100%;
height: 100%;
object-fit: contain;
}
.table__status {
display: flex;
align-items: center;
}
.table__status-color {
border-radius: 50%;
background: #fff;
border: 2px solid #D9D9D9;
height: 100%;
}
.table__status-color[data-color="green"] {
background: #54EE51;
}
.table__status-color[data-color="red"] {
background: red;
}
.table__status-color[data-color="black"] {
background: black;
}
@media (min-width: 1024px) {
.table {
font-size: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);
line-height: calc((100vw - 1024px) / (1440 - 1024) * (32 - 26) + 26px);
}
.VueTables td {
padding-left: calc((100vw - 1024px) / (1024 - 320) * (6 - 4) + 4px);
padding-right: calc((100vw - 1024px) / (1024 - 320) * (6 - 4) + 4px);
}
.VueTables thead th:first-child {
padding-left: calc((100vw - 1024px) / (1440 - 1024) * (10 - 7) + 7px);
padding-right: calc((100vw - 1024px) / (1440 - 1024) * (10 - 7) + 7px);
}
.table__status-item {
width: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);
height: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);
margin-right: 5px;
}
.table__check label {
width: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);
height: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);
}
.table__check label::before {
transform: translateY(-50%) translateX(-50%);
width: calc((100vw - 1024px) / (1440 - 1024) * (8 - 6) + 6px);
height: calc((100vw - 1024px) / (1440 - 1024) * (8 - 6) + 6px);
}
.__vuescroll.hasHBar .VueTables {
padding-bottom: calc((100vw - 1024px) / (1440 - 1024) * (24 - 20) + 20px);
}
.VueTables__sortable {
padding-left: calc((100vw - 1024px) / (1440 - 1024) * (28 - 17) + 24px);
padding-right: calc((100vw - 1024px) / (1440 - 1024) * (28 - 17) + 24px);
padding-top: calc((100vw - 1024px) / (1440 - 1024) * (7 - 4) + 4px);
padding-bottom: calc((100vw - 1024px) / (1440 - 1024) * (7 - 4) + 4px);
cursor: pointer;
}
.table__edit-img {
width: calc((100vw - 1024px) / (1440 - 1024) * (28 - 22) + 22px);
height: calc((100vw - 1024px) / (1440 - 1024) * (28 - 22) + 22px);
}
}
@media (min-width: 1440px) {
.VueTables__sortable {
padding-left: 31px;
padding-right: 31px;
padding-top: 5px;
}
.VueTables thead th:first-child {
padding-left: 10px;
padding-right: 10px;
}
.VueTables td {
padding-left: 6px;
padding-right: 6px;
height: 28px;
}
.table__edit-img {
width: 28px;
height: 28px;
}
.vuetable th,
.vuetable td {
padding-left: 6px;
padding-right: 6px;
}
.table {
font-size: 20px;
line-height: 32px;
}
.__vuescroll.hasHBar .VueTables {
padding-bottom: calc((100vw - 1440px) / (1920 - 1440) * (20 - 24) + 24px);
}
/* checkbox */
.table__check label {
width: 20px;
height: 20px;
}
.table__check label::before {
width: 8px;
height: 8px;
}
/* end checkbox */
/* status icon */
.table__status-item {
width: 20px;
height: 20px;
}
/* end status icon */
}
@media screen and (min-width: 1920px) {
.VueTables__sortable {
padding-top: calc((100vw - 1920px) / (2560 - 1920) * (6 - 5) + 5px);
padding-bottom: calc((100vw - 1920px) / (2560 - 1920) * (6 - 5) + 5px);
}
.table__edit-img {
width: calc((100vw - 1920px) / (3840 - 1920) * (36 - 28) + 28px);
height: calc((100vw - 1920px) / (3840 - 1920) * (36 - 28) + 28px);
}
.vuetable th,
.vuetable td {
padding-left: calc((100vw - 1920px) / (3840 - 1920) * (10 - 6) + 6px);
padding-right: calc((100vw - 1920px) / (3840 - 1920) * (10 - 6) + 6px);
}
.table {
font-size: calc((100vw - 1920px) / (2560 - 1920) * (22 - 20) + 20px);
line-height: calc((100vw - 1920px) / (2560 - 1920) * (36 - 32) + 32px);
}
.__vuescroll.hasHBar .VueTables {
padding-bottom: calc((100vw - 1920px) / (2560 - 1920) * (27 - 20) + 20px);
}
.VueTables td {
height: calc((100vw - 1920px) / (2560 - 1920) * (31 - 28) + 28px);
}
/* checkbox */
.table__check label {
width: calc((100vw - 1920px) / (3840 - 1920) * (26 - 20) + 20px);
height: calc((100vw - 1920px) / (3840 - 1920) * (26 - 20) + 20px);
}
.table__check label::before {
width: calc((100vw - 1920px) / (3840 - 1920) * (11 - 8) + 8px);
height: calc((100vw - 1920px) / (3840 - 1920) * (11 - 8) + 8px);
}
/* end checkbox */
/* status icon */
.table__status-item {
width: calc((100vw - 1920px) / (2560 - 1920) * (32 - 28) + 28px);
height: calc((100vw - 1920px) / (2560 - 1920) * (32 - 28) + 28px);
}
/* end status icon */
}
@media (min-width: 2560px) {
.table {
font-size: calc((100vw - 2560px) / (3840 - 2560) * (24 - 22) + 22px);
line-height: calc((100vw - 2560px) / (3840 - 2560) * (39 - 36) + 36px);
}
.VueTables td {
padding-left: calc((100vw - 2560px) / (3840 - 2560) * (10 - 6) + 6px);
padding-right: calc((100vw - 2560px) / (3840 - 2560) * (10 - 6) + 6px);
padding-bottom: calc((100vw - 2560px) / (3840 - 2560) * (8 - 4) + 4px);
padding-top: calc((100vw - 2560px) / (3840 - 2560) * (5 - 4) + 4px);
}
.VueTables__sortable {
padding-top: calc((100vw - 2560px) / (3840 - 2560) * (9 - 6) + 6px);
padding-bottom: calc((100vw - 2560px) / (3840 - 2560) * (9 - 6) + 6px);
padding-left: calc((100vw - 2560px) / (3840 - 2560) * (37 - 35) + 35px);
padding-right: calc((100vw - 2560px) / (3840 - 2560) * (37 - 35) + 35px);
}
.VueTables thead th:first-child {
padding-left: calc((100vw - 1024px) / (1440 - 1024) * (12 - 10) + 10px);
padding-right: calc((100vw - 1024px) / (1440 - 1024) * (12 - 10) + 10px);
}
.table__wrap-sort {
width: calc((100vw - 1920px) / (2560 - 1920) * (23 - 19) + 19px);
height: calc((100vw - 1920px) / (2560 - 1920) * (20 - 16) + 16px);
}
.__vuescroll.hasHBar .VueTables {
padding-bottom: calc((100vw - 2560px) / (3840 - 2560) * (32 - 27) + 27px);
}
.VueTables td {
height: calc((100vw - 2560px) / (3840 - 2560) * (39 - 31) + 31px);
}
/* status icon */
.table__status-item {
width: calc((100vw - 2560px) / (3840 - 2560) * (37 - 32) + 32px);
height: calc((100vw - 2560px) / (3840 - 2560) * (37 - 32) + 32px);
}
/* end status icon */
}
.__rail-is-horizontal {
display: flex;
align-items: center;
background: #3E5266!important;
height: calc(100vw * 24/834)!important;
border-radius: 0!important;
bottom: -2px!important;
width: 100%;
}
.__rail-is-vertical {
height: 100%;
background: #3E5266!important;
border-radius: 0!important;
width: calc(100vw * 24/834)!important;
right: -2px!important;
display: flex;
justify-content: center;
height: 100%;
}
/* .mouseEnter .__rail-is-vertical {
opacity: 1;
} */
.__bar-wrap-is-horizontal {
background: #3D607E;
border-radius: 12px!important;
height: calc(100vw * 20/834)!important;
}
.__bar-wrap-is-vertical {
background: #3D607E;
border-radius: 12px!important;
width: calc(100vw * 20/834)!important;
}
.__bar-is-horizontal {
opacity: 1!important;
background: #8495A2!important;
border-radius: 12px!important;
height: 100%!important;
}
.__bar-is-vertical {
opacity: 1!important;
background: #8495A2!important;
border-radius: 12px!important;
width: 100%!important;
}
.scroll-tabs .__rail-is-horizontal {
width: 100%;
margin: 0!important;
bottom: -2px!important;
}
/* .__vuescroll.hasVBar.hasHBar .__rail-is-vertical {
height: calc(100% - (100vw * 42/834));
top: calc(100vw * 42/834)!important;
} */
.__vuescroll.hasVBar.hasHBar .__bar-wrap-is-vertical {
height: calc(100% - calc((100vw - 1024px) / (1440 - 1024) * (27 - 22) + 22px));
}
.__vuescroll.hasVBar.hasHBar .__bar-wrap-is-horizontal {
width: calc(100% - (100vw * 40/834));
}
@media screen and (min-width: 1024px) {
.__rail-is-horizontal {
height: calc((100vw - 1024px) / (1440 - 1024) * (24 - 20) + 20px)!important;
}
.__rail-is-vertical {
width: calc((100vw - 1024px) / (1440 - 1024) * (24 - 20) + 20px)!important;
}
.__bar-wrap-is-horizontal {
height: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px)!important;
}
.__vuescroll.hasVBar.hasHBar .__bar-wrap-is-horizontal {
width: calc(100% - calc((100vw - 1024px) / (1440 - 1024) * (27 - 20) + 20px));
}
.__bar-wrap-is-vertical {
width: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px)!important;
}
}
@media screen and (min-width: 1440px) {
.__rail-is-horizontal {
height: 24px!important;
}
.__rail-is-vertical {
width: 24px!important;
}
.__bar-wrap-is-horizontal {
height: 20px!important;
}
.__bar-wrap-is-vertical {
width: 20px!important;
}
}
.wrap-table {
height: 200px;
}
<!DOCTYPE html>
<html lang="en" {IF CLASSES}class="classes"{/IF}>
<head>
<meta charset="UTF-8">
</head>
<body>
<div class="wrap-table wrap-table--main" id="baseTable">
<vue-scroll class="scroll-table" :initialScrollY="true" :ops="ops">
<v-client-table
:columns="columns"
:data="dataEl"
:options="options"
:show-sort-icons="true"
class="table-main"
:filter="false"
>
<div
v-for="(column, index) in columns"
:key="'column'+index"
:slot="`h__${column}`"
class="bin"
>
<span v-if="index !== 0" v-html="options.headings[column]"></span>
<span v-if="index !== 0" class="table__wrap-sort">
<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 15.7 16" enable-background="new 0 0 15.7 16" xml:space="preserve">
<path class="arrow-down" fill="#808e9b" d="M14.2,8.6H1.5c-0.7,0-1.2,0.4-1.4,1s0,1.3,0.6,1.7L7,15.7C7.2,15.9,7.5,16,7.8,16s0.6-0.1,0.9-0.3l6.3-4.5 c0.5-0.4,0.8-1,0.6-1.7C15.4,9,14.8,8.6,14.2,8.6z"/>
<path class="arrow-up" fill="#808e9b" d="M1.5,7.4h12.7c0.7,0,1.2-0.4,1.4-1c0.2-0.6,0-1.3-0.6-1.7L8.7,0.3C8.2-0.1,7.5-0.1,7,0.3L0.6,4.8 c-0.5,0.4-0.8,1-0.6,1.7S0.8,7.4,1.5,7.4z"/>
</svg>
</span>
</div>
<template slot="h__choice">
<button class="table__edit-img" @click="updateTable">
<img :src="imgUpdate" alt="" width="22" height="22">
</button>
</template>
<div class="table__status glyphicon glyphicon-star" slot="status" slot-scope="props">
<button class="table__status-item" v-for="(item, index) in props.row.status.slice(0, 7)" :key="'status-table-'+index">
<img v-if="item.statusImg" :src="item.statusImg" :alt="item.statusText" width="" height="" />
<div v-if="item.color" class="table__status-color" :data-color="item.color">
<!-- выпадающий список из цветов, наверное, пока застилить кружком -->
<!-- <div>color</div> -->
</div>
</button>
</div>
<div slot="dateTime" slot-scope="props" v-html="props.row.date"></div>
</v-client-table>
</vue-scroll>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-tables-2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuescroll.min.js"></script>
</body>
Буду благодарна за совет. Схематично накинула как это выглядеть должно 
Ответы (1 шт):
Вариант 1
При монтировании и загрузке данными таблицы делаем ширину колонок в
thaedиtbodyодинаковыми.При клике на
table header, делаем его активным и позволяем обрабатывать только его скрол, аналогично при клике наtable body, для сенсорных нужно будет обрабатывать касания.При скролировании делаем скрол другого элемента на ту же позицию В случае прокрутки колесиком
table bodyзапоминаем верткальную позицию прокрутки (как при скроле)
function getData() {
return Array.from(new Array(7)).fill(
{
modal: 'что то',
checkedId: 'check1',
date: '85.12.3021',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то',
//status: ['статус','статус','статус','статус','статус','статус','статус','статус','статус','статус','статус']
})
}
new Vue({
el: "#app",
data() {
return {
count: 0,
active: 'head or body', // костыльчик 1 (конфликт скроллинга)
scrollXPos: 0,
scrollYPos: 0, // костыльчик 3 (позиция скрола по высоте)
dataEl: getData(),
columns: [
'choice',
'status',
'modal',
'date', // <- было 'dateTime' (найти данные в объекте)
'fio',
'floor',
'dateBeathdey',
'area',
'research',
'idPacient',
'quality',
'AETitle',
'direction',
'registrationNumber',
'priority',
'institution',
'appointed',
'nameProtokol',
],
}
},
mounted() {
const th = this.$refs.thead.querySelector('table thead tr')
const tr = this.$refs.tbody.querySelector('table tbody tr')
const h = Array.from(th.querySelectorAll('th'))
const r = Array.from(tr.querySelectorAll('td'))
for (c in r){
const minColumnWidth = 100
w = Math.max(Math.min(h[c].clientWidth, r[c].clientWidth), minColumnWidth)
h[c].style.maxWidth = `${w}px`
h[c].style.width = `${w}px`
r[c].style.maxWidth = `${w}px`
r[c].style.width = `${w}px`
}
},
methods: {
activate(e) { this.active = 'head' },
scrollHanlder(e) {
if (this.active === 'head'){
this.$refs.tbody.scroll(e.target.scrollLeft, this.scrollYPos)
}
},
activate2(e) { this.active = 'body' },
scrollHanlder2(e) {
this.scrollYPos = e.target.scrollTop
if (this.active === 'body'){
this.$refs.thead.scroll(e.target.scrollLeft, 0)
}
}
},
})
.header-wrapper {
display: flex;
align-items: flex-start;
width: 100vw;
height: 40px;
overflow-x: scroll;
}
.fix-header { /* костыльчик 4 (дополнить скролл) */
min-width: 25vw; /* = (100vw - .body-wrapper.width) */
}
.body-wrapper {
width: 75vw;
height: 120px;
overflow-x: scroll;
}
.theader {
width: 200%;
border-collapse: collapse;
}
.table thead th{
border-right: 2px solid #3E5266;
font-family: 'Inter-SemiBold';
background: linear-gradient(180deg, #3E523F 0%, rgba(67, 91, 114, 0.00520833) 260.84%, #234636 260.87%);
}
tbody tr:nth-child(odd) {
background: #6B6D8A;
}
.table { /* костыльчик 2 (сделать таблицы одинаковой ширины) */
min-width: 3000px;
width: 3000px;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id="app">
<div class="header-wrapper" ref="thead" @scroll="scrollHanlder" @mousedown="activate">
<table border="1" class="theader table">
<thead>
<tr>
<th v-for="(item, index) in columns">{{item}}</th>
</tr>
</thead>
</table>
<div class="fix-header"> </div>
</div>
<div class="body-wrapper" ref="tbody" @scroll="scrollHanlder2" @mousedown="activate2" @wheel="scrollHanlder2">
<table border="1" class="theader table">
<tbody>
<tr v-for="(row, index) in dataEl">
<td v-for="(item, index) in columns">{{row[item]}}</td>
</tr>
</tbody>
</table>
</div>
</div>
Стили я прописал минимальные, просто чтобы можно было видеть основные моменты. На счет сортировки можно попробовать посмотреть например такой пример и реализовать что-то похожее для этих данных. Заголовки колонок не подменял - для экономии места и наглядности.
Вариант 2:
Этот вариант экзотический, и понятное дело тоже немного костыльный. По части горизонтального скрола я его не доделал нужен тот же фикс что был в пеовом варианте (JS:создать и внедрить элемент после таблицы) По поводу общего исполнения, в данном случае понадобилось только дописать css, где clip-path задает Г-образную форму таблицы и скроллбары смещаются:
.scroll-table.__vuescroll.hasVBar.hasHBar {
clip-path: polygon(100% 0%,100% 23%,95% 23%,95% 100%,0% 100%,0% 0%);
}
.__rail-is-vertical{
top: 23% !important;
right: 5% !important;
z-index: 1;
max-height: 77%;
}
.__rail-is-horizontal{
max-width: 95%;
}
Посмотреть результат можно тут
.table {border-collapse: collapse;background: black;font-size: calc(100vw * 19/834);line-height: calc(100vw * 31/834);letter-spacing: -0.015em;color: #fff;width: 100%;overflow: auto!important;}.table thead th{border-right: 2px solid #3E5266;}.VueTables thead tr {border-bottom: 2px solid #3E5266;position: relative;z-index: 1;background: #597A95;}.VueTables thead th {font-family: 'Inter-SemiBold';background: linear-gradient(180deg, #3E523F 0%, rgba(67, 91, 114, 0.00520833) 260.84%, #234636 260.87%);}.table thead th:last-child {border-right: none;}.VueTables {border-collapse: collapse;}.VueTables th {white-space: nowrap;font-weight: normal;}.table__edit-img {padding: 0;width: calc(100vw * 30/834);height: calc(100vw * 30/834);vertical-align: middle;}.table__edit-img img {width: 100%;height: 100%;object-fit: cover;}.VueTables thead {z-index: 1;position: sticky;top: 0;}.VueTables thead th:first-child {padding-left: calc((100vw - 320px) / (1024 - 320) * (7 - 2) + 2px);padding-right: calc((100vw - 320px) / (1024 - 320) * (7 - 2) + 2px);line-height: 0;}.VueTables__sortable {padding: calc(100vw * 5/834) calc(100vw * 6/834);cursor: pointer;}.VueTables__heading {display: inline-block;vertical-align: middle;}.VueTables__sortable::before {content: '';position: absolute;bottom: 4px;left: 4px;background-image: url('../images/marker-sort.svg');background-repeat: no-repeat;background-size: contain;width: calc((100vw - 1024px) / (2560 - 1024) * (18 - 12) + 12px);height: calc((100vw - 1024px) / (2560 - 1024) * (10 - 8) + 8px);opacity: 0;transition: opacity 0.3s;}.VueTables__sortable[class*="-sorted-asc"] .table__wrap-sort, .VueTables__sortable[class*="-sorted-desc"] .table__wrap-sort, .VueTables__sortable[class*="-sorted-asc"]::before, .VueTables__sortable[class*="-sorted-desc"]::before {opacity: 1;}.VueTables__sortable[class*="-sorted-asc"] .table__wrap-sort .arrow-up {fill: #D9D9D9;}.VueTables__sortable[class*="-sorted-desc"] .table__wrap-sort .arrow-down {fill: #D9D9D9;}.VueTables td {padding-left: calc((100vw - 320px) / (1024 - 320) * (4 - 2) + 2px);padding-right: calc((100vw - 320px) / (1024 - 320) * (4 - 2) + 2px);text-align: center;border-right: 2px solid #3E5266;white-space: nowrap;height: calc((100vw - 1024px) / (1440 - 1024) * (28 - 24) + 24px);line-height: calc((100vw - 1024px) / (1440 - 1024) * (28 - 23) + 23px);padding: calc(100vw * 4/834) calc(100vw * 6/834);}.VueTables tbody tr:nth-child(odd) {background: #6B6D8A;}.VueTables tbody tr.active {background: rgba(255, 147, 80, 0.45);}.VueTables--client>.row:first-of-type {display: none;}.VuePagination__pagination {display: flex;align-items: center;}.VuePagination__pagination-item {list-style: none;}.VuePagination {display: none;}.bottom-table {width: calc((100vw - 1440px) / (2560 - 1440) * (383 - 340) + 340px);}.wrap-table {position: relative;overflow: hidden;border-radius: 0px 0px 4px 4px;border: 2px solid #3E5266;height: 100%;}.table__wrap-sort {display: flex;position: absolute;width: calc((100vw - 320px) / (1024 - 320) * (19 - 13) + 13px);height: calc((100vw - 320px) / (1024 - 320) * (16 - 10) + 10px);top: 50%;transform: translateY(-50%);right: 2px;opacity: 0;transition: opacity 0.3s;}.table__wrap-sort svg {width: 100%;height: 100%;}.table__wrap-sort .arrow-down, .table__wrap-sort .arrow-up {transition: fill 0.3s;}.VueTables tr td:last-child {border-right: none;}.table-characteristics thead {display: none;}.table-characteristics.VueTables td {text-align: left;}.__vuescroll.hasHBar .VueTables {padding-bottom: calc(100vw * 22/834);}.table__wrap-sort {width: calc((100vw - 1024px) / (2560 - 1004) * (19 - 12) + 12px);height: calc((100vw - 1024px) / (2560 - 1004) * (19 - 12) + 12px);}.table__status-item {width: calc(100vw * 20/834);height: calc(100vw * 20/834);margin-right: calc(100vw * 5/834);padding: 0;}.table__status-item:last-child {margin-right: 0;}.table__status-item img {width: 100%;height: 100%;object-fit: contain;}.table__status {display: flex;align-items: center;}.table__status-color {border-radius: 50%;background: #fff;border: 2px solid #D9D9D9;height: 100%;}.table__status-color[data-color="green"] {background: #54EE51;}.table__status-color[data-color="red"] {background: red;}.table__status-color[data-color="black"] {background: black;}@media (min-width: 1024px) {.table {font-size: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);line-height: calc((100vw - 1024px) / (1440 - 1024) * (32 - 26) + 26px);}.VueTables td {padding-left: calc((100vw - 1024px) / (1024 - 320) * (6 - 4) + 4px);padding-right: calc((100vw - 1024px) / (1024 - 320) * (6 - 4) + 4px);}.VueTables thead th:first-child {padding-left: calc((100vw - 1024px) / (1440 - 1024) * (10 - 7) + 7px);padding-right: calc((100vw - 1024px) / (1440 - 1024) * (10 - 7) + 7px);}.table__status-item {width: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);height: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);margin-right: 5px;}.table__check label {width: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);height: calc((100vw - 1024px) / (1440 - 1024) * (20 - 16) + 16px);}.table__check label::before {transform: translateY(-50%) translateX(-50%);width: calc((100vw - 1024px) / (1440 - 1024) * (8 - 6) + 6px);height: calc((100vw - 1024px) / (1440 - 1024) * (8 - 6) + 6px);}.__vuescroll.hasHBar .VueTables {padding-bottom: calc((100vw - 1024px) / (1440 - 1024) * (24 - 20) + 20px);}.VueTables__sortable {padding-left: calc((100vw - 1024px) / (1440 - 1024) * (28 - 17) + 24px);padding-right: calc((100vw - 1024px) / (1440 - 1024) * (28 - 17) + 24px);padding-top: calc((100vw - 1024px) / (1440 - 1024) * (7 - 4) + 4px);padding-bottom: calc((100vw - 1024px) / (1440 - 1024) * (7 - 4) + 4px);cursor: pointer;}.table__edit-img {width: calc((100vw - 1024px) / (1440 - 1024) * (28 - 22) + 22px);height: calc((100vw - 1024px) / (1440 - 1024) * (28 - 22) + 22px);}}@media (min-width: 1440px) {.VueTables__sortable {padding-left: 31px;padding-right: 31px;padding-top: 5px;}.VueTables thead th:first-child {padding-left: 10px;padding-right: 10px;}.VueTables td {padding-left: 6px;padding-right: 6px;height: 28px;}.table__edit-img {width: 28px;height: 28px;}.vuetable th, .vuetable td {padding-left: 6px;padding-right: 6px;}.table {font-size: 20px;line-height: 32px;}.__vuescroll.hasHBar .VueTables {padding-bottom: calc((100vw - 1440px) / (1920 - 1440) * (20 - 24) + 24px);}.table__check label {width: 20px;height: 20px;}.table__check label::before {width: 8px;height: 8px;}.table__status-item {width: 20px;height: 20px;}}@media screen and (min-width: 1920px) {.VueTables__sortable {padding-top: calc((100vw - 1920px) / (2560 - 1920) * (6 - 5) + 5px);padding-bottom: calc((100vw - 1920px) / (2560 - 1920) * (6 - 5) + 5px);}.table__edit-img {width: calc((100vw - 1920px) / (3840 - 1920) * (36 - 28) + 28px);height: calc((100vw - 1920px) / (3840 - 1920) * (36 - 28) + 28px);}.vuetable th, .vuetable td {padding-left: calc((100vw - 1920px) / (3840 - 1920) * (10 - 6) + 6px);padding-right: calc((100vw - 1920px) / (3840 - 1920) * (10 - 6) + 6px);}.table {font-size: calc((100vw - 1920px) / (2560 - 1920) * (22 - 20) + 20px);line-height: calc((100vw - 1920px) / (2560 - 1920) * (36 - 32) + 32px);}.__vuescroll.hasHBar .VueTables {padding-bottom: calc((100vw - 1920px) / (2560 - 1920) * (27 - 20) + 20px);}.VueTables td {height: calc((100vw - 1920px) / (2560 - 1920) * (31 - 28) + 28px);}.table__check label {width: calc((100vw - 1920px) / (3840 - 1920) * (26 - 20) + 20px);height: calc((100vw - 1920px) / (3840 - 1920) * (26 - 20) + 20px);}.table__check label::before {width: calc((100vw - 1920px) / (3840 - 1920) * (11 - 8) + 8px);height: calc((100vw - 1920px) / (3840 - 1920) * (11 - 8) + 8px);}.table__status-item {width: calc((100vw - 1920px) / (2560 - 1920) * (32 - 28) + 28px);height: calc((100vw - 1920px) / (2560 - 1920) * (32 - 28) + 28px);}}@media (min-width: 2560px) {.table {font-size: calc((100vw - 2560px) / (3840 - 2560) * (24 - 22) + 22px);line-height: calc((100vw - 2560px) / (3840 - 2560) * (39 - 36) + 36px);}.VueTables td {padding-left: calc((100vw - 2560px) / (3840 - 2560) * (10 - 6) + 6px);padding-right: calc((100vw - 2560px) / (3840 - 2560) * (10 - 6) + 6px);padding-bottom: calc((100vw - 2560px) / (3840 - 2560) * (8 - 4) + 4px);padding-top: calc((100vw - 2560px) / (3840 - 2560) * (5 - 4) + 4px);}.VueTables__sortable {padding-top: calc((100vw - 2560px) / (3840 - 2560) * (9 - 6) + 6px);padding-bottom: calc((100vw - 2560px) / (3840 - 2560) * (9 - 6) + 6px);padding-left: calc((100vw - 2560px) / (3840 - 2560) * (37 - 35) + 35px);padding-right: calc((100vw - 2560px) / (3840 - 2560) * (37 - 35) + 35px);}.VueTables thead th:first-child {padding-left: calc((100vw - 1024px) / (1440 - 1024) * (12 - 10) + 10px);padding-right: calc((100vw - 1024px) / (1440 - 1024) * (12 - 10) + 10px);}.table__wrap-sort {width: calc((100vw - 1920px) / (2560 - 1920) * (23 - 19) + 19px);height: calc((100vw - 1920px) / (2560 - 1920) * (20 - 16) + 16px);}.__vuescroll.hasHBar .VueTables {padding-bottom: calc((100vw - 2560px) / (3840 - 2560) * (32 - 27) + 27px);}.VueTables td {height: calc((100vw - 2560px) / (3840 - 2560) * (39 - 31) + 31px);}.table__status-item {width: calc((100vw - 2560px) / (3840 - 2560) * (37 - 32) + 32px);height: calc((100vw - 2560px) / (3840 - 2560) * (37 - 32) + 32px);}}.__rail-is-horizontal {display: flex;align-items: center;background: #3E5266!important;height: calc(100vw * 24/834)!important;border-radius: 0!important;bottom: -2px!important;width: 100%;}.__rail-is-vertical {height: 100%;background: #3E5266!important;border-radius: 0!important;width: calc(100vw * 24/834)!important;right: -2px!important;display: flex;justify-content: center;height: 100%;}.__bar-wrap-is-horizontal {background: #3D607E;border-radius: 12px!important;height: calc(100vw * 20/834)!important;}.__bar-wrap-is-vertical {background: #3D607E;border-radius: 12px!important;width: calc(100vw * 20/834)!important;}.__bar-is-horizontal {opacity: 1!important;background: #8495A2!important;border-radius: 12px!important;height: 100%!important;}.__bar-is-vertical {opacity: 1!important;background: #8495A2!important;border-radius: 12px!important;width: 100%!important;}.scroll-tabs .__rail-is-horizontal {width: 100%;margin: 0!important;bottom: -2px!important;}.__vuescroll.hasVBar.hasHBar .__bar-wrap-is-vertical {height: calc(100% - calc((100vw - 1024px) / (1440 - 1024) * (27 - 22) + 22px));}.__vuescroll.hasVBar.hasHBar .__bar-wrap-is-horizontal {width: calc(100% - (100vw * 40/834));}.wrap-table {height: 200px;}
/******************************/
* {
margin: 0;
}
.scroll-table.__vuescroll.hasVBar.hasHBar {
clip-path: polygon(100% 0%,100% 23%,95% 23%,95% 100%,0% 100%,0% 0%);
}
.__rail-is-vertical{
top: 23% !important;
right: 5% !important;
z-index: 1;
max-height: 77%;
}
.__rail-is-horizontal{
max-width: 95%;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-tables-2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuescroll.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="wrap-table wrap-table--main" id="baseTable">
<vue-scroll class="scroll-table" :initialScrollY="true" :ops="ops">
<v-client-table
:columns="columns"
:data="dataEl"
:options="options"
:show-sort-icons="true"
class="table-main"
:filter="false"
>
<div
v-for="(column, index) in columns"
:key="'column'+index"
:slot="`h__${column}`"
class="bin"
>
<span v-if="index !== 0" v-html="options.headings[column]"></span>
<span v-if="index !== 0" class="table__wrap-sort">
<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 15.7 16" enable-background="new 0 0 15.7 16" xml:space="preserve">
<path class="arrow-down" fill="#808e9b" d="M14.2,8.6H1.5c-0.7,0-1.2,0.4-1.4,1s0,1.3,0.6,1.7L7,15.7C7.2,15.9,7.5,16,7.8,16s0.6-0.1,0.9-0.3l6.3-4.5 c0.5-0.4,0.8-1,0.6-1.7C15.4,9,14.8,8.6,14.2,8.6z"/>
<path class="arrow-up" fill="#808e9b" d="M1.5,7.4h12.7c0.7,0,1.2-0.4,1.4-1c0.2-0.6,0-1.3-0.6-1.7L8.7,0.3C8.2-0.1,7.5-0.1,7,0.3L0.6,4.8 c-0.5,0.4-0.8,1-0.6,1.7S0.8,7.4,1.5,7.4z"/>
</svg>
</span>
</div>
<template slot="h__choice">
<!--
<button class="table__edit-img" @click="updateTable">
<img :src="imgUpdate" alt="" width="22" height="22">
</button>
-->
</template>
<div class="table__status glyphicon glyphicon-star" slot="status" slot-scope="props">
<button class="table__status-item" v-for="(item, index) in props.row.status.slice(0, 7)" :key="'status-table-'+index">
<img v-if="item.statusImg" :src="item.statusImg" :alt="item.statusText" width="" height="" />
<div v-if="item.color" class="table__status-color" :data-color="item.color">
<!-- выпадающий список из цветов, наверное, пока застилить кружком -->
<!-- <div>color</div> -->
</div>
</button>
</div>
<div slot="dateTime" slot-scope="props" v-html="props.row.date"></div>
</v-client-table>
</vue-scroll>
</div>
<script>
Vue.use(VueTables.ClientTable);
Vue.use(vuescroll);
function getData() {
return Array.from(new Array(7)).fill(
{
modal: 'что то',
checkedId: 'check1',
date: '85.12.3021',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то',
status: ['статус','статус','статус','статус','статус','статус','статус','статус','статус','статус','статус']
})
}
const BaseTable = new Vue({
el: "#baseTable",
data() {
return {
dataEl: getData(),
ops: {
scrollPanel: {
initialScrollX: 1,
initialScrollY: 1,
},
},
columns: [
'choice',
'status',
'modal',
'dateTime',
'fio',
'floor',
'dateBeathdey',
'area',
'research',
'idPacient',
'quality',
'AETitle',
'direction',
'registrationNumber',
'priority',
'institution',
'appointed',
'nameProtokol',
],
filterable: [
'choice',
'status',
'modal',
'dateTime',
'fio',
'floor',
'dateBeathdey',
'area',
'research',
'idPacient',
'quality',
'AETitle',
'direction',
'registrationNumber',
'priority',
'institution',
'appointed',
'nameProtokol',
],
options: {
headings: {
status: 'что то',
modal: 'что то',
dateTime: 'что то',
fio: 'что то',
floor: 'что то',
dateBeathdey: 'что то',
area: 'что то',
research: 'что то',
idPacient: 'что то',
quality: 'что то',
AETitle: 'что то',
direction: 'что то',
registrationNumber: 'что то',
priority: 'что то',
institution: 'что то',
appointed: 'что то',
nameProtokol: 'что то',
},
sortable: [
'status',
'modal',
'dateTime',
'fio',
'floor',
'dateBeathdey',
'area',
'research',
'idPacient',
'quality',
'AETitle',
'direction',
'registrationNumber',
'priority',
'institution',
'appointed',
'nameProtokol',
]
},
}
}
});
</script>
</body>
</html>