fix display:none

This commit is contained in:
samunohito
2024-01-30 09:53:47 +09:00
parent b2c8548c67
commit ad03ef03da
4 changed files with 101 additions and 18 deletions
@@ -50,7 +50,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, defineAsyncComponent, nextTick, ref, shallowRef, toRefs, watch } from 'vue'; import { computed, defineAsyncComponent, nextTick, onMounted, onUnmounted, ref, shallowRef, toRefs, watch } from 'vue';
import { GridEventEmitter, Size } from '@/components/grid/grid.js'; import { GridEventEmitter, Size } from '@/components/grid/grid.js';
import { useTooltip } from '@/scripts/use-tooltip.js'; import { useTooltip } from '@/scripts/use-tooltip.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
@@ -144,6 +144,10 @@ function onInputText(ev: Event) {
editingValue.value = (ev.target as HTMLInputElement).value; editingValue.value = (ev.target as HTMLInputElement).value;
} }
function onForceRefreshContentSize() {
emitContentSizeChanged();
}
function registerOutsideMouseDown() { function registerOutsideMouseDown() {
unregisterOutsideMouseDown(); unregisterOutsideMouseDown();
addEventListener('mousedown', onOutsideMouseDown); addEventListener('mousedown', onOutsideMouseDown);
@@ -223,6 +227,14 @@ useTooltip(rootEl, (showing) => {
}, {}, 'closed'); }, {}, 'closed');
}); });
onMounted(() => {
bus.value.on('forceRefreshContentSize', onForceRefreshContentSize);
});
onUnmounted(() => {
bus.value.off('forceRefreshContentSize', onForceRefreshContentSize);
});
</script> </script>
<style module lang="scss"> <style module lang="scss">
@@ -36,7 +36,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, toRefs, watch } from 'vue'; import { computed, nextTick, onMounted, ref, toRefs, watch } from 'vue';
import { import {
CellValueChangedEvent, CellValueChangedEvent,
ColumnSetting, ColumnSetting,
@@ -71,7 +71,21 @@ const emit = defineEmits<{
(ev: 'change:cellValue', event: CellValueChangedEvent): void; (ev: 'change:cellValue', event: CellValueChangedEvent): void;
}>(); }>();
/**
* grid -> 各子コンポーネントのイベント経路を担う{@link GridEventEmitter}。
* 子コンポーネント -> gridのイベントでは原則使用せず、{@link emit}を使用する。
*/
const bus = new GridEventEmitter(); const bus = new GridEventEmitter();
/**
* テーブルコンポーネントのリサイズイベントを監視するための{@link ResizeObserver}。
* 表示切替を検知し、サイズの再計算要求を発行するために使用する(マウント時にコンテンツが表示されていない場合、初手のサイズの自動計算が正常に働かないため)
*
* {@link setTimeout}を経由している理由は、{@link onResize}の中でサイズ再計算要求→サイズ変更が発生するとループとみなされ、
* 「ResizeObserver loop completed with undelivered notifications.」という警告が発生するため(状態管理してるので実際にはループしない)
*
* @see {@link onResize}
*/
const resizeObserver = new ResizeObserver((entries) => setTimeout(() => onResize(entries)));
const { gridSetting, columnSettings, data } = toRefs(props); const { gridSetting, columnSettings, data } = toRefs(props);
@@ -122,14 +136,44 @@ watch(columnSettings, refreshColumnsSetting);
watch(data, refreshData); watch(data, refreshData);
if (_DEV_) { if (_DEV_) {
watch(state, (value) => { watch(state, (value, oldValue) => {
console.log(`state: ${value}`); console.log(`[grid][state] ${oldValue} -> ${value}`);
}); });
} }
function onResize(entries: ResizeObserverEntry[]) {
if (entries.length !== 1 || entries[0].target !== rootEl.value) {
return;
}
const contentRect = entries[0].contentRect;
if (_DEV_) {
console.log(`[grid][resize] contentRect: ${contentRect.width}x${contentRect.height}`);
}
switch (state.value) {
case 'hidden': {
if (contentRect.width > 0 && contentRect.height > 0) {
state.value = 'normal';
// 選択状態が狂うかもしれないので解除しておく
unSelectionRange();
bus.emit('forceRefreshContentSize');
}
break;
}
default: {
if (contentRect.width === 0 || contentRect.height === 0) {
state.value = 'hidden';
}
break;
}
}
}
function onKeyDown(ev: KeyboardEvent) { function onKeyDown(ev: KeyboardEvent) {
if (_DEV_) { if (_DEV_) {
console.log('[Grid]', `ctrl: ${ev.ctrlKey}, shift: ${ev.shiftKey}, code: ${ev.code}`); console.log(`[grid][key] ctrl: ${ev.ctrlKey}, shift: ${ev.shiftKey}, code: ${ev.code}`);
} }
switch (state.value) { switch (state.value) {
@@ -482,7 +526,7 @@ function onChangeCellValue(sender: GridCell, newValue: CellValue) {
function onChangeCellContentSize(sender: GridCell, contentSize: Size) { function onChangeCellContentSize(sender: GridCell, contentSize: Size) {
cells.value[sender.address.row][sender.address.col].contentSize = contentSize; cells.value[sender.address.row][sender.address.col].contentSize = contentSize;
if (sender.column.setting.width === 'auto') { if (sender.column.setting.width === 'auto') {
largestCellWidth(sender.column); calcLargestCellWidth(sender.column);
} }
} }
@@ -519,7 +563,7 @@ function onHeaderCellChangeContentSize(sender: GridColumn, newSize: Size) {
case 'normal': { case 'normal': {
columns.value[sender.index].contentSize = newSize; columns.value[sender.index].contentSize = newSize;
if (sender.setting.width === 'auto') { if (sender.setting.width === 'auto') {
largestCellWidth(sender); calcLargestCellWidth(sender);
} }
break; break;
} }
@@ -529,13 +573,13 @@ function onHeaderCellChangeContentSize(sender: GridColumn, newSize: Size) {
function onHeaderCellWidthLargest(sender: GridColumn) { function onHeaderCellWidthLargest(sender: GridColumn) {
switch (state.value) { switch (state.value) {
case 'normal': { case 'normal': {
largestCellWidth(sender); calcLargestCellWidth(sender);
break; break;
} }
} }
} }
function largestCellWidth(column: GridColumn) { function calcLargestCellWidth(column: GridColumn) {
const _cells = cells.value; const _cells = cells.value;
const largestColumnWidth = columns.value[column.index].contentSize.width; const largestColumnWidth = columns.value[column.index].contentSize.width;
@@ -548,7 +592,9 @@ function largestCellWidth(column: GridColumn) {
) )
: 0; : 0;
console.log(`largestCellWidth: ${largestColumnWidth}, ${largestCellWidth}`); if (_DEV_) {
console.log(`[grid][calc-largest] idx:${column.setting.bindTo}, col:${largestColumnWidth}, cell:${largestCellWidth}`);
}
column.width = `${Math.max(largestColumnWidth, largestCellWidth)}px`; column.width = `${Math.max(largestColumnWidth, largestCellWidth)}px`;
} }
@@ -800,9 +846,21 @@ function unregisterMouseUp() {
removeEventListener('mouseup', onMouseUp); removeEventListener('mouseup', onMouseUp);
} }
refreshColumnsSetting(); onMounted(() => {
refreshData(); refreshColumnsSetting();
refreshData();
if (rootEl.value) {
resizeObserver.observe(rootEl.value);
// 初期表示時にコンテンツが表示されていない場合はhidden状態にしておく。
// コンテンツ表示時にresizeイベントが発生するが、そのときにhidden状態にしておかないとサイズの再計算が走らないので
const bounds = rootEl.value.getBoundingClientRect();
if (bounds.width === 0 || bounds.height === 0) {
state.value = 'hidden';
}
}
});
</script> </script>
<style module lang="scss"> <style module lang="scss">
@@ -812,7 +870,6 @@ $borderRadius: var(--radius);
.grid { .grid {
overflow: scroll; overflow: scroll;
table-layout: fixed; table-layout: fixed;
width: fit-content;
user-select: none; user-select: none;
} }
@@ -22,7 +22,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, nextTick, ref, toRefs, watch } from 'vue'; import { computed, nextTick, onMounted, onUnmounted, ref, toRefs, watch } from 'vue';
import { GridColumn, GridEventEmitter, Size } from '@/components/grid/grid.js'; import { GridColumn, GridEventEmitter, Size } from '@/components/grid/grid.js';
const emit = defineEmits<{ const emit = defineEmits<{
@@ -51,7 +51,7 @@ const text = computed(() => {
watch(column, () => { watch(column, () => {
// 中身がセットされた直後はサイズが分からないので、次のタイミングで更新する // 中身がセットされた直後はサイズが分からないので、次のタイミングで更新する
nextTick(updateContentSize); nextTick(emitContentSizeChanged);
}, { immediate: true }); }, { immediate: true });
function onHandleDoubleClick(ev: MouseEvent) { function onHandleDoubleClick(ev: MouseEvent) {
@@ -111,6 +111,10 @@ function onHandleMouseUp(ev: MouseEvent) {
} }
} }
function onForceRefreshContentSize() {
emitContentSizeChanged();
}
function registerHandleMouseMove() { function registerHandleMouseMove() {
unregisterHandleMouseMove(); unregisterHandleMouseMove();
addEventListener('mousemove', onHandleMouseMove); addEventListener('mousemove', onHandleMouseMove);
@@ -129,7 +133,7 @@ function unregisterHandleMouseUp() {
removeEventListener('mouseup', onHandleMouseUp); removeEventListener('mouseup', onHandleMouseUp);
} }
function updateContentSize() { function emitContentSizeChanged() {
const clientWidth = contentEl.value?.clientWidth ?? 0; const clientWidth = contentEl.value?.clientWidth ?? 0;
const clientHeight = contentEl.value?.clientHeight ?? 0; const clientHeight = contentEl.value?.clientHeight ?? 0;
emit('change:contentSize', column.value, { emit('change:contentSize', column.value, {
@@ -139,6 +143,14 @@ function updateContentSize() {
}); });
} }
onMounted(() => {
bus.value.on('forceRefreshContentSize', onForceRefreshContentSize);
});
onUnmounted(() => {
bus.value.off('forceRefreshContentSize', onForceRefreshContentSize);
});
</script> </script>
<style module lang="scss"> <style module lang="scss">
@@ -8,7 +8,7 @@ export type GridSetting = {
export type DataSource = Record<string, CellValue>; export type DataSource = Record<string, CellValue>;
export type GridState = 'normal' | 'cellSelecting' | 'cellEditing' | 'colResizing' | 'colSelecting' | 'rowSelecting' export type GridState = 'normal' | 'cellSelecting' | 'cellEditing' | 'colResizing' | 'colSelecting' | 'rowSelecting' | 'hidden'
export type Size = { export type Size = {
width: number; width: number;
@@ -47,5 +47,7 @@ export type CellValueChangedEvent = {
value: CellValue; value: CellValue;
} }
export class GridEventEmitter extends EventEmitter<{}> { export class GridEventEmitter extends EventEmitter<{
'forceRefreshContentSize': void;
}> {
} }