修复虚拟滚动后筛选后滚动条显示错误问题

This commit is contained in:
xuliangzhan
2022-01-23 19:26:30 +08:00
parent 4a3245a42a
commit 38469f8bff
7 changed files with 567 additions and 161 deletions

File diff suppressed because one or more lines are too long

View File

@@ -34,7 +34,7 @@
:checkbox-config="{checkField: 'checked'}">
<vxe-column type="checkbox" width="60" fixed="left"></vxe-column>
<vxe-column type="seq" width="100" fixed="left"></vxe-column>
<vxe-column field="name" title="Name" sortable width="200"></vxe-column>
<vxe-column field="name" title="Name" sortable width="200" :filters="[{label: '50',value:50},{label: '120',value:120},{label: '220',value:220}]" :filter-method="filterNameMethod"></vxe-column>
<vxe-column field="sex" title="Sex" width="200"></vxe-column>
<vxe-column field="rate" title="Rate" width="200"></vxe-column>
<vxe-column field="region" title="Region" width="200"></vxe-column>
@@ -209,6 +209,7 @@ export default {
const list = []
for (let index = 0; index < size; index++) {
list.push({
key: index,
name: `名称${index}`,
checked: false,
sex: '0',
@@ -225,6 +226,9 @@ export default {
getSelectEvent () {
const selectRecords = this.$refs.xTable.getCheckboxRecords()
this.$XModal.alert(selectRecords.length)
},
filterNameMethod ({ value, row }) {
return row.key > value
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "vxe-table",
"version": "3.4.14-beta.1",
"version": "3.4.14-beta.3",
"description": "一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟列表、虚拟树、懒加载、快捷菜单、数据校验、树形结构、打印导出、表单渲染、数据分页、弹窗、自定义模板、渲染器、贼灵活的配置项、扩展接口等...",
"scripts": {
"serve": "vue-cli-service serve",

View File

@@ -159,7 +159,7 @@ export default {
* @param {Event} evnt 事件
*/
confirmFilterEvent (evnt) {
const { filterStore, filterOpts, scrollXLoad, scrollYLoad } = this
const { filterStore, filterOpts, scrollXLoad: oldScrollXLoad, scrollYLoad: oldScrollYLoad } = this
const { column } = filterStore
const { property } = column
const values = []
@@ -175,19 +175,26 @@ export default {
if (!filterOpts.remote) {
this.handleTableData(true)
this.checkSelectionStatus()
this.updateFooter()
if (scrollXLoad || scrollYLoad) {
this.refreshScroll()
if (scrollYLoad) {
this.updateScrollYSpace()
}
}
}
this.emitEvent('filter-change', { column, property, values, datas, filters: filterList, filterList }, evnt)
this.closeFilter()
this.$nextTick(() => {
this.recalculate()
this.updateFooter().then(() => {
const { scrollXLoad, scrollYLoad } = this
if ((oldScrollXLoad || scrollXLoad) || (oldScrollYLoad || scrollYLoad)) {
if ((oldScrollXLoad || scrollXLoad)) {
this.updateScrollXSpace()
}
if ((oldScrollYLoad || scrollYLoad)) {
this.updateScrollYSpace()
}
return this.refreshScroll()
}
}).then(() => {
this.updateCellAreas()
return this.recalculate(true)
}).then(() => {
// 存在滚动行为未结束情况
setTimeout(() => this.recalculate(), 50)
})
},
handleClearFilter (column) {

View File

@@ -3,7 +3,7 @@ import GlobalConfig from '../../v-x-e-table/src/conf'
import VXETable from '../../v-x-e-table'
import { UtilTools, DomTools, isEnableConf } from '../../tools'
import { getOffsetSize, calcTreeLine, mergeBodyMethod, removeScrollListener, restoreScrollListener } from './util'
import { browse } from '../../tools/src/dom'
import { browse, setScrollLeftAndTop } from '../../tools/src/dom'
const renderType = 'body'
@@ -401,7 +401,7 @@ function renderRows (h, _vm, $xetable, fixedType, tableData, tableColumn) {
* 同步滚动条
*/
let scrollProcessTimeout
function syncBodyScroll (scrollTop, elem1, elem2) {
function syncBodyScroll (_vm, fixedType, scrollTop, elem1, elem2) {
if (elem1 || elem2) {
if (elem1) {
removeScrollListener(elem1)
@@ -412,9 +412,30 @@ function syncBodyScroll (scrollTop, elem1, elem2) {
elem2.scrollTop = scrollTop
}
clearTimeout(scrollProcessTimeout)
scrollProcessTimeout = setTimeout(function () {
scrollProcessTimeout = setTimeout(() => {
const { tableBody, leftBody, rightBody } = _vm.$refs
const bodyElem = tableBody.$el
const leftElem = leftBody ? leftBody.$el : null
const rightElem = rightBody ? rightBody.$el : null
restoreScrollListener(elem1)
restoreScrollListener(elem2)
// 检查滚动条是的同步
let targetTop = bodyElem.scrollTop
let targetLeft = bodyElem.scrollLeft
if (fixedType === 'left') {
if (leftElem) {
targetTop = leftElem.scrollTop
targetLeft = leftElem.scrollLeft
}
} else if (fixedType === 'right') {
if (rightElem) {
targetTop = rightElem.scrollTop
targetLeft = rightElem.scrollLeft
}
}
setScrollLeftAndTop(bodyElem, targetLeft, targetTop)
setScrollLeftAndTop(leftElem, targetLeft, targetTop)
setScrollLeftAndTop(rightElem, targetLeft, targetTop)
}, 300)
}
}
@@ -621,10 +642,10 @@ export default {
}
if (leftElem && fixedType === 'left') {
scrollTop = leftElem.scrollTop
syncBodyScroll(scrollTop, bodyElem, rightElem)
syncBodyScroll($xetable, fixedType, scrollTop, bodyElem, rightElem)
} else if (rightElem && fixedType === 'right') {
scrollTop = rightElem.scrollTop
syncBodyScroll(scrollTop, bodyElem, leftElem)
syncBodyScroll($xetable, fixedType, scrollTop, bodyElem, leftElem)
} else {
if (isRollX) {
if (headerElem) {
@@ -637,7 +658,7 @@ export default {
if (leftElem || rightElem) {
$xetable.checkScrolling()
if (isRollY) {
syncBodyScroll(scrollTop, leftElem, rightElem)
syncBodyScroll($xetable, fixedType, scrollTop, leftElem, rightElem)
}
}
}
@@ -689,15 +710,15 @@ export default {
wheelYInterval = wheelYInterval - (wheelYTotal - wheelYSize)
}
const { scrollTop, clientHeight, scrollHeight } = bodyElem
const targerTop = scrollTop + (wheelYInterval * (isTopWheel ? -1 : 1))
bodyElem.scrollTop = targerTop
const targetTop = scrollTop + (wheelYInterval * (isTopWheel ? -1 : 1))
bodyElem.scrollTop = targetTop
if (leftElem) {
leftElem.scrollTop = targerTop
leftElem.scrollTop = targetTop
}
if (rightElem) {
rightElem.scrollTop = targerTop
rightElem.scrollTop = targetTop
}
if (isTopWheel ? targerTop < scrollHeight - clientHeight : targerTop >= 0) {
if (isTopWheel ? targetTop < scrollHeight - clientHeight : targetTop >= 0) {
this.wheelTime = setTimeout(handleSmooth, 10)
}
this.wheelYTotal = wheelYTotal

View File

@@ -9,7 +9,7 @@ import { browse, getPaddingTopBottomSize, setScrollTop, setScrollLeft } from '..
import { formats } from '../../v-x-e-table/src/formats'
const { getRowid, getRowkey, setCellValue, hasChildrenList, getColumnList } = UtilTools
const { calcHeight, hasClass, addClass, removeClass, getEventTargetNode } = DomTools
const { calcHeight, hasClass, addClass, removeClass, getEventTargetNode, isNodeElement } = DomTools
const isWebkit = browse['-webkit'] && !browse.edge
const debounceScrollYDuration = browse.msie ? 80 : 20
@@ -294,11 +294,30 @@ const Methods = {
})
},
/**
* 手动处理数据
* 手动处理数据,用于手动排序与筛选
* 对于手动更改了排序、筛选...等条件后需要重新处理数据时可能会用到
*/
updateData () {
return this.handleTableData(true).then(this.updateFooter).then(this.recalculate)
const { scrollXLoad, scrollYLoad } = this
return this.handleTableData(true).then(() => {
this.updateFooter()
this.checkSelectionStatus()
if (scrollXLoad || scrollYLoad) {
if (scrollXLoad) {
this.updateScrollXSpace()
}
if (scrollYLoad) {
this.updateScrollYSpace()
}
return this.refreshScroll()
}
}).then(() => {
this.updateCellAreas()
return this.recalculate(true)
}).then(() => {
// 存在滚动行为未结束情况
setTimeout(() => this.recalculate(), 50)
})
},
handleTableData (force) {
const { scrollYLoad, scrollYStore, fullDataRowIdData, afterFullData } = this
@@ -1688,15 +1707,22 @@ const Methods = {
const leftBodyElem = leftBody ? leftBody.$el : null
const rightBodyElem = rightBody ? rightBody.$el : null
const tableFooterElem = tableFooter ? tableFooter.$el : null
// 还原滚动条位置
if (lastScrollLeft || lastScrollTop) {
return restoreScrollLocation(this, lastScrollLeft, lastScrollTop)
}
// 重置
setScrollTop(tableBodyElem, lastScrollTop)
setScrollTop(leftBodyElem, lastScrollTop)
setScrollTop(rightBodyElem, lastScrollTop)
setScrollLeft(tableFooterElem, lastScrollLeft)
return new Promise(resolve => {
// 还原滚动条位置
if (lastScrollLeft || lastScrollTop) {
return restoreScrollLocation(this, lastScrollLeft, lastScrollTop).then(() => {
// 存在滚动行为未结束情况
setTimeout(resolve, 30)
})
}
// 重置
setScrollTop(tableBodyElem, lastScrollTop)
setScrollTop(leftBodyElem, lastScrollTop)
setScrollTop(rightBodyElem, lastScrollTop)
setScrollLeft(tableFooterElem, lastScrollLeft)
// 存在滚动行为未结束情况
setTimeout(resolve, 30)
})
},
/**
* 计算单元格列宽,动态分配可用剩余空间
@@ -1965,7 +1991,7 @@ const Methods = {
}
} else if (layout === 'body') {
const emptyBlockElem = elemStore[`${name}-${layout}-emptyBlock`]
if (wrapperElem) {
if (isNodeElement(wrapperElem)) {
if (customMaxHeight) {
wrapperElem.style.maxHeight = `${fixedType ? customMaxHeight - headerHeight - (showFooter ? 0 : scrollbarHeight) : customMaxHeight - headerHeight}px`
} else {
@@ -1981,7 +2007,7 @@ const Methods = {
if (fixedWrapperElem) {
const isRightFixed = fixedType === 'right'
const fixedColumn = columnStore[`${fixedType}List`]
if (wrapperElem) {
if (isNodeElement(wrapperElem)) {
wrapperElem.style.top = `${headerHeight}px`
}
fixedWrapperElem.style.height = `${(customHeight > 0 ? customHeight - headerHeight - footerHeight : tableHeight) + headerHeight + footerHeight - scrollbarHeight * (showFooter ? 2 : 1)}px`
@@ -2045,7 +2071,7 @@ const Methods = {
}
tWidth = tableColumn.reduce((previous, column) => previous + column.renderWidth, 0)
if (wrapperElem) {
if (isNodeElement(wrapperElem)) {
// 如果是固定列
if (fixedWrapperElem) {
wrapperElem.style.top = `${customHeight > 0 ? customHeight - footerHeight : tableHeight + headerHeight}px`

View File

@@ -80,6 +80,17 @@ export function setScrollLeft (elem, scrollLeft) {
}
}
export function setScrollLeftAndTop (elem, scrollLeft, scrollTop) {
if (elem) {
elem.scrollLeft = scrollLeft
elem.scrollTop = scrollTop
}
}
function isNodeElement (elem) {
return elem && elem.nodeType === 1
}
export const DomTools = {
browse,
isPx (val) {
@@ -225,7 +236,8 @@ export const DomTools = {
}
}
return num
}
},
isNodeElement
}
export default DomTools