- 修复resize layout布局错乱

- 修复fixed元素hover失效
This commit is contained in:
Julyp
2020-02-05 17:10:11 +08:00
parent 1b786975f4
commit 41ed2e04cd
5 changed files with 153 additions and 132 deletions

File diff suppressed because one or more lines are too long

View File

@@ -55,7 +55,7 @@
<th colspan="1" fixed sort>Logo</th>
<th colspan="1" width="200" fixed>日期</th>
<th colspan="1" width="100" sort>姓名</th>
<th colspan="1" width="100">省份</th>
<th colspan="1">省份(包含自治区)</th>
<th colspan="1" sort>市区</th>
<th colspan="1">地址</th>
<th colspan="1" width="95" fixed>邮编</th>
@@ -145,18 +145,18 @@
<thead>
<tr>
<th colspan="1" rowspan="3" fixed sort="number">Id</th>
<th colspan="1" rowspan="3" sort fixed>日期</th>
<th colspan="1" rowspan="3" width="240" sort fixed>日期</th>
<th colspan="5" rowspan="1" sort>配送信息</th>
<th colspan="1" rowspan="3" fixed>操作</th>
</tr>
<tr>
<th colspan="1" rowspan="2" width="240" sort>姓名</th>
<th colspan="1" rowspan="2" width="280" sort>姓名</th>
<th colspan="4" rowspan="1" sort>地址</th>
</tr>
<tr>
<th colspan="1" rowspan="1">省份</th>
<th colspan="1" rowspan="1" width="120">市区</th>
<th colspan="1" rowspan="1" width="280">地址</th>
<th colspan="1" rowspan="1" width="240">市区</th>
<th colspan="1" rowspan="1" width="300">地址</th>
<th colspan="1" rowspan="1" sort>邮编</th>
</tr>
</thead>
@@ -229,12 +229,13 @@
<script>
new SmartTable({
selector: '#smartTable1',
height: 300,
height: 320,
hoverBgColor: '#C5DFFF'
})
new SmartTable({
selector: '#smartTable2',
align: 'left',
height: 320,
size: 'middle'
})
</script>

View File

@@ -48,24 +48,29 @@ export default function initMixin(Table) {
vm.style = {
hoverBgColor: options.hoverBgColor || '#EFF8FF'
}
vm.size = {}
//初始化thead 并获取props
vm.props = initProps(thead);
initProps(vm)
layout(vm, table)
// createFixed(vm, thead, tbody);
//初始化fixed元素及宽度
initFixed(vm)
createFixed(vm, thead, tbody)
//获取tbody的data数据
vm.data = initData(vm, tbody);
bindEvents(vm);
initData(vm, tbody)
bindEvents(vm)
const th = createElement("th");
th.style.display = 'none'
th.setAttribute("width", vm.gutterWidth);
th.setAttribute("rowspan", vm.props.shapes.length);
appendChild(querySelector(vm.$thead, "tr"), th);
vm.$scrollTH = th;
if (vm.scrollY) {
let th = createElement("th");
th.setAttribute("width", vm.gutterWidth);
th.setAttribute("rowspan", vm.props.shapes.length);
appendChild(querySelector(thead, "tr"), th);
vm.$scrollTH.style.display = 'table-cell'
resize(vm)
}
}
}
@@ -89,27 +94,19 @@ function layout(vm, table) {
const tbodyWrapperHeight = offsetHeight > theadHeight ? (offsetHeight - theadHeight - 1) : (theadHeight + 150)
vm.$tbodyWrapper.style.height = tbodyWrapperHeight + "px";
vm.size.rootHeight = theadHeight + tbodyWrapperHeight;
vm.size.theadHeight = theadHeight;
vm.size.tbodyHeight = $tbody.offsetHeight;
vm.size.tbodyWrapperHeight = tbodyWrapperHeight;
//垂直方向是否有滚动条
vm.scrollY = vm.size.tbodyHeight > tbodyWrapperHeight;
//水平方向是否有滚动条
vm.scrollX = vm.size.tableWidth > vm.size.rootWidth;
//初始化fixed元素及宽度
initFixed(vm.$thead, vm);
vm.scrollY = vm.$tbody.offsetHeight > tbodyWrapperHeight;
//删除空余的table节点
removeChild(table.parentNode, table);
console.log(vm.size)
}
//根据表格中的tbody第一行 查出每列的宽度并记录
function initColgroupData(vm) {
const { $root, props } = vm;
let offsetWidth = $root.offsetWidth - 1;
let clientWidth = offsetWidth - (vm.scrollY ? vm.gutterWidth : 0);
const offsetWidth = $root.offsetWidth - 1;
const clientWidth = offsetWidth - (vm.scrollY ? vm.gutterWidth : 0);
let arr = [];
let totalWidth = 0;
props.shapes.forEach(shape => {
@@ -128,9 +125,8 @@ function initColgroupData(vm) {
item === 0 && zeroLen++
})
if (zeroLen) {
let diff = clientWidth - totalWidth
let per = Math.floor(diff / zeroLen)
let min = per > 80 ? per : 80;
const per = Math.floor((clientWidth - totalWidth) / zeroLen)
const min = per > 80 ? per : 80;
let lastZeroIndex = 0;
totalWidth = 0;
arr = arr.map((item, index) => {
@@ -149,20 +145,17 @@ function initColgroupData(vm) {
totalWidth = arr.reduce((item, sum) => sum + item, 0)
}
vm.colgroup = arr;
vm.size = {
rootWidth: offsetWidth,
tableWidth: totalWidth
}
vm.size.rootWidth = offsetWidth
vm.size.tableWidth = totalWidth
vm.scrollX = vm.size.tableWidth > vm.size.rootWidth;
}
function bindResizeEvents(vm) {
window.addEventListener("resize", debounce(500, () => {
initColgroupData(vm)
console.log(vm.$root.offsetWidth)
}))
window.addEventListener("resize", () => resize(vm), {
passive: true
})
}
function bindEvents(vm) {
bindScrollEvents(vm)
bindHoverEvents(vm)
@@ -170,31 +163,55 @@ function bindEvents(vm) {
bindResizeEvents(vm)
}
function replaceFixedColGroup(vm, selector, newTableWidth) {
if (selector) {
let fixedHeader = querySelector(selector, '.stb_header');
let fixedBody = querySelector(selector, '.stb_body');
replaceColGroup(vm, fixedHeader);
replaceColGroup(vm, fixedBody);
const columns = querySelectorAll(selector, "tr:first-child>th");
let fixedWrapperWidth = 0;
columns.forEach((item, index) => {
if (item.className != 'is-hidden') fixedWrapperWidth += vm.colgroup[index]
})
selector.style.width = fixedWrapperWidth + 'px';
fixedHeader.style.width = newTableWidth + 'px';
fixedBody.style.width = newTableWidth + 'px';
}
function resize(vm) {
debounce(500, () => {
const { fixedLeft, fixedRight } = vm.props;
initColgroupData(vm)
replaceColGroup(vm)
vm.scrollY = vm.$tbody.offsetHeight > vm.size.tbodyWrapperHeight;
vm.$scrollTH.style.display = vm.scrollY ? 'table-cell' : 'none';
let height = (vm.$root.offsetHeight - (vm.scrollX ? vm.gutterWidth : 2));
const tableHeight = vm.$thead.offsetHeight + vm.$tbody.offsetHeight;
height = tableHeight > height ? height : tableHeight
const bodyWrapperHeight = vm.size.tbodyWrapperHeight - (vm.scrollX ? vm.gutterWidth : 0);
const bodyWrapperTop = vm.$thead.offsetHeight;
let fixedLeftWidth = 0;
let fixedRightWidth = 0;
if (vm.$fixedLeft && fixedLeft.thead.length) {
fixedLeft.thead.forEach((item, index) => {
fixedLeftWidth += vm.colgroup[index]
})
vm.$fixedLeftBody.style.height = bodyWrapperHeight + "px";
vm.$fixedLeftBody.style.top = bodyWrapperTop + "px";
vm.$fixedLeft.style.width = fixedLeftWidth + "px";
vm.$fixedLeft.style.height = height + "px";
}
if (vm.$fixedRight && fixedRight.thead.length) {
fixedRight.thead.forEach((item, index) => {
fixedRightWidth += vm.colgroup[vm.colgroup.length - index - 1]
})
vm.$fixedRightBody.style.height = bodyWrapperHeight + "px";
vm.$fixedRightBody.style.top = bodyWrapperTop + "px";
vm.$fixedRight.style.width = fixedRightWidth + "px"
vm.$fixedRight.style.height = height + "px";
vm.$fixedRight.style.right = (vm.scrollY ? vm.gutterWidth : 0) + "px";
vm.$rightPatch.style.display = vm.scrollY ? 'block' : 'none';
vm.$rightPatch.style.height = vm.$thead.offsetHeight;
}
})()
}
function syncPostion(vm) {
throttle(20, () => {
vm.$theadWrapper.scrollLeft = vm.$tbodyWrapper.scrollLeft;
if (vm.$fixedLeft) {
vm.$fixedLeft.scrollTop = vm.$tbodyWrapper.scrollTop;
if (vm.$fixedLeftBody) {
vm.$fixedLeftBody.scrollTop = vm.$tbodyWrapper.scrollTop;
}
if (vm.$fixedRight) {
vm.$fixedRight.scrollTop = vm.$tbodyWrapper.scrollTop;
if (vm.$fixedRightBody) {
vm.$fixedRightBody.scrollTop = vm.$tbodyWrapper.scrollTop;
}
})()
}
@@ -206,19 +223,27 @@ function bindScrollEvents(vm) {
}
function bindHoverEvents(vm) {
let trs = querySelectorAll(vm.$tbodyWrapper, 'tr');
let fixedLeftTrs = querySelectorAll(vm.$root, '.stb_fixed .stb_fixed-body-wrapper tr');
let fixedRightTrs = querySelectorAll(vm.$root, '.stb_fixed-right .stb_fixed-body-wrapper tr');
trs.forEach((tr, trIndex) => {
tr.addEventListener('mouseenter', () => {
tr.style.background = vm.style.hoverBgColor;
if (fixedLeftTrs.length > 0) fixedLeftTrs[trIndex].style.background = vm.style.hoverBgColor;
if (fixedRightTrs.length > 0) fixedRightTrs[trIndex].style.background = vm.style.hoverBgColor;
let data = [].concat(vm.data, vm.unsortData)
data.forEach(row => {
addHoverEventByEl(vm, row.$el, [row.$fixedLeftEl, row.$fixedRightEl])
row.$fixedLeftEl && addHoverEventByEl(vm, row.$fixedLeftEl, [row.$el, row.$fixedRightEl])
row.$fixedRightEl && addHoverEventByEl(vm, row.$fixedRightEl, [row.$el, row.$fixedLeftEl])
})
}
function addHoverEventByEl(vm, trigger, relates) {
if (!trigger) return;
trigger.addEventListener('mouseenter', () => {
trigger.style.background = vm.style.hoverBgColor
relates.forEach(el => {
el && (el.style.background = vm.style.hoverBgColor)
})
tr.addEventListener('mouseleave', () => {
tr.style.background = ''
if (fixedLeftTrs.length > 0) fixedLeftTrs[trIndex].style.background = '';
if (fixedRightTrs.length > 0) fixedRightTrs[trIndex].style.background = '';
})
trigger.addEventListener('mouseleave', () => {
trigger.style.background = ''
relates.forEach(el => {
el && (el.style.background = '')
})
})
}
@@ -250,35 +275,11 @@ function bindSortEvents(vm) {
})
}
function bindResizeEvents2(vm) {
window.addEventListener("resize", debounce(600, () => {
let table = vm.$root;
let oldWrapperWidth = vm.size.wrapperWidth;
let oldTableWidth = vm.size.tableWidth;
let newWrapperWidth = table.offsetWidth;
let newTableWidth = parseInt(oldTableWidth * (newWrapperWidth / oldWrapperWidth));
let headerWrapper = querySelector(vm.$theadWrapper, '.stb_header');
let bodyWrapper = querySelector(vm.$tbodyWrapper, '.stb_body');
vm.colgroup.forEach(function(item, index) {
vm.colgroup[index] = parseInt(newTableWidth * (item / oldTableWidth)) + 1
})
vm.size.wrapperWidth = newWrapperWidth;
vm.size.tableWidth = newTableWidth;
headerWrapper.style.width = newTableWidth + 'px';
bodyWrapper.style.width = newTableWidth + 'px';
// 替换colgroup
replaceColGroup(vm, headerWrapper);
replaceColGroup(vm, bodyWrapper);
replaceFixedColGroup(vm, querySelector(table, '.stb_fixed'), newTableWidth);
replaceFixedColGroup(vm, querySelector(table, '.stb_fixed-right'), newTableWidth);
}))
}
function initProps(thead) {
function initProps(vm) {
let props = {};
//创建表头单元格二维数组
let shapes = [];
let rows = querySelectorAll(thead, "tr");
let rows = querySelectorAll(vm.$thead, "tr");
rows.forEach((row, index) => {
let shape = shapes[index] || [];
let columns = querySelectorAll(row, "th");
@@ -311,10 +312,10 @@ function initProps(thead) {
})
})
props.shapes = shapes;
return props;
vm.props = props;
}
function initFixed(thead, vm) {
function initFixed(vm) {
let {
colgroup,
props
@@ -330,7 +331,7 @@ function initFixed(thead, vm) {
tbody: [],
width: 0
};
const columns = querySelectorAll(thead, "tr:first-child>th");
const columns = querySelectorAll(vm.$thead, "tr:first-child>th");
const len = columns.length;
let lastLeftIndex = 0;
if (len !== 0) {
@@ -343,8 +344,10 @@ function initFixed(thead, vm) {
let colspan = getIntByAttr(columns[i], "colspan", 1);
for (let j = 0; j < colspan; j++) {
fixedLeft.tbody.push("field-" + (i + j));
fixedLeft.width = fixedLeft.width + colgroup[i + j];
fixedLeft.width += colgroup[i + j];
}
} else {
break;
}
}
}
@@ -362,8 +365,10 @@ function initFixed(thead, vm) {
for (let j = 0; j < colspan; j++) {
rightCnt++;
fixedRight.tbody.push("field-" + (colgroupLen - rightCnt))
fixedRight.width = fixedRight.width + colgroup[colgroupLen - rightCnt];
fixedRight.width += colgroup[colgroupLen - rightCnt];
}
} else {
break;
}
}
}
@@ -373,22 +378,26 @@ function initFixed(thead, vm) {
}
function initData(vm, tbody) {
let fixedLeftRows = vm.$fixedLeft && querySelectorAll(vm.$fixedLeft, "tbody tr");
let fixedRightRows = vm.$fixedRight && querySelectorAll(vm.$fixedRight, "tbody tr");
let fixedLeftRows = vm.$fixedLeftBody && querySelectorAll(vm.$fixedLeftBody, "tbody tr");
let fixedRightRows = vm.$fixedRightBody && querySelectorAll(vm.$fixedRightBody, "tbody tr");
let data = [];
let unsortData = [];
querySelectorAll(tbody, "tr").forEach((row, index) => {
let rowData = {
$el: row,
$fixedLeftEl: fixedLeftRows && fixedLeftRows[index],
$fixedRightEl: fixedRightRows && fixedRightRows[index],
$key: '$$rowkey' + index
};
querySelectorAll(row, "td .stb_cell").forEach((cell, index) => {
rowData["field-" + index] = cell.innerHTML;
})
if (!row.hasAttribute("unsort")) {
let rowData = {
$el: row,
$fixedLeftEl: fixedLeftRows && fixedLeftRows[index],
$fixedRightEl: fixedRightRows && fixedRightRows[index],
$key: '$$rowkey' + index
};
querySelectorAll(row, "td .stb_cell").forEach((cell, index) => {
rowData["field-" + index] = cell.innerHTML;
})
data.push(rowData)
} else {
unsortData.push(rowData)
}
})
return data;
vm.data = data;
vm.unsortData = unsortData;
}

View File

@@ -19,29 +19,34 @@ export default function(vm, theadModel, tbodyModel) {
rootMinWidth = rootMinWidth > fixedLeft.width ? rootMinWidth : fixedLeft.width;
const headerWrapper = createHeaderWrapper(vm, theadModel, fixedLeft);
const bodyWrapper = createBodyWrapper(vm, tbodyModel, fixedLeft, 'left');
appendChild(vm.$root, createContainer(vm, headerWrapper, bodyWrapper, fixedLeft, 'stb_fixed', 'left'));
vm.$fixedLeft = bodyWrapper;
vm.$fixedLeft = createContainer(vm, headerWrapper, bodyWrapper, fixedLeft, 'stb_fixed', 'left');
appendChild(vm.$root, vm.$fixedLeft);
vm.$fixedLeftBody = bodyWrapper;
}
//右边有固定列
if (fixedRight.thead.length > 0) {
rootMinWidth = rootMinWidth + fixedRight.width;
const headerWrapper = createHeaderWrapper(vm, theadModel, fixedRight);
const bodyWrapper = createBodyWrapper(vm, tbodyModel, fixedRight, 'right');
appendChild(vm.$root, createContainer(vm, headerWrapper, bodyWrapper, fixedRight, 'stb_fixed-right', 'right'));
vm.$fixedRight = bodyWrapper;
vm.$fixedRight = createContainer(vm, headerWrapper, bodyWrapper, fixedRight, 'stb_fixed-right', 'right');
appendChild(vm.$root, vm.$fixedRight);
vm.$fixedRightBody = bodyWrapper;
let rightPatch = createElement("div", "stb_fixed-right-patch");
rightPatch.style.display = 'none';
rightPatch.style.width = vm.gutterWidth + "px";
rightPatch.style.height = vm.$thead.offsetHeight + "px";
appendChild(vm.$root, rightPatch)
vm.$rightPatch = rightPatch;
if (vm.scrollY) {
let rightPatch = createElement("div", "stb_fixed-right-patch");
rightPatch.style.width = vm.gutterWidth + "px";
rightPatch.style.height = vm.size.theadHeight + "px";
appendChild(vm.$root, rightPatch)
vm.$rightPatch.style.display = 'block'
}
}
vm.$root.style.minWidth = rootMinWidth + "px";
}
function createHeaderWrapper(vm, model, meta) {
let thead = cloneNode(model, true);
const thead = cloneNode(model, true);
querySelectorAll(thead, "tr:first-child>th").forEach((column, index) => {
if (meta.thead.indexOf("field-" + index) === -1) {
column.classList.add('is-hidden')
@@ -51,8 +56,8 @@ function createHeaderWrapper(vm, model, meta) {
}
function createBodyWrapper(vm, model, meta, type) {
let tbody = cloneNode(model, true);
let rows = querySelectorAll(tbody, "tr");
const tbody = cloneNode(model, true);
const rows = querySelectorAll(tbody, "tr");
rows.forEach(row => {
let offsetX = -1;
querySelectorAll(row, "td").forEach((column, index) => {
@@ -66,17 +71,20 @@ function createBodyWrapper(vm, model, meta, type) {
}
})
})
let bodyWrapper = createTableWrapper("stb_fixed-body-wrapper", vm, "body", tbody);
bodyWrapper.style.top = vm.size.theadHeight + "px";
const bodyWrapper = createTableWrapper("stb_fixed-body-wrapper", vm, "body", tbody);
bodyWrapper.style.top = vm.$thead.offsetHeight + "px";
bodyWrapper.style.height = (vm.size.tbodyWrapperHeight - (vm.scrollX ? vm.gutterWidth : 0)) + "px";
return bodyWrapper
}
function createContainer(vm, thead, tbody, meta, className, type) {
let fixedContainer = createElement("div", className);
const fixedContainer = createElement("div", className);
type === 'right' && (fixedContainer.style.right = (vm.scrollY ? vm.gutterWidth : 0) + "px");
appendChildren(fixedContainer, [thead, tbody]);
fixedContainer.style.width = meta.width + "px";
fixedContainer.style.height = (vm.size.rootHeight - (vm.scrollX ? vm.gutterWidth : 0)) + "px";
let height = (vm.$root.offsetHeight - (vm.scrollX ? vm.gutterWidth : 2));
const tableHeight = vm.$thead.offsetHeight + vm.$tbody.offsetHeight;
height = tableHeight > height ? height : tableHeight
fixedContainer.style.height = height + "px";
return fixedContainer
}

View File

@@ -3,6 +3,7 @@ import {
createElement,
querySelector,
appendChildren,
querySelectorAll,
} from './node-ops';
export function refactorCell(cell) {
@@ -23,9 +24,11 @@ export function createTableWrapper(className, vm, type, content) {
return wrapper;
}
export function replaceColGroup(vm, wrapper) {
let colgroup = createColgroup(vm.colgroup);
wrapper.replaceChild(colgroup, querySelector(wrapper, 'colgroup'));
export function replaceColGroup(vm) {
querySelectorAll(vm.$root, 'table').forEach(table => {
table.style.width = vm.size.tableWidth + "px";
table.replaceChild(createColgroup(vm.colgroup), querySelector(table, 'colgroup'));
})
}
export function getIntByAttr(el, key, def) {