预设响应式布局
v-model:responsive-layouts 为每个断点保存一份布局。较窄的断点没有预设时,Grid Layout Plus 会根据最近的可用断点布局生成,并写回模型。
试一试: 调整页面宽度,依次经过 lg、md 和更窄的断点。来源标签会标明当前布局来自预设还是自动生成。
在线示例
vue
<script setup lang="ts">
import { ref } from 'vue'
import { GridLayout } from 'grid-layout-plus'
import type { Layout, ResponsiveLayoutsInput } from 'grid-layout-plus'
const responsiveLayouts = ref<ResponsiveLayoutsInput>({
md: [
{ x: 0, y: 0, w: 2, h: 2, i: 'a' },
{ x: 2, y: 0, w: 2, h: 3, i: 'b' },
{ x: 4, y: 0, w: 2, h: 2, i: 'c' },
],
lg: [
{ x: 0, y: 0, w: 3, h: 2, i: 'a' },
{ x: 3, y: 0, w: 3, h: 3, i: 'b' },
{ x: 6, y: 0, w: 3, h: 2, i: 'c' },
],
})
const layout = ref<Layout>(responsiveLayouts.value.lg?.map(item => ({ ...item })) ?? [])
</script>
<template>
<GridLayout
v-model:layout="layout"
v-model:responsive-layouts="responsiveLayouts"
responsive
:row-height="30"
>
<template #item="{ item }">
{{ item.i }}
</template>
</GridLayout>
</template>vue
<script setup lang="ts">
import { computed, ref } from 'vue'
import type {
Breakpoint,
Layout,
LayoutUpdateMeta,
ReadonlyLayout,
ResponsiveLayoutsInput,
WidthChangedPayload,
} from 'grid-layout-plus'
const defaultCols: Record<Breakpoint, number> = {
lg: 12,
md: 10,
sm: 6,
xs: 4,
xxs: 2,
}
const explicitPresets = new Set<Breakpoint>(['md', 'lg'])
function createResponsiveLayouts(): ResponsiveLayoutsInput {
return {
md: [
{ x: 0, y: 0, w: 2, h: 2, i: '0' },
{ x: 2, y: 0, w: 2, h: 3, i: '1' },
{ x: 4, y: 0, w: 2, h: 2, i: '2' },
{ x: 6, y: 0, w: 2, h: 3, i: '3' },
{ x: 8, y: 0, w: 2, h: 2, i: '4' },
{ x: 0, y: 3, w: 2, h: 2, i: '5' },
],
lg: [
{ x: 0, y: 0, w: 2, h: 2, i: '0' },
{ x: 2, y: 0, w: 2, h: 3, i: '1' },
{ x: 4, y: 0, w: 2, h: 2, i: '2' },
{ x: 6, y: 0, w: 2, h: 3, i: '3' },
{ x: 8, y: 0, w: 2, h: 2, i: '4' },
{ x: 10, y: 0, w: 2, h: 3, i: '5' },
],
}
}
function cloneLayout(layout: ReadonlyLayout): Layout {
return layout.map(item => ({ ...item }))
}
const responsiveLayouts = ref<ResponsiveLayoutsInput>(createResponsiveLayouts())
const layout = ref(cloneLayout(responsiveLayouts.value.lg ?? []))
const containerWidth = ref(0)
const currentBreakpoint = ref<Breakpoint | null>(null)
const currentCols = ref(12)
const lastAction = ref('Waiting for container measurement')
const layoutSource = computed(() => {
if (!currentBreakpoint.value) return 'Waiting'
return explicitPresets.has(currentBreakpoint.value) ? 'Explicit preset' : 'Generated fallback'
})
function handleWidthChanged(payload: WidthChangedPayload) {
containerWidth.value = Math.round(payload.width)
currentBreakpoint.value = payload.committed.breakpoint
currentCols.value = payload.committed.cols
}
function handleBreakpointChanged(
breakpoint: Breakpoint | null,
nextLayout: ReadonlyLayout,
_meta: LayoutUpdateMeta,
) {
currentBreakpoint.value = breakpoint
currentCols.value = breakpoint ? defaultCols[breakpoint] : 12
lastAction.value = breakpoint
? `${breakpoint} loaded · ${nextLayout.length} items`
: 'Responsive mode inactive'
}
function resetDemo() {
responsiveLayouts.value = createResponsiveLayouts()
lastAction.value = 'Presets restored'
}
</script>
<template>
<section class="demo-root demo-shell">
<div class="demo-toolbar">
<Tag class="demo-state demo-state--accent" type="primary" simple circle>
Responsive layouts
</Tag>
<Tag class="demo-state" simple circle> {{ lastAction }} </Tag>
<Button button-type="button" @click="resetDemo"> Reset presets </Button>
</div>
<dl class="demo-metrics">
<div class="demo-metric">
<dt>Width</dt>
<dd>{{ containerWidth }}px</dd>
</div>
<div class="demo-metric">
<dt>Breakpoint</dt>
<dd>{{ currentBreakpoint ?? 'measuring' }}</dd>
</div>
<div class="demo-metric">
<dt>Columns</dt>
<dd>{{ currentCols }}</dd>
</div>
<div class="demo-metric">
<dt>Layout source</dt>
<dd>{{ layoutSource }}</dd>
</div>
<div class="demo-metric">
<dt>Items</dt>
<dd>{{ layout.length }}</dd>
</div>
</dl>
<GridLayout
v-model:layout="layout"
v-model:responsive-layouts="responsiveLayouts"
class="demo-grid"
:row-height="30"
responsive
@breakpoint-changed="handleBreakpointChanged"
@width-changed="handleWidthChanged"
>
<template #item="{ item }">
<span class="demo-item__label">{{ item.i }}</span>
</template>
</GridLayout>
</section>
</template>