|
@@ -4,12 +4,17 @@
|
|
|
:style="getStyle"
|
|
:style="getStyle"
|
|
|
:class="schema.type === 'page' ? '' : 'ignore-click widget-node'"
|
|
:class="schema.type === 'page' ? '' : 'ignore-click widget-node'"
|
|
|
:widget-id="schema.id"
|
|
:widget-id="schema.id"
|
|
|
- @click.stop="handleSelect"
|
|
|
|
|
|
|
+ @click="handleSelect"
|
|
|
@contextmenu.stop="handleContextmenu"
|
|
@contextmenu.stop="handleContextmenu"
|
|
|
v-if="!schema.hidden"
|
|
v-if="!schema.hidden"
|
|
|
>
|
|
>
|
|
|
<!-- 控件 -->
|
|
<!-- 控件 -->
|
|
|
- <component :is="widget" v-bind="schema.props" :styles="schema.style" />
|
|
|
|
|
|
|
+ <component
|
|
|
|
|
+ :is="widget"
|
|
|
|
|
+ v-bind="schema.props"
|
|
|
|
|
+ :styles="schema.style"
|
|
|
|
|
+ style="width: 100%; height: 100%"
|
|
|
|
|
+ />
|
|
|
<!-- 子节点 -->
|
|
<!-- 子节点 -->
|
|
|
<NodeItem
|
|
<NodeItem
|
|
|
v-if="schema.children"
|
|
v-if="schema.children"
|
|
@@ -20,47 +25,6 @@
|
|
|
:rootContainer="nodeRef!"
|
|
:rootContainer="nodeRef!"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
- <!-- 拖拽、缩放、吸附 -->
|
|
|
|
|
- <div v-show="schema.type !== 'page' && selected">
|
|
|
|
|
- <Moveable
|
|
|
|
|
- :target="nodeRef"
|
|
|
|
|
- :draggable="selected && !schema.locked"
|
|
|
|
|
- :resizable="selected && !schema.locked"
|
|
|
|
|
- :padding="2"
|
|
|
|
|
- :container="rootContainer"
|
|
|
|
|
- :snappable="true"
|
|
|
|
|
- :useMutationObserver="true"
|
|
|
|
|
- :useResizeObserver="true"
|
|
|
|
|
- :throttleDrag="1"
|
|
|
|
|
- :throttleResize="1"
|
|
|
|
|
- :snapDirections="{
|
|
|
|
|
- top: true,
|
|
|
|
|
- left: true,
|
|
|
|
|
- bottom: true,
|
|
|
|
|
- right: true,
|
|
|
|
|
- center: true,
|
|
|
|
|
- middle: true
|
|
|
|
|
- }"
|
|
|
|
|
- :elementSnapDirections="{
|
|
|
|
|
- top: true,
|
|
|
|
|
- left: true,
|
|
|
|
|
- bottom: true,
|
|
|
|
|
- right: true,
|
|
|
|
|
- center: true,
|
|
|
|
|
- middle: true
|
|
|
|
|
- }"
|
|
|
|
|
- :maxSnapElementGuidelineDistance="100"
|
|
|
|
|
- :elementGuidelines="elementGridelines"
|
|
|
|
|
- :verticalGuidelines="verticalGuidelines"
|
|
|
|
|
- :horizontalGuidelines="horizontalGuidelines"
|
|
|
|
|
- :controlPadding="4"
|
|
|
|
|
- @render="onRender"
|
|
|
|
|
- @drag="onDrag"
|
|
|
|
|
- @resize="onResize"
|
|
|
|
|
- @dragStart="onDragStart"
|
|
|
|
|
- @dragEnd="onDragEnd"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
<!-- 右键菜单 -->
|
|
<!-- 右键菜单 -->
|
|
|
<ContentMenu
|
|
<ContentMenu
|
|
|
ref="contentMenuRef"
|
|
ref="contentMenuRef"
|
|
@@ -80,9 +44,7 @@ import { useDrop } from 'vue-hooks-plus'
|
|
|
import { createWidget } from '@/model'
|
|
import { createWidget } from '@/model'
|
|
|
import LvglWidgets from '@/lvgl-widgets'
|
|
import LvglWidgets from '@/lvgl-widgets'
|
|
|
import { useProjectStore } from '@/store/modules/project'
|
|
import { useProjectStore } from '@/store/modules/project'
|
|
|
-import { useMutationObserver } from '@vueuse/core'
|
|
|
|
|
|
|
|
|
|
-import Moveable from 'vue3-moveable'
|
|
|
|
|
import ContentMenu from './ContentMenu.vue'
|
|
import ContentMenu from './ContentMenu.vue'
|
|
|
import { getAddWidgetIndex } from '@/utils'
|
|
import { getAddWidgetIndex } from '@/utils'
|
|
|
|
|
|
|
@@ -92,7 +54,6 @@ defineOptions({
|
|
|
|
|
|
|
|
const page = inject<Page>('page')
|
|
const page = inject<Page>('page')
|
|
|
const pageState = inject<StageState>('state')
|
|
const pageState = inject<StageState>('state')
|
|
|
-const pageEl = inject<HTMLElement>('pageEl')
|
|
|
|
|
|
|
|
|
|
const props = defineProps<{
|
|
const props = defineProps<{
|
|
|
// 父级容器 拖拽缩放设置
|
|
// 父级容器 拖拽缩放设置
|
|
@@ -112,10 +73,7 @@ const widget = computed(() => LvglWidgets[props.schema.type]?.component)
|
|
|
const nodeRef = ref<HTMLDivElement>()
|
|
const nodeRef = ref<HTMLDivElement>()
|
|
|
// 当前层级
|
|
// 当前层级
|
|
|
const zIndex = ref(props.zIndex)
|
|
const zIndex = ref(props.zIndex)
|
|
|
-// 判断当前节点是否选中
|
|
|
|
|
-const selected = computed(() =>
|
|
|
|
|
- projectStore.activeWidgets.map((item) => item.id).includes(props.schema.id)
|
|
|
|
|
-)
|
|
|
|
|
|
|
+
|
|
|
// 放置效果样式
|
|
// 放置效果样式
|
|
|
const dropStyle = ref<CSSProperties>({})
|
|
const dropStyle = ref<CSSProperties>({})
|
|
|
|
|
|
|
@@ -124,7 +82,8 @@ const getStyle = computed((): CSSProperties => {
|
|
|
const { style = {}, schema } = props
|
|
const { style = {}, schema } = props
|
|
|
|
|
|
|
|
const other: CSSProperties = {}
|
|
const other: CSSProperties = {}
|
|
|
- if (pageState?.showBorder) {
|
|
|
|
|
|
|
+ // 显示所有控件边框
|
|
|
|
|
+ if (pageState?.showBorder && props.schema.type !== 'page') {
|
|
|
other.border = '1px dashed #000'
|
|
other.border = '1px dashed #000'
|
|
|
other.transform = `translate(${schema.props.x - 1}px, ${schema.props.y - 1}px)`
|
|
other.transform = `translate(${schema.props.x - 1}px, ${schema.props.y - 1}px)`
|
|
|
}
|
|
}
|
|
@@ -143,50 +102,6 @@ const getStyle = computed((): CSSProperties => {
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-// 吸附辅助线
|
|
|
|
|
-const elementGridelines = ref<Element[]>([])
|
|
|
|
|
-// 垂直辅助线
|
|
|
|
|
-const verticalGuidelines = computed(() => {
|
|
|
|
|
- return (
|
|
|
|
|
- (pageState?.showReferenceLine &&
|
|
|
|
|
- projectStore.activePage?.referenceLine
|
|
|
|
|
- .filter((item) => item.type === 'horizontal')
|
|
|
|
|
- .map((item) => item.value)) ||
|
|
|
|
|
- []
|
|
|
|
|
- )
|
|
|
|
|
-})
|
|
|
|
|
-// 水平辅助线
|
|
|
|
|
-const horizontalGuidelines = computed(() => {
|
|
|
|
|
- return (
|
|
|
|
|
- (pageState?.showReferenceLine &&
|
|
|
|
|
- projectStore.activePage?.referenceLine
|
|
|
|
|
- .filter((item) => item.type === 'vertical')
|
|
|
|
|
- .map((item) => item.value)) ||
|
|
|
|
|
- []
|
|
|
|
|
- )
|
|
|
|
|
-})
|
|
|
|
|
-
|
|
|
|
|
-// 监听页面节点变化 设置元素辅助线
|
|
|
|
|
-useMutationObserver(
|
|
|
|
|
- pageEl,
|
|
|
|
|
- (mutations) => {
|
|
|
|
|
- mutations.forEach(() => {
|
|
|
|
|
- const els = document.querySelectorAll('.widget-node')
|
|
|
|
|
- elementGridelines.value = []
|
|
|
|
|
- els.forEach((el) => {
|
|
|
|
|
- // 排除自己
|
|
|
|
|
- if (el.attributes['widget-id']?.value !== props.schema.id) {
|
|
|
|
|
- elementGridelines.value.push(el)
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- childList: true,
|
|
|
|
|
- subtree: true
|
|
|
|
|
- }
|
|
|
|
|
-)
|
|
|
|
|
-
|
|
|
|
|
// 拖拽放置事件处理
|
|
// 拖拽放置事件处理
|
|
|
useDrop(nodeRef, {
|
|
useDrop(nodeRef, {
|
|
|
// 元素放置
|
|
// 元素放置
|
|
@@ -217,54 +132,22 @@ useDrop(nodeRef, {
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// 选择节点
|
|
// 选择节点
|
|
|
-const handleSelect = (e) => {
|
|
|
|
|
|
|
+const handleSelect = (e: MouseEvent) => {
|
|
|
if (props.schema.type !== 'page') {
|
|
if (props.schema.type !== 'page') {
|
|
|
|
|
+ e.stopPropagation()
|
|
|
// 判断当前是否按住ctrl
|
|
// 判断当前是否按住ctrl
|
|
|
if (e.ctrlKey) {
|
|
if (e.ctrlKey) {
|
|
|
projectStore.activeWidgets.push(props.schema as BaseWidget)
|
|
projectStore.activeWidgets.push(props.schema as BaseWidget)
|
|
|
} else {
|
|
} else {
|
|
|
projectStore.setSelectWidgets([props.schema as BaseWidget])
|
|
projectStore.setSelectWidgets([props.schema as BaseWidget])
|
|
|
}
|
|
}
|
|
|
|
|
+ } else {
|
|
|
|
|
+ projectStore.setSelectWidgets([])
|
|
|
}
|
|
}
|
|
|
// 关闭右键菜单
|
|
// 关闭右键菜单
|
|
|
contentMenuRef.value?.handleClose()
|
|
contentMenuRef.value?.handleClose()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// 拖拽开始
|
|
|
|
|
-const onDragStart = () => {
|
|
|
|
|
- zIndex.value = 999
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 拖拽结束
|
|
|
|
|
-const onDragEnd = () => {
|
|
|
|
|
- zIndex.value = props.zIndex
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 渲染节点拖拽
|
|
|
|
|
-const onDrag = (e) => {
|
|
|
|
|
- // 当前选中节点整体移动
|
|
|
|
|
- projectStore.activeWidgets.forEach((item) => {
|
|
|
|
|
- item.props.x += e.beforeDelta[0]
|
|
|
|
|
- item.props.y += e.beforeDelta[1]
|
|
|
|
|
- })
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 渲染节点缩放
|
|
|
|
|
-const onResize = (e) => {
|
|
|
|
|
- props.schema.props.width = e.width
|
|
|
|
|
- props.schema.props.height = e.height
|
|
|
|
|
- if (e.drag?.beforeTranslate) {
|
|
|
|
|
- props.schema.props.x = e.drag.beforeTranslate[0]
|
|
|
|
|
- props.schema.props.y = e.drag.beforeTranslate[1]
|
|
|
|
|
- }
|
|
|
|
|
- e.target.style.cssText += e.cssText
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// 渲染节点事件
|
|
|
|
|
-const onRender = (e) => {
|
|
|
|
|
- e.target.style.cssText += e.cssText
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
/******************************右键菜单*********************************/
|
|
/******************************右键菜单*********************************/
|
|
|
const position = ref({
|
|
const position = ref({
|
|
|
top: 0,
|
|
top: 0,
|
|
@@ -279,6 +162,7 @@ const triggerRef = ref({
|
|
|
getBoundingClientRect: () => position.value
|
|
getBoundingClientRect: () => position.value
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+// 处理右键菜单
|
|
|
const handleContextmenu = (event: MouseEvent) => {
|
|
const handleContextmenu = (event: MouseEvent) => {
|
|
|
const { clientX, clientY } = event
|
|
const { clientX, clientY } = event
|
|
|
position.value = DOMRect.fromRect({
|
|
position.value = DOMRect.fromRect({
|