有人有如何在 ag 网格内渲染 svelte 组件的示例吗? 类似于如何在 ag-grid 中渲染 angularjs 或 React 组件。
只是为了添加@ben-sewards 答案,我想出了一个工厂函数,使我可以更轻松地嵌入随机组件。
/**
* Base class for embedding a svelte component within an AGGrid call.
* See: https://stackoverflow.com/a/72608215
*/
import type {
ICellRendererComp,
ICellRendererParams
} from "ag-grid-community";
/**
* Class for defining a cell renderer.
* If you don't need to define a separate class you could use cellRendererFactory
* to create a component with the column definitions.
*/
export abstract class AbstractCellRenderer implements ICellRendererComp {
eGui: any
protected value: any
constructor(parentElement = "span") {
// create empty span (or other element) to place svelte component in
this.eGui = document.createElement(parentElement);
}
init(params: ICellRendererParams) {
this.value = params.value;
this.createComponent(params);
}
getGui() {
return this.eGui;
}
refresh(params: ICellRendererParams) {
this.value = params.value;
this.eGui.innerHTML = '';
return true;
}
/**
* Define and create the svelte component to use in the cell
* @example
* // This is all you need to do within this method: create the component with new, specify the target
* // is the class, and pass in props via the params.
* new CampusIcon({
* target: this.eGui,
* props: {
* color: params.data?.color,
* name: params.data?.name
* }
* @param params params for rendering the call, including the value for the cell
*/
abstract createComponent(params: ICellRendererParams): void
}
/**
* Creates a cell renderer using the given callback for how to initialise a svelte component.
* See AbstractCellRenderer.createComponent
* @param svelteComponent function for how to create the svelte component
* @returns
*/
export function cellRendererFactory(svelteComponent: (cell: AbstractCellRenderer, params: ICellRendererParams) => void) {
class Renderer extends AbstractCellRenderer {
createComponent(params: ICellRendererParams < any, any > ): void {
svelteComponent(this, params)
}
}
return Renderer;
}
然后对于列定义,像这样使用它:
import CampusIcon from '$lib/components/campus/CampusIcon.svelte';
const columnDefs = [
{
field: 'campusId',
cellRenderer: cellRendererFactory((c, p) => {
new CampusIcon({
target: c.eGui,
props: {
color: p.data?.color,
name: p.data?.name
}
});
}),
headerName: 'Campus',
}
]
由于 AG-Grid 没有 Svelte 扩展,您可能必须使用 Svelte 客户端组件 API 来处理此问题。
编辑:下面经过测试的工作方法
创建 CellRenderer
import SiteAccountCellButtonSvelte from "./SiteAccountCellButton.svelte";
export class SiteAccountButtonRenderer {
constructor() {
// create empty div to place svelte component in
this.eGui = document.createElement("div");
}
init(params: ICellRendererParams) {
this.value = params.value;
new SiteAccountCellButtonSvelte({
target: this.eGui,
props: {
// your props here
siteBalance: params.data,
},
});
}
getGui() {
return this.eGui;
}
refresh(params) {
this.value = params.value;
this.eGui.innerHTML = '';
return true;
}
}
配置 AG-Grid 选项
const gridOptions: GridOptions = {
pagination: true,
paginationPageSize: 15,
domLayout: "autoHeight",
rowHeight: 56,
defaultColDef: {
sortable: true,
unSortIcon: true,
resizable: true,
flex: 1,
minWidth: 170,
},
columnDefs: [
{
headerName: "account name",
field: "accountName",
filter: true,
floatingFilter: true,
cellClass: (_params: CellClassParams) => {
return "fw-bold";
},
cellRenderer: SiteAccountButtonRenderer,
},
// more columnDefs here
],
};
在父 Svelte 组件中初始化网格
<script lang="ts">
import { Grid } from "@ag-grid-community/core";
import { onMount } from "svelte";
import type { SiteBalance, SiteBalancesViewModel } from "../../../typings/Payments";
import { createGridOptions } from "./SiteBalances";
export let vm: SiteBalancesViewModel;
export let data: SiteBalance[];
let gridEl: HTMLElement;
onMount(async () => {
const gridOptions = createGridOptions(vm);
new Grid(gridEl, gridOptions);
gridOptions.api.setRowData(data);
});
</script>
<div style="height: 100%;" bind:this={gridEl} class="ag-theme-alpine" />
原答案
我以前没有设置过这个,但一般设置可能是这样的:
init
方法中,确保使用 svelte 组件的 CSS 选择器将 this.eGui.innerHTML
属性设置为空 div (<div class="svelte-widget"></div>
)
2b.在相同的 init
方法中,初始化 svelte 组件:import SvelteWidget, { selector as SvelteWidgetSelector } from "./your-path/SvelteWidget.svelte";
class SvelteWidgetRenderer {
init(params) {
this.eGui = document.createElement('div');
this.eGui.classList.add('svelte-widget');
// initialize svelte widget with client-side component API
new SvelteWidget({ target: this.eGui, props: { /* your props */ });
}
}
svelte 小部件“选择器”是可选的,因为我们将 svelte 组件附加到 ag-grid DOM 元素
我刚刚遇到了同样的问题,并在 svelte 5 项目中实现了这个问题。对于任何想知道的人来说,它最终在主要组件中看起来像这样(还有一堆额外的东西需要刷新):
...
{
field: FIELD_NAMES.STATUS,
headerName: DISPLAY_NAMES.status,
editable: false,
maxWidth: 80,
cellRenderer: cellRendererFactory((cell, params) => {
const props = $state({ value: params.value });
const component = mount(CellRendererStatus, {
target: cell.eGui,
props
});
cell.refresh = (refreshParams: ICellRendererParams) => {
props.value = refreshParams.value;
return true;
};
return component;
// optimize might have to cleanup? ... return () => { component.$destroy(); };
})
}
不要忘记导入
ICellRendererParams
和要在单元格内渲染的组件(相应地调整你的组件),还有 mount
:
import type ICellRendererParams from "../../node_modules/ag-grid-community";
import CellRendererStatus from "./CellRendererStatus.svelte";
import { mount } from "svelte";
CellRendererStatus.svelte
是我的自定义组件,如下所示:
<script lang="ts">
import { CheckCircleSolid, CloseCircleSolid } from "flowbite-svelte-icons";
// this is the important bit
export let value: boolean;
</script>
<div class="mt-1">
{#if value}
<CheckCircleSolid class="text-green-500"></CheckCircleSolid>
{:else}
<CloseCircleSolid class="text-red-500"></CloseCircleSolid>
{/if}
</div>
我在单独的
AbstractCellRenderer.ts
文件中添加了 @Corrl 建议的完全相同的代码。希望这有帮助!