refactor: 优化viewed实例初始化,rowStyle rowClassName 从最新的配置中读取
parent
28905b0bec
commit
9c49f4bb1e
|
|
@ -6,6 +6,7 @@ import type {
|
|||
} from '@vben-core/form-ui';
|
||||
|
||||
import type { VxeGridProps } from './types';
|
||||
import type {ViewedRowHelper} from './use-viewed-row';
|
||||
|
||||
import { toRaw } from 'vue';
|
||||
|
||||
|
|
@ -42,20 +43,15 @@ export class VxeGridApi<
|
|||
|
||||
public store: Store<VxeGridProps<T, D, P>>;
|
||||
|
||||
/**
|
||||
* 已读行 helper(在 mount 中初始化,业务能力全部封装在 useViewedRow 中)
|
||||
*/
|
||||
public viewedRowHelper: null | ViewedRowHelper<T> = null;
|
||||
|
||||
private isMounted = false;
|
||||
|
||||
private stateHandler: StateHandler;
|
||||
|
||||
// 已读行相关方法(由 use-vxe-grid.vue 注入)
|
||||
private viewedRowHelper: null | {
|
||||
clearViewed: () => void;
|
||||
isViewed: (record: T) => boolean;
|
||||
markAsViewed: (record: T) => void;
|
||||
markKeysAsViewed: (keys: Array<number | string>) => void;
|
||||
removeKeys: (keys: Array<number | string>) => void;
|
||||
viewedSet: { value: Set<number | string> };
|
||||
} = null;
|
||||
|
||||
constructor(options: VxeGridProps<T, D, P> = {} as VxeGridProps<T, D, P>) {
|
||||
const storeState = { ...options };
|
||||
|
||||
|
|
@ -82,7 +78,7 @@ export class VxeGridApi<
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取所有已读的 key 集合
|
||||
* 获取所有已读的 key 集合(返回副本,避免外部修改内部状态)
|
||||
*/
|
||||
getViewedKeys(): Set<number | string> {
|
||||
const raw = this.viewedRowHelper?.viewedSet.value;
|
||||
|
|
@ -170,14 +166,6 @@ export class VxeGridApi<
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置已读行 helper(由组件内部调用)
|
||||
* @internal
|
||||
*/
|
||||
setViewedRowHelper(helper: VxeGridApi<T, D, P>['viewedRowHelper']) {
|
||||
this.viewedRowHelper = helper;
|
||||
}
|
||||
|
||||
toggleSearchForm(show?: boolean) {
|
||||
this.setState({
|
||||
showSearchForm: isBoolean(show) ? show : !this.state?.showSearchForm,
|
||||
|
|
@ -191,5 +179,6 @@ export class VxeGridApi<
|
|||
unmount() {
|
||||
this.isMounted = false;
|
||||
this.stateHandler.reset();
|
||||
this.viewedRowHelper = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ export interface VxeGridProps<
|
|||
/**
|
||||
* 已读行功能
|
||||
*/
|
||||
viewedRow?: boolean | ViewedRowOptions<T>;
|
||||
viewedRowOptions?: boolean | ViewedRowOptions<T>;
|
||||
}
|
||||
|
||||
export type ExtendedVxeGridApi<
|
||||
|
|
|
|||
|
|
@ -373,6 +373,8 @@ export function useViewedRow<T = any>(
|
|||
};
|
||||
}
|
||||
|
||||
export type ViewedRowHelper<T = any> = ReturnType<typeof useViewedRow<T>>;
|
||||
|
||||
// ========== 工具函数 ==========
|
||||
|
||||
function normalizeClassName(value: any): string {
|
||||
|
|
@ -445,24 +447,64 @@ export function applyViewedRowOptions(
|
|||
viewedRowConfig: boolean | ViewedRowOptions,
|
||||
helper: ReturnType<typeof useViewedRow>,
|
||||
) {
|
||||
// 从最新的配置中读取 rowClassName 和 rowStyle(支持运行时修改)
|
||||
const viewedRowClassName = isBoolean(viewedRowConfig)
|
||||
? undefined
|
||||
: viewedRowConfig.rowClassName;
|
||||
const viewedRowStyle = isBoolean(viewedRowConfig)
|
||||
? undefined
|
||||
: viewedRowConfig.rowStyle;
|
||||
|
||||
// 注入 rowClassName
|
||||
const originalRowClassName = mergedOptions.rowClassName;
|
||||
mergedOptions.rowClassName = (params: any) => {
|
||||
if (!helper.isViewed(params.row)) {
|
||||
return normalizeClassName(
|
||||
isFunction(originalRowClassName)
|
||||
? originalRowClassName(params)
|
||||
: originalRowClassName,
|
||||
);
|
||||
}
|
||||
|
||||
let viewedClass: string;
|
||||
if (viewedRowClassName === undefined || viewedRowClassName === null) {
|
||||
viewedClass = DEFAULT_VIEWED_CLASS;
|
||||
} else if (typeof viewedRowClassName === 'string') {
|
||||
viewedClass = viewedRowClassName;
|
||||
} else if (isFunction(viewedRowClassName)) {
|
||||
viewedClass = normalizeClassName(viewedRowClassName(params));
|
||||
} else {
|
||||
viewedClass = DEFAULT_VIEWED_CLASS;
|
||||
}
|
||||
|
||||
return mergeClassNames(
|
||||
isFunction(originalRowClassName)
|
||||
? originalRowClassName(params)
|
||||
: originalRowClassName,
|
||||
helper.getRowClassName(params),
|
||||
viewedClass,
|
||||
);
|
||||
};
|
||||
|
||||
// 注入 rowStyle
|
||||
const originalRowStyle = mergedOptions.rowStyle;
|
||||
mergedOptions.rowStyle = (params: any) => {
|
||||
const viewedStyle = helper.getRowStyle(params);
|
||||
const originalStyle = isFunction(originalRowStyle)
|
||||
? originalRowStyle(params)
|
||||
: originalRowStyle;
|
||||
|
||||
if (!helper.isViewed(params.row)) {
|
||||
return originalStyle || undefined;
|
||||
}
|
||||
|
||||
let viewedStyle: any;
|
||||
if (viewedRowStyle === undefined || viewedRowStyle === null) {
|
||||
viewedStyle = undefined;
|
||||
} else if (isFunction(viewedRowStyle)) {
|
||||
viewedStyle = viewedRowStyle(params);
|
||||
} else {
|
||||
viewedStyle = viewedRowStyle;
|
||||
}
|
||||
|
||||
if (!viewedStyle && !originalStyle) return undefined;
|
||||
if (!originalStyle) return viewedStyle;
|
||||
if (!viewedStyle) return originalStyle;
|
||||
|
|
|
|||
|
|
@ -19,12 +19,10 @@ import {
|
|||
nextTick,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
shallowRef,
|
||||
toRaw,
|
||||
useSlots,
|
||||
useTemplateRef,
|
||||
watch,
|
||||
watchEffect,
|
||||
} from 'vue';
|
||||
|
||||
import { usePriorityValues } from '@vben/hooks';
|
||||
|
|
@ -79,45 +77,31 @@ const {
|
|||
tableTitleHelp,
|
||||
showSearchForm,
|
||||
separator,
|
||||
viewedRow,
|
||||
viewedRowOptions,
|
||||
} = usePriorityValues(props, state);
|
||||
|
||||
// ========== 已读行:响应 viewedRow 配置变化 ==========
|
||||
const defaultKeyField = (gridOptions.value?.rowConfig as any)?.keyField || 'id';
|
||||
// viewedRowOptions:helper 只创建一次(persist/keyField 不支持运行时切换)
|
||||
// actionCodes、rowClassName、rowStyle、viewedKeys 的变化通过 options computed 自然响应
|
||||
const gridApi = props.api;
|
||||
|
||||
const viewedRowHelper = shallowRef<null | ReturnType<typeof useViewedRow>>(
|
||||
null,
|
||||
);
|
||||
|
||||
// 初始化 + 监听配置变化时重建 helper
|
||||
watch(
|
||||
viewedRow,
|
||||
viewedRowOptions,
|
||||
(cfg) => {
|
||||
if (!cfg) {
|
||||
viewedRowHelper.value = null;
|
||||
props.api?.setViewedRowHelper?.(null);
|
||||
return;
|
||||
}
|
||||
const resolvedOptions = isBoolean(cfg)
|
||||
? {keyField: defaultKeyField}
|
||||
: {keyField: defaultKeyField, ...cfg};
|
||||
viewedRowHelper.value = useViewedRow(resolvedOptions);
|
||||
// 同步更新 API 中的 helper 引用
|
||||
if (props.api?.setViewedRowHelper) {
|
||||
props.api.setViewedRowHelper(viewedRowHelper.value);
|
||||
}
|
||||
// helper 已存在则不重建
|
||||
if (gridApi.viewedRowHelper) return;
|
||||
|
||||
if (!cfg) return;
|
||||
|
||||
const keyField =
|
||||
(gridOptions.value?.rowConfig as any)?.keyField || 'id';
|
||||
const resolved = isBoolean(cfg)
|
||||
? {keyField}
|
||||
: {keyField, ...cfg};
|
||||
gridApi.viewedRowHelper = useViewedRow(resolved);
|
||||
},
|
||||
{immediate: true},
|
||||
);
|
||||
|
||||
// viewedSet 变化时,主动刷新 grid 行样式
|
||||
watchEffect(() => {
|
||||
const helper = viewedRowHelper.value;
|
||||
if (!helper) return;
|
||||
// 访问 viewedSet.value 建立依赖追踪
|
||||
void helper.viewedSet.value;
|
||||
});
|
||||
|
||||
const { isMobile } = usePreferences();
|
||||
const isSeparator = computed(() => {
|
||||
if (
|
||||
|
|
@ -276,11 +260,11 @@ const options = computed(() => {
|
|||
}
|
||||
|
||||
// 注入已读行功能(rowClassName、rowStyle、columns 拦截)
|
||||
if (viewedRow.value && viewedRowHelper.value) {
|
||||
if (viewedRowOptions.value && gridApi.viewedRowHelper) {
|
||||
applyViewedRowOptions(
|
||||
mergedOptions,
|
||||
viewedRow.value,
|
||||
viewedRowHelper.value,
|
||||
viewedRowOptions.value,
|
||||
gridApi.viewedRowHelper,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ const gridOptions: VxeGridProps<RowType> = {
|
|||
|
||||
const [Grid, gridApi] = useVbenVxeGrid({
|
||||
gridOptions,
|
||||
viewedRow: {
|
||||
viewedRowOptions: {
|
||||
// 触发已读的操作码
|
||||
actionCodes: ['view'],
|
||||
// 行数据中的唯一标识字段
|
||||
|
|
@ -144,6 +144,33 @@ function onView(row: RowType) {
|
|||
});
|
||||
}
|
||||
|
||||
const isStyle = ref(false);
|
||||
|
||||
function onStyleSet() {
|
||||
isStyle.value = !isStyle.value;
|
||||
gridApi.setState({
|
||||
viewedRowOptions: {
|
||||
rowStyle: () => {
|
||||
return isStyle.value ? {backgroundColor: 'gray'} : '';
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const isClassName = ref(false);
|
||||
|
||||
function onClassNameSet() {
|
||||
isClassName.value = !isClassName.value;
|
||||
gridApi.setState({
|
||||
viewedRowOptions: {
|
||||
rowClassName: () => {
|
||||
|
||||
return isClassName.value ? 'bg-red-100 vxe-row--viewed' : 'vxe-row--viewed';
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function onCustomSet() {
|
||||
const tableData = gridApi.grid.getData();
|
||||
const keys = tableData.slice(0, 2).map((row) => row.id);
|
||||
|
|
@ -168,7 +195,13 @@ function onClearViewed() {
|
|||
<Grid table-title="已查看行标记" table-title-help="提示">
|
||||
<template #toolbar-tools>
|
||||
<Button class="mr-2" type="primary" @click="onCustomSet">
|
||||
手动设置
|
||||
手动标记
|
||||
</Button>
|
||||
<Button class="mr-2" type="primary" @click="onStyleSet">
|
||||
设置Style
|
||||
</Button>
|
||||
<Button class="mr-2" type="primary" @click="onClassNameSet">
|
||||
设置ClassName
|
||||
</Button>
|
||||
<Button type="primary" @click="onClearViewed"> 清空缓存</Button>
|
||||
</template>
|
||||
|
|
|
|||
Loading…
Reference in New Issue