test:1.组件嵌套拖拽

2.schema定义与动态绑定
This commit is contained in:
lhj
2024-08-01 01:06:00 +08:00
parent 0c148a6401
commit 309e045720
13 changed files with 824 additions and 457 deletions

4
auto-imports.d.ts vendored
View File

@ -152,6 +152,7 @@ declare global {
const useDeviceOrientation: typeof import('@vueuse/core')['useDeviceOrientation']
const useDevicePixelRatio: typeof import('@vueuse/core')['useDevicePixelRatio']
const useDevicesList: typeof import('@vueuse/core')['useDevicesList']
const useDialog: typeof import('naive-ui')['useDialog']
const useDisplayMedia: typeof import('@vueuse/core')['useDisplayMedia']
const useDocumentVisibility: typeof import('@vueuse/core')['useDocumentVisibility']
const useDraggable: typeof import('@vueuse/core')['useDraggable']
@ -184,6 +185,7 @@ declare global {
const useKeyModifier: typeof import('@vueuse/core')['useKeyModifier']
const useLastChanged: typeof import('@vueuse/core')['useLastChanged']
const useLink: typeof import('vue-router')['useLink']
const useLoadingBar: typeof import('naive-ui')['useLoadingBar']
const useLocalStorage: typeof import('@vueuse/core')['useLocalStorage']
const useMagicKeys: typeof import('@vueuse/core')['useMagicKeys']
const useManualRefHistory: typeof import('@vueuse/core')['useManualRefHistory']
@ -191,6 +193,7 @@ declare global {
const useMediaQuery: typeof import('@vueuse/core')['useMediaQuery']
const useMemoize: typeof import('@vueuse/core')['useMemoize']
const useMemory: typeof import('@vueuse/core')['useMemory']
const useMessage: typeof import('naive-ui')['useMessage']
const useMounted: typeof import('@vueuse/core')['useMounted']
const useMouse: typeof import('@vueuse/core')['useMouse']
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
@ -198,6 +201,7 @@ declare global {
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
const useNavigatorLanguage: typeof import('@vueuse/core')['useNavigatorLanguage']
const useNetwork: typeof import('@vueuse/core')['useNetwork']
const useNotification: typeof import('naive-ui')['useNotification']
const useNow: typeof import('@vueuse/core')['useNow']
const useObjectUrl: typeof import('@vueuse/core')['useObjectUrl']
const useOffsetPagination: typeof import('@vueuse/core')['useOffsetPagination']

10
components.d.ts vendored
View File

@ -7,13 +7,23 @@ export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AButton: typeof import('@arco-design/web-vue')['Button']
AInput: typeof import('@arco-design/web-vue')['Input']
ARate: typeof import('@arco-design/web-vue')['Rate']
ASwitch: typeof import('@arco-design/web-vue')['Switch']
ATable: typeof import('@arco-design/web-vue')['Table']
ElButton: typeof import('element-plus/es')['ElButton']
ElInput: typeof import('element-plus/es')['ElInput']
ElLabel: typeof import('element-plus/es')['ElLabel']
ElTable: typeof import('./src/components/ElTable.vue')['default']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElText: typeof import('element-plus/es')['ElText']
MyComponent1: typeof import('./src/components/MyComponent1.vue')['default']
MyComponent2: typeof import('./src/components/MyComponent2.vue')['default']
MyComponent3: typeof import('./src/components/MyComponent3.vue')['default']
NDataTable: typeof import('naive-ui')['NDataTable']
NestedDirective: typeof import('./src/components/NestedDirective.vue')['default']
NestedFunction: typeof import('./src/components/NestedFunction.vue')['default']
VueDemo: typeof import('./src/components/VueDemo.vue')['default']
}
}

930
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,6 @@
},
"dependencies": {
"@vueuse/core": "^10.11.0",
"element-plus": "^2.7.8",
"lodash": "^4.17.21",
"lsp-uuid": "^3.2.0",
"vue": "^3.2.25",
@ -18,12 +17,15 @@
"vue-draggable-plus": "^0.5.2"
},
"devDependencies": {
"@arco-design/web-vue": "^2.56.0",
"@vitejs/plugin-vue": "^5.0.5",
"less": "^4.2.0",
"naive-ui": "^2.39.0",
"sass": "^1.77.8",
"typescript": "^5.2.2",
"unplugin-auto-import": "^0.18.2",
"unplugin-vue-components": "^0.27.3",
"vfonts": "^0.0.3",
"vite": "^5.3.4",
"vue-loader": "^17.4.2",
"vue-template-compiler": "^2.7.16",

View File

@ -0,0 +1,22 @@
<template>
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody class="el-table">
<tr v-for="item in list" :key="item.name" class="cursor-move">
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
</tr>
</tbody>
</table>
</template>
<script setup lang="ts">
interface Props {
list: Record<'name' | 'id', string>[]
}
defineProps<Props>()
</script>

View File

@ -1,33 +0,0 @@
<template>
<div>
<!-- 左侧组件列表 -->
<div class="left">
<div
class="left-item"
v-for="item in list1"
:key="item.code"
draggable
>
{{ item.name }}
</div>
</div>
<!-- 画布区域 -->
<div class="targetContent" ref="targetContent">
<div
class="item"
v-for="item in list2"
:key="item.id"
:ref="item.id"
:style="{
top: `${item.top - 16}px`,
left: `${item.left - 85}px`,
'z-index': `${item.zIndex}`
}"
>
<template v-if="item.code === 'MyInput'">
<a-input></a-input>
</template>
</div>
</div>
</div>
</template>

View File

@ -1,22 +0,0 @@
<template>
<div style="background: lightgreen; height: 100%; padding: 10px;">
组件2内容
<div v-if="$slots.default" class="slot-area">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'MyComponent2'
}
</script>
<style scoped>
.slot-area {
border: 2px dashed grey;
min-height: 50px;
margin-top: 10px;
}
</style>

View File

@ -1,22 +0,0 @@
<template>
<div style="background: lightcoral; height: 100%; padding: 10px;">
组件3内容
<div v-if="$slots.default" class="slot-area">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'MyComponent3'
}
</script>
<style scoped>
.slot-area {
border: 2px dashed grey;
min-height: 50px;
margin-top: 10px;
}
</style>

View File

@ -0,0 +1,37 @@
<template>
<ul v-draggable="[list, { group: 'g1' }]" class="drag-area">
<li v-for="el in modelValue" :key="el.name">
<p>{{ el.name }}</p>
<nested-directive v-model="el.children" />
</li>
</ul>
</template>
<script setup lang="ts">
import { vDraggable } from 'vue-draggable-plus'
import { computed } from 'vue'
interface IList {
name: string
children: IList[]
}
interface Props {
modelValue: IList[]
}
const props = defineProps<Props>()
interface Emits {
(e: 'update:modelValue', value: IList[]): void
}
const emits = defineEmits<Emits>()
const list = computed({
get: () => props.modelValue,
set: value => emits('update:modelValue', value)
})
</script>
<style scoped>
.drag-area {
min-height: 50px;
outline: 1px dashed;
}
</style>

View File

@ -0,0 +1,55 @@
<template>
<ul class="drag-area" ref="el">
<li v-for="el in modelValue" :key="el.name">
<div style="width: 200px;border: 1px solid red;">
<p>{{ el.name }}:{{ el.id }}</p>
</div>
<nested-function v-model="el.children" />
</li>
</ul>
</template>
<script setup lang="ts">
import { useDraggable} from 'vue-draggable-plus'
import { computed, ref } from 'vue'
import { IList } from '../type/IList'
interface Props {
modelValue: IList[]
}
const props = defineProps<Props>()
interface Emits {
(e: 'update:modelValue', value: IList[]): void
}
const emits = defineEmits<Emits>()
const list = computed({
get: () => props.modelValue,
set: value => emits('update:modelValue', value)
})
const el = ref()
useDraggable(el, list, {
group: 'designer',
animation: 150,
onStart() {
console.log('start')
},
onUpdate() {
console.log('update list1')
},
onAdd: (e) => {
// console.log(e)
console.log('add list1')
},
onRemove: () => {
console.log('remove list1')
}
},)
</script>
<style scoped>
.drag-area {
min-height: 50px;
outline: 1px dashed;
background-color: hsl(0, 0%, 100%);
}
</style>

View File

@ -1,81 +1,75 @@
<template>
<div style="display: flex;">
<section v-draggable="[
list1,
{
animation: 150,
group: {
name: 'people',
pull: 'clone',
put: false
},
sort: false,
clone
}
]">
<div v-for="item in list1" :key="item.id" style="border: 1px solid green;margin: 5px;">
{{ item.name }}
<div style="display: flex;flex-direction: row;">
<div ref="el2" style="margin: 5%;display: flex;flex-direction: column;">
<div v-for="item in list1" :key="item.id" style="width: 200px;border: 1px solid red;">
{{ item.name }}:{{ item.id }}
</div>
</section>
<section v-draggable="[
list2,
{
animation: 150,
group: 'people'
}
]">
<div v-for="item in list2" :key="item.id" style="border: 1px solid red;margin: 5px;">
{{ item.name }}
</div>
</section>
</div>
<div>
<div>
{{ list1 }}
</div>
<div>
{{ list2 }}
<div class="flex justify-between">
<NestedFunction v-model="list" class="w-full"></NestedFunction>
{{ list }}
</div>
</br>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { uuid } from 'lsp-uuid'
import { vDraggable } from 'vue-draggable-plus'
import NestedFunction from './NestedFunction.vue'
import { useDraggable } from 'vue-draggable-plus'
import { uuid } from 'lsp-uuid';
const list1 = ref([
{
name: 'Joao',
id: '1'
{
type: 'Switch',
name: '开关',
id: 'switch',
designer: '',
props: {},
style: '',
class: '',
children: []
},
{
name: 'Jean',
id: '2'
type: 'Rate',
name: '开关',
id: 'rate',
designer: '',
props: {},
style: '',
class: '',
children: []
},
{
name: 'Johanna',
id: '3'
},
{
name: 'Juan',
id: '4'
type: 'Button',
name: '按钮',
id: 'button',
designer: '',
props: {},
style: '',
class: '',
children: []
}
])
const list2 = ref(
list1.value.map(item => ({
name: `${item.name}-2`,
id: `${item.id}-2`
}))
)
function clone(element: Record<'name' | 'id', string>) {
const len = list2.value.length
return {
name: `${element.name}-clone-${len}`,
id: `${element.id}-clone-${uuid()}`
])
const list=ref([])
const el2 = ref()
useDraggable(el2, list1, {
animation: 150,
group: { name: 'designer', pull: 'clone', put: false },
sort: false,
onClone() {
console.log('clone')
},
clone(element: Record<'id'|'children', any>) {
return {
id: `${element.id}-${uuid()}`,
children:[]
}
}
}
})
</script>

10
src/type/IList.ts Normal file
View File

@ -0,0 +1,10 @@
export interface IList {
type: string;
name: string;
id: string;
designer: JSON;
props: JSON;
style: string;
class: string;
children: IList[];
}

View File

@ -5,21 +5,25 @@ import vue from '@vitejs/plugin-vue'
// import vueDevTools from 'vite-plugin-vue-devtools'
import AutoImport from 'unplugin-auto-import/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { ArcoResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
AutoImport({
resolvers: [ElementPlusResolver({ importStyle: 'sass' })],
resolvers: [ArcoResolver()],
imports: [
'vue',
'vue-router',
'@vueuse/core',
{
from: 'element-plus',
imports: ['ElMessage', 'ElMessageBox']
'naive-ui': [
'useDialog',
'useMessage',
'useNotification',
'useLoadingBar'
]
}
],
dirs: [
@ -30,7 +34,11 @@ export default defineConfig({
]
}),
Components({
resolvers: [ElementPlusResolver({ importStyle: 'sass' })]
resolvers: [
ArcoResolver({
sideEffect: true
})
]
}),
vue(),
// vueDevTools()