Skip to content

Commit 8ed61ca

Browse files
authored
fix(canvasShortCutPanel): add click event to quick insert component in… (#81)
* fix(canvasShotCutPanel): add click event to quick insert component in shortcutpanel * fix(canvasShortPanel): add deepclone utils * feat(utils): add deepClone method * feat(unit-test): add unit test for deepclone function
1 parent 3ae47c8 commit 8ed61ca

File tree

5 files changed

+333
-19
lines changed

5 files changed

+333
-19
lines changed

packages/canvas/src/components/container/CanvasDragItem.vue

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
<template>
2-
<div draggable="true" class="drag-item" @dragstart="dragstart">
2+
<div draggable="true" class="drag-item" @dragstart="dragstart" @click="handleClick">
33
<slot></slot>
44
</div>
55
</template>
66

77
<script>
8+
import { utils } from '@opentiny/tiny-engine-utils'
89
import { dragStart } from './container'
10+
11+
const { deepClone } = utils
12+
913
export default {
1014
props: {
1115
data: Object
1216
},
1317
emits: ['click'],
1418
setup(props, { emit }) {
1519
const dragstart = (e) => {
16-
if (props.data && e.button === 0) {
17-
const data = JSON.parse(JSON.stringify(props.data))
18-
emit('click', data)
20+
if (props.data) {
21+
const data = deepClone(props.data)
1922
dragStart(data)
2023
2124
// 设置拖拽鼠标样式和设置拖拽预览图
@@ -24,8 +27,18 @@ export default {
2427
e.dataTransfer.setDragImage(target, 10, 10)
2528
}
2629
}
30+
31+
const handleClick = () => {
32+
if (props.data) {
33+
const data = deepClone(props.data)
34+
35+
emit('click', data)
36+
}
37+
}
38+
2739
return {
28-
dragstart
40+
dragstart,
41+
handleClick
2942
}
3043
}
3144
}

packages/utils/package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"dist"
1212
],
1313
"scripts": {
14-
"build": "vite build"
14+
"build": "vite build",
15+
"test": "vitest"
1516
},
1617
"keywords": [],
1718
"repository": {
@@ -26,9 +27,11 @@
2627
"license": "MIT",
2728
"homepage": "https://opentiny.design/tiny-engine",
2829
"devDependencies": {
29-
"vite": "^4.3.7"
30+
"vite": "^4.3.7",
31+
"vitest": "^0.34.6"
3032
},
3133
"dependencies": {
32-
"@opentiny/vue-renderless": "~3.10.0"
34+
"@opentiny/vue-renderless": "~3.10.0",
35+
"vue": "^3.3.8"
3336
}
3437
}

packages/utils/src/utils/index.js

Lines changed: 157 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
/**
2-
* Copyright (c) 2023 - present TinyEngine Authors.
3-
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
4-
*
5-
* Use of this source code is governed by an MIT-style license.
6-
*
7-
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8-
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9-
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10-
*
11-
*/
2+
* Copyright (c) 2023 - present TinyEngine Authors.
3+
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
4+
*
5+
* Use of this source code is governed by an MIT-style license.
6+
*
7+
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8+
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9+
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10+
*
11+
*/
1212

13+
import { isRef, isProxy, unref, toRaw } from 'vue'
1314
import { isObject, isArray } from '@opentiny/vue-renderless/grid/static'
1415

1516
export const fun_ctor = Function
@@ -177,3 +178,149 @@ export function generateRandomLetters(length = 1) {
177178
}
178179
return result
179180
}
181+
182+
export function getRawValue(target) {
183+
let res = target
184+
185+
if (isRef(res)) {
186+
res = unref(res)
187+
}
188+
189+
if (isProxy(res)) {
190+
return toRaw(res)
191+
}
192+
193+
return res
194+
}
195+
196+
export function getType(val) {
197+
let type = typeof val
198+
199+
if (type !== 'object') {
200+
return type
201+
}
202+
203+
return Object.prototype.toString.call(val).replace(/\[object (.*)\]/, '$1')
204+
}
205+
206+
function cloneArray(target, map, _deepClone) {
207+
let res = []
208+
209+
map.set(target, res)
210+
211+
target.forEach((item, index) => {
212+
res[index] = _deepClone(item, map)
213+
})
214+
215+
return res
216+
}
217+
218+
function cloneMap(target, map, _deepClone) {
219+
let res = new Map()
220+
221+
map.set(target, res)
222+
223+
target.forEach((value, key) => {
224+
res.set(key, _deepClone(value, map))
225+
})
226+
227+
return res
228+
}
229+
230+
function cloneSet(target, map, _deepClone) {
231+
let res = new Set()
232+
233+
map.set(target, res)
234+
235+
target.forEach((value) => {
236+
res.add(_deepClone(value, map))
237+
})
238+
239+
return res
240+
}
241+
242+
function cloneObject(target, map, _deepClone) {
243+
const res = {}
244+
245+
map.set(target, res)
246+
247+
Object.entries(target).forEach(([key, value]) => {
248+
res[key] = _deepClone(value, map)
249+
})
250+
251+
return res
252+
}
253+
254+
export function naiveDeepClone(target) {
255+
try {
256+
return structuredClone(target)
257+
} catch (error) {
258+
// target is no serializable
259+
}
260+
}
261+
262+
/**
263+
* 使用 JSON.stringify 进行 deep clone
264+
* 不支持 Map、Set、Date、RegExp、ArrayBuffer 等变量类型
265+
* 不支持循环引用
266+
* @param {*} target target to be copy
267+
* @param {*} callback target copyed
268+
*/
269+
export function jsonDeepClone(target, callback) {
270+
try {
271+
JSON.parse(JSON.stringify(target))
272+
} catch (error) {
273+
if (typeof callback === 'function') {
274+
callback()
275+
}
276+
}
277+
}
278+
279+
const copyMethodMap = {
280+
Array: cloneArray,
281+
Map: cloneMap,
282+
Set: cloneSet,
283+
Object: cloneObject
284+
}
285+
286+
function _deepClone(target, map) {
287+
if (map.has(target)) {
288+
return map.get(target)
289+
}
290+
291+
const copyTarget = getRawValue(target)
292+
const basicType = ['undefined', 'number', 'string', 'boolean', 'function', 'bigint', 'symbol', 'Null']
293+
294+
let type = getType(copyTarget)
295+
296+
if (basicType.includes(type)) {
297+
return target
298+
}
299+
300+
let res = naiveDeepClone(copyTarget)
301+
302+
if (res) {
303+
map.set(target, res)
304+
305+
return res
306+
}
307+
308+
if (copyMethodMap[type]) {
309+
res = copyMethodMap[type](target, map, _deepClone)
310+
311+
return res
312+
}
313+
314+
return copyTarget
315+
}
316+
317+
/**
318+
* 优先使用 structuredClone 的深拷贝方法
319+
* 不支持 拷贝 prototype、function、DOM nodes、proxy(getter、setter)
320+
* 如果是 vue 的 ref 或者 reactive,会尝试拿到 raw value 然后进行深拷贝
321+
* @param {*} target value to be deep clone
322+
* @returns * deepCloned target
323+
*/
324+
export function deepClone(target) {
325+
return _deepClone(target, new WeakMap())
326+
}

0 commit comments

Comments
 (0)