Skip to content

PageDesigner 页面设计器

可视化页面设计器,支持拖拽组件、自由布局、数据绑定等功能。

基础用法

最基础的页面设计器用法。

vue
<template>
  <NPageDesigner
    :schema="schema"
    @save="handleSave"
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [],
  dataFlow: [],
})

const handleSave = (data) => {
  console.log('保存页面:', data)
}
</script>

使用模板

使用预设模板快速创建页面。

vue
<template>
  <NPageDesigner
    :schema="schema"
    :templates="templates"
    @save="handleSave"
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [],
  dataFlow: [],
})

const templates = [
  {
    id: 'blank',
    name: '空白页面',
    description: '从空白页面开始设计',
    schema: {
      components: [],
      dataFlow: [],
    },
  },
  {
    id: 'form',
    name: '表单页面',
    description: '包含常用表单组件的页面',
    schema: {
      components: [
        { type: 'input', props: { label: '姓名' } },
        { type: 'select', props: { label: '性别' } },
      ],
      dataFlow: [],
    },
  },
]

const handleSave = (data) => {
  console.log('保存页面:', data)
}
</script>

自由布局

支持自由拖拽和定位组件。

vue
<template>
  <NPageDesigner
    :schema="schema"
    layout="free"
    @save="handleSave"
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [
    {
      id: '1',
      type: 'button',
      props: { text: '按钮' },
      position: { x: 100, y: 100, width: 120, height: 40 },
    },
  ],
  dataFlow: [],
})

const handleSave = (data) => {
  console.log('保存页面:', data)
}
</script>

网格布局

使用网格布局系统。

vue
<template>
  <NPageDesigner
    :schema="schema"
    layout="grid"
    :gridSize="12"
    @save="handleSave"
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [
    {
      id: '1',
      type: 'button',
      props: { text: '按钮' },
      grid: { col: 1, row: 1, colSpan: 2, rowSpan: 1 },
    },
  ],
  dataFlow: [],
})

const handleSave = (data) => {
  console.log('保存页面:', data)
}
</script>

数据绑定

支持组件之间的数据绑定。

vue
<template>
  <NPageDesigner
    :schema="schema"
    @save="handleSave"
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [
    {
      id: 'input1',
      type: 'input',
      props: { label: '输入框' },
    },
    {
      id: 'text1',
      type: 'text',
      props: { content: '' },
    },
  ],
  dataFlow: [
    {
      source: { componentId: 'input1', output: 'value' },
      target: { componentId: 'text1', input: 'content' },
    },
  ],
})

const handleSave = (data) => {
  console.log('保存页面:', data)
}
</script>

自定义组件

注册自定义组件。

vue
<template>
  <NPageDesigner
    :schema="schema"
    :customComponents="customComponents"
    @save="handleSave"
  />
</template>

<script setup>
import { ref } from 'vue')
import MyComponent from './MyComponent.vue')

const schema = ref({
  components: [],
  dataFlow: [],
})

const customComponents = [
  {
    type: 'my-component',
    name: '自定义组件',
    icon: 'custom',
    component: MyComponent,
    defaultProps: {
      text: '默认文本',
    },
  },
]

const handleSave = (data) => {
  console.log('保存页面:', data)
}
</script>

只读模式

设置 readonly 属性为 true 进入只读模式。

vue
<template>
  <NPageDesigner
    :schema="schema"
    readonly
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [
    {
      id: '1',
      type: 'button',
      props: { text: '按钮' },
      position: { x: 100, y: 100, width: 120, height: 40 },
    },
  ],
  dataFlow: [],
})
</script>

预览模式

设置 preview 属性为 true 进入预览模式。

vue
<template>
  <div>
    <NButton @click="preview = !preview">
      {{ preview ? '编辑' : '预览' }}
    </NButton>
    <NPageDesigner
      :schema="schema"
      :preview="preview"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue')

const preview = ref(false)
const schema = ref({
  components: [
    {
      id: '1',
      type: 'button',
      props: { text: '按钮' },
      position: { x: 100, y: 100, width: 120, height: 40 },
    },
  ],
  dataFlow: [],
})
</script>

禁用拖拽

设置 draggable 属性为 false 禁用拖拽。

vue
<template>
  <NPageDesigner
    :schema="schema"
    :draggable="false"
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [
    {
      id: '1',
      type: 'button',
      props: { text: '按钮' },
      position: { x: 100, y: 100, width: 120, height: 40 },
    },
  ],
  dataFlow: [],
})
</script>

禁用调整大小

设置 resizable 属性为 false 禁用调整大小。

vue
<template>
  <NPageDesigner
    :schema="schema"
    :resizable="false"
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [
    {
      id: '1',
      type: 'button',
      props: { text: '按钮' },
      position: { x: 100, y: 100, width: 120, height: 40 },
    },
  ],
  dataFlow: [],
})
</script>

显示网格

设置 showGrid 属性为 true 显示网格。

vue
<template>
  <NPageDesigner
    :schema="schema"
    showGrid
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [
    {
      id: '1',
      type: 'button',
      props: { text: '按钮' },
      position: { x: 100, y: 100, width: 120, height: 40 },
    },
  ],
  dataFlow: [],
})
</script>

吸附对齐

设置 snap 属性为 true 启用吸附对齐。

vue
<template>
  <NPageDesigner
    :schema="schema"
    snap
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [
    {
      id: '1',
      type: 'button',
      props: { text: '按钮' },
      position: { x: 100, y: 100, width: 120, height: 40 },
    },
  ],
  dataFlow: [],
})
</script>

事件监听

vue
<template>
  <NPageDesigner
    :schema="schema"
    @save="handleSave"
    @select="handleSelect"
    @deselect="handleDeselect"
    @dragStart="handleDragStart"
    @dragEnd="handleDragEnd"
    @resizeStart="handleResizeStart"
    @resizeEnd="handleResizeEnd"
  />
</template>

<script setup>
import { ref } from 'vue')

const schema = ref({
  components: [],
  dataFlow: [],
})

const handleSave = (data) => {
  console.log('保存:', data)
}

const handleSelect = (component) => {
  console.log('选中:', component)
}

const handleDeselect = () => {
  console.log('取消选中')
}

const handleDragStart = (component) => {
  console.log('开始拖拽:', component)
}

const handleDragEnd = (component) => {
  console.log('结束拖拽:', component)
}

const handleResizeStart = (component) => {
  console.log('开始调整大小:', component)
}

const handleResizeEnd = (component) => {
  console.log('结束调整大小:', component)
}
</script>

API

Props

属性说明类型默认值
schema页面 schemaPageSchema
templates预设模板列表PageTemplate[][]
customComponents自定义组件列表CustomComponent[][]
layout布局模式'free' | 'grid''free'
gridSize网格大小number12
readonly是否只读模式booleanfalse
preview是否预览模式booleanfalse
draggable是否可拖拽booleantrue
resizable是否可调整大小booleantrue
showGrid是否显示网格booleanfalse
snap是否启用吸附对齐booleantrue

PageSchema

属性说明类型
components组件列表LayoutNode[]
dataFlow数据流配置DataFlowConfig[]

LayoutNode

属性说明类型
id组件 IDstring
type组件类型string
props组件属性Record<string, any>
position位置和尺寸(自由布局){ x: number; y: number; width: number; height: number }
grid网格位置(网格布局){ col: number; row: number; colSpan: number; rowSpan: number }

DataFlowConfig

属性说明类型
source数据源{ componentId: string; output: string }
target数据目标{ componentId: string; input: string }

Events

事件名说明类型
save保存时触发(schema: PageSchema) => void
select选中组件时触发(component: LayoutNode) => void
deselect取消选中时触发() => void
dragStart开始拖拽时触发(component: LayoutNode) => void
dragEnd结束拖拽时触发(component: LayoutNode) => void
resizeStart开始调整大小时触发(component: LayoutNode) => void
resizeEnd结束调整大小时触发(component: LayoutNode) => void

方法

方法名说明类型
save保存页面() => void
undo撤销操作() => void
redo重做操作() => void
clear清空所有组件() => void
getSchema获取当前 schema() => PageSchema
setSchema设置 schema(schema: PageSchema) => void