import { computed, defineComponent, PropType, provide, ref, watch } from 'vue' import deepcopy from 'deepcopy' import FormBlock from './components/FormBlock' import { registerConfig } from './utils/edit-config' import { useMenuDragger } from './hooks/useMenuDragger' import { useFocus } from './hooks/useFocus' import { useBlockDragger } from './hooks/useBlockDragger' import { useCommand } from './hooks/useCommand' import { $dialog } from './components/Dialog' import { $dropdown, DropdownItem } from './components/Dropdown' import { ElButton } from 'element-plus' import EditorOperator from './components/EditorOperator' import { isNumber } from 'skzz-utils' export interface IDfOpts { container: { width: string | number height: string | number } blocks: Array } export interface IBlock { top: number left: number zIndex: number key: string focus: boolean props: IBlockProps | null } export interface IBlockProps{ text: string color: string size: string } export default defineComponent({ name: 'SkDynamicForm', components: { FormBlock, EditorOperator }, emits: ['update:modelValue'], props: { modelValue: { type: Object as PropType }, formData: { type: Object }, edit: { type: Boolean, default: true, }, }, setup(props, ctx) { const config = registerConfig provide('config', config) const data = computed({ get() { return props.modelValue }, set (newValue) { ctx.emit('update:modelValue', deepcopy(newValue)) }, }) const containerStyles = computed(() => { const isWNumber = isNumber(Number(data.value.container.width)) const isHNumber = isNumber(Number(data.value.container.height)) return { width: isWNumber ? data.value.container.width + 'px' : data.value.container.width, height: isHNumber ? data.value.container.height + 'px' : data.value.container.height, } }) const previewRef = ref(false) const containerRef = ref(null) const editorRef = ref(true) watch(() => props.edit, v => editorRef.value = v) // 1.实现菜单的拖拽功能 const { dragstart, dragend } = useMenuDragger(containerRef, data) // 2.实现获取焦点 选中后可能直接就进行拖拽了 const { blockMousedown, focusData, containerMousedown, lastSelectBlock, clearBlockFocus, } = useFocus(data, previewRef, e => { // 获取焦点后进行拖拽 mousedown(e) }) // 2.实现组件拖拽 const { mousedown, markLine } = useBlockDragger(focusData, lastSelectBlock, data, containerRef) const { commands } = useCommand(data, focusData) const buttons = [ { label: '撤销', icon: 'skicon-back', handler: () => commands.undo() }, { label: '重做', icon: 'skicon-forward', handler: () => commands.redo() }, { label: '导出', icon: 'skicon-export', handler: () => { $dialog({ title: '导出json使用', content: JSON.stringify(data.value), }) }, }, { label: '导入', icon: 'skicon-import', handler: () => { $dialog({ title: '导入json使用', content: '', footer: true, onConfirm(text) { //data.value = JSON.parse(text); // 这样去更改无法保留历史记录 commands.updateContainer(JSON.parse(text)) }, }) }, }, { label: '置顶', icon: 'skicon-place-top', handler: () => commands.placeTop() }, { label: '置底', icon: 'skicon-place-bottom', handler: () => commands.placeBottom() }, { label: '删除', icon: 'skicon-delete', handler: () => commands.delete() }, { label: () => previewRef.value ? '编辑' : '预览', icon: () => previewRef.value ? 'skicon-edit' : 'skicon-browse', handler: () => { previewRef.value = !previewRef.value clearBlockFocus() }, }, { label: '关闭', icon: 'skicon-close', handler: () => { editorRef.value = false clearBlockFocus() }, }, ] const onContextMenuBlock = (e, block) => { e.preventDefault() $dropdown({ el: e.target, // 以哪个元素为准产生一个dropdown content: () => { return <> commands.delete()}> commands.placeTop()}> commands.placeBottom()}> { $dialog({ title: '查看节点数据', content: JSON.stringify(block), }) }}> { $dialog({ title: '导入节点数据', content: '', footer: true, onConfirm(text) { text = JSON.parse(text) commands.updateBlock(text, block) }, }) }}> }, }) } return () => !editorRef.value ? <>
{ (data.value.blocks.map((block, index) => ( ))) }
editorRef.value = true}>继续编辑 {JSON.stringify(props.formData)}
:
{ buttons.map((btn, index) => { const icon = typeof btn.icon == 'function' ? btn.icon() : btn.icon const label = typeof btn.label == 'function' ? btn.label() : btn.label return
{label}
}) }
{/* 根据注册列表 渲染对应的内容 可以实现h5的拖拽*/} {config.componentList.map(component => (
dragstart(e, component)} onDragend={dragend} > {component.label}
{component.preview()}
))}
{/* 负责产生滚动条 */}
{/* 产生内容区域 */}
{ (data.value.blocks.map((block, index) => ( blockMousedown(e, block, index)} onContextmenu={e => onContextMenuBlock(e, block)} formData={props.formData} > ))) } {markLine.x !== null &&
} {markLine.y !== null &&
}
}, })