自定义缩放手柄
resizeConfig.handles 和 LayoutItem.resizeHandles 仍是启用方向的唯一来源。resize-handle 插槽只替换每个已启用手柄的视觉内容,定位、指针命中区域、光标和缩放行为继续由 Grid Layout Plus 管理。
插槽会提供配置轴 axis,以及经过 RTL 或镜像渲染后的物理方向 direction。自定义图标需要指向实际显示侧时,应使用 direction。
试一试: 从 Item 0 的任意箭头进行缩放。Item 1 和 Item 2 使用同一套自定义渲染,但分别覆盖了可用方向。
在线示例
vue
<script setup lang="ts">
import { ref } from 'vue'
import { GridLayout } from 'grid-layout-plus'
import type { Layout, ResizeConfig, ResizeHandleAxis } from 'grid-layout-plus'
const resizeConfig: ResizeConfig = {
handles: ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'],
}
const glyphs: Record<ResizeHandleAxis, string> = {
n: '↑',
ne: '↗',
e: '→',
se: '↘',
s: '↓',
sw: '↙',
w: '←',
nw: '↖',
}
const layout = ref<Layout>([
{ x: 0, y: 0, w: 6, h: 3, i: 'all' },
{ x: 6, y: 0, w: 6, h: 3, i: 'limited', resizeHandles: ['e', 's', 'se'] },
])
</script>
<template>
<GridLayout
v-model:layout="layout"
:is-draggable="false"
:resize-config="resizeConfig"
:row-height="30"
>
<template #item="{ item }">
{{ item.i }}
</template>
<template #resize-handle="{ axis, direction }">
<span class="custom-handle" :data-axis="axis">{{ glyphs[direction] }}</span>
</template>
</GridLayout>
</template>vue
<script setup lang="ts">
import { ref } from 'vue'
import type {
InteractionStartPayload,
InteractionTerminalPayload,
Layout,
ResizeConfig,
ResizeHandleAxis,
} from 'grid-layout-plus'
const resizeConfig: ResizeConfig = {
handles: ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'],
}
const directionGlyph: Record<ResizeHandleAxis, string> = {
n: '↑',
ne: '↗',
e: '→',
se: '↘',
s: '↓',
sw: '↙',
w: '←',
nw: '↖',
}
function createLayout(): Layout {
return [
{ x: 0, y: 0, w: 6, h: 4, i: '0' },
{ x: 6, y: 0, w: 6, h: 4, i: '1', resizeHandles: ['e', 's', 'se'] },
{ x: 0, y: 4, w: 12, h: 3, i: '2', resizeHandles: ['n', 'w', 'nw'] },
]
}
const layout = ref(createLayout())
const lastAction = ref('Waiting · resize from a custom arrow handle')
function handleInteractionStart(payload: InteractionStartPayload) {
if (payload.type === 'resize') lastAction.value = `Resizing item ${payload.id}`
}
function handleInteractionEnd(payload: InteractionTerminalPayload) {
if (payload.type === 'resize') lastAction.value = `Resized item ${payload.id}`
}
function itemLabel(id: string) {
if (id === '0') return 'Item 0 · all 8 custom handles'
if (id === '1') return 'Item 1 · E / S / SE'
return 'Item 2 · N / W / NW'
}
function resetDemo() {
layout.value = createLayout()
lastAction.value = 'Reset · resize from a custom arrow handle'
}
</script>
<template>
<section class="demo-root demo-shell">
<div class="demo-toolbar">
<Tag class="demo-state demo-state--accent" type="primary" simple circle>
{{ lastAction }}
</Tag>
<Button button-type="button" @click="resetDemo"> Reset layout </Button>
</div>
<GridLayout
v-model:layout="layout"
class="demo-grid"
:is-draggable="false"
:resize-config="resizeConfig"
:row-height="40"
@interaction-end="handleInteractionEnd"
@interaction-start="handleInteractionStart"
>
<template #item="{ item }">
<span class="demo-item__label" :data-custom-resize-item="item.i">
{{ itemLabel(String(item.i)) }}
</span>
</template>
<template #resize-handle="{ item, axis, direction }">
<span
class="demo-custom-resize-handle"
data-testid="custom-resize-handle"
:data-resize-axis="axis"
:data-resize-direction="direction"
:data-resize-item="item.i"
>
{{ directionGlyph[direction] }}
</span>
</template>
</GridLayout>
</section>
</template>