Skip to content

Commit 434aa86

Browse files
committed
营销:优化装修编辑器
1 parent 0b0ba1f commit 434aa86

File tree

4 files changed

+267
-208
lines changed

4 files changed

+267
-208
lines changed
Lines changed: 199 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,222 @@
11
<template>
2-
<div
3-
:style="{
4-
...style
5-
}"
6-
>
7-
<slot></slot>
2+
<div :class="['component', { active: active }]">
3+
<div
4+
:style="{
5+
...style
6+
}"
7+
>
8+
<component :is="component.id" :property="component.property" />
9+
</div>
10+
<div class="component-wrap">
11+
<!-- 左侧组件名 -->
12+
<div class="component-name" v-if="component.name">
13+
{{ component.name }}
14+
</div>
15+
<!-- 左侧:组件操作工具栏 -->
16+
<div class="component-toolbar" v-if="showToolbar && component.name && active">
17+
<VerticalButtonGroup type="primary">
18+
<el-tooltip content="上移" placement="right">
19+
<el-button :disabled="!canMoveUp" @click.stop="handleMoveComponent(-1)">
20+
<Icon icon="ep:arrow-up" />
21+
</el-button>
22+
</el-tooltip>
23+
<el-tooltip content="下移" placement="right">
24+
<el-button :disabled="!canMoveDown" @click.stop="handleMoveComponent(1)">
25+
<Icon icon="ep:arrow-down" />
26+
</el-button>
27+
</el-tooltip>
28+
<el-tooltip content="复制" placement="right">
29+
<el-button @click.stop="handleCopyComponent()">
30+
<Icon icon="ep:copy-document" />
31+
</el-button>
32+
</el-tooltip>
33+
<el-tooltip content="删除" placement="right">
34+
<el-button @click.stop="handleDeleteComponent()">
35+
<Icon icon="ep:delete" />
36+
</el-button>
37+
</el-tooltip>
38+
</VerticalButtonGroup>
39+
</div>
40+
</div>
841
</div>
942
</template>
1043

44+
<script lang="ts">
45+
// 注册所有的组件
46+
import { components } from '../components/mobile/index'
47+
export default {
48+
components: { ...components }
49+
}
50+
</script>
1151
<script setup lang="ts">
12-
import { ComponentStyle } from '@/components/DiyEditor/util'
52+
import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
53+
import { propTypes } from '@/utils/propTypes'
54+
import { object } from 'vue-types'
1355
1456
/**
1557
* 组件容器
1658
* 用于包裹组件,为组件提供 背景、外边距、内边距、边框等样式
1759
*/
1860
defineOptions({ name: 'ComponentContainer' })
1961
20-
const props = defineProps<{ property: ComponentStyle | undefined }>()
62+
type DiyComponentWithStyle = DiyComponent<any> & { property: { style?: ComponentStyle } }
63+
const props = defineProps({
64+
component: object<DiyComponentWithStyle>().isRequired,
65+
active: propTypes.bool.def(false),
66+
canMoveUp: propTypes.bool.def(false),
67+
canMoveDown: propTypes.bool.def(false),
68+
showToolbar: propTypes.bool.def(true)
69+
})
2170
71+
/**
72+
* 组件样式
73+
*/
2274
const style = computed(() => {
23-
if (!props.property) {
75+
let componentStyle = props.component.property.style
76+
if (!componentStyle) {
2477
return {}
2578
}
2679
return {
27-
marginTop: `${props.property.marginTop || 0}px`,
28-
marginBottom: `${props.property.marginBottom || 0}px`,
29-
marginLeft: `${props.property.marginLeft || 0}px`,
30-
marginRight: `${props.property.marginRight || 0}px`,
31-
paddingTop: `${props.property.paddingTop || 0}px`,
32-
paddingRight: `${props.property.paddingRight || 0}px`,
33-
paddingBottom: `${props.property.paddingBottom || 0}px`,
34-
paddingLeft: `${props.property.paddingLeft || 0}px`,
35-
borderTopLeftRadius: `${props.property.borderTopLeftRadius || 0}px`,
36-
borderTopRightRadius: `${props.property.borderTopRightRadius || 0}px`,
37-
borderBottomRightRadius: `${props.property.borderBottomRightRadius || 0}px`,
38-
borderBottomLeftRadius: `${props.property.borderBottomLeftRadius || 0}px`,
80+
marginTop: `${componentStyle.marginTop || 0}px`,
81+
marginBottom: `${componentStyle.marginBottom || 0}px`,
82+
marginLeft: `${componentStyle.marginLeft || 0}px`,
83+
marginRight: `${componentStyle.marginRight || 0}px`,
84+
paddingTop: `${componentStyle.paddingTop || 0}px`,
85+
paddingRight: `${componentStyle.paddingRight || 0}px`,
86+
paddingBottom: `${componentStyle.paddingBottom || 0}px`,
87+
paddingLeft: `${componentStyle.paddingLeft || 0}px`,
88+
borderTopLeftRadius: `${componentStyle.borderTopLeftRadius || 0}px`,
89+
borderTopRightRadius: `${componentStyle.borderTopRightRadius || 0}px`,
90+
borderBottomRightRadius: `${componentStyle.borderBottomRightRadius || 0}px`,
91+
borderBottomLeftRadius: `${componentStyle.borderBottomLeftRadius || 0}px`,
3992
overflow: 'hidden',
4093
background:
41-
props.property.bgType === 'color' ? props.property.bgColor : `url(${props.property.bgImg})`
94+
componentStyle.bgType === 'color' ? componentStyle.bgColor : `url(${componentStyle.bgImg})`
4295
}
4396
})
97+
98+
const emits = defineEmits<{
99+
(e: 'move', direction: number): void
100+
(e: 'copy'): void
101+
(e: 'delete'): void
102+
}>()
103+
/**
104+
* 移动组件
105+
* @param direction 移动方向
106+
*/
107+
const handleMoveComponent = (direction: number) => {
108+
emits('move', direction)
109+
}
110+
/**
111+
* 复制组件
112+
*/
113+
const handleCopyComponent = () => {
114+
emits('copy')
115+
}
116+
/**
117+
* 删除组件
118+
*/
119+
const handleDeleteComponent = () => {
120+
emits('delete')
121+
}
44122
</script>
45123

46-
<style scoped lang="scss"></style>
124+
<style scoped lang="scss">
125+
$active-border-width: 2px;
126+
$hover-border-width: 1px;
127+
$name-position: -85px;
128+
$toolbar-position: -55px;
129+
/* 组件 */
130+
.component {
131+
position: relative;
132+
cursor: move;
133+
.component-wrap {
134+
display: block;
135+
position: absolute;
136+
left: -$active-border-width;
137+
top: 0;
138+
width: 100%;
139+
height: 100%;
140+
/* 鼠标放到组件上时 */
141+
&:hover {
142+
border: $hover-border-width dashed var(--el-color-primary);
143+
box-shadow: 0 0 5px 0 rgba(24, 144, 255, 0.3);
144+
.component-name {
145+
/* 防止加了边框之后,位置移动 */
146+
left: $name-position - $hover-border-width;
147+
top: $hover-border-width;
148+
}
149+
}
150+
/* 左侧:组件名称 */
151+
.component-name {
152+
display: block;
153+
position: absolute;
154+
width: 80px;
155+
text-align: center;
156+
line-height: 25px;
157+
height: 25px;
158+
background: #fff;
159+
font-size: 12px;
160+
left: $name-position;
161+
top: $active-border-width;
162+
box-shadow:
163+
0 0 4px #00000014,
164+
0 2px 6px #0000000f,
165+
0 4px 8px 2px #0000000a;
166+
/* 右侧小三角 */
167+
&:after {
168+
position: absolute;
169+
top: 7.5px;
170+
right: -10px;
171+
content: ' ';
172+
height: 0;
173+
width: 0;
174+
border: 5px solid transparent;
175+
border-left-color: #fff;
176+
}
177+
}
178+
/* 右侧:组件操作工具栏 */
179+
.component-toolbar {
180+
display: none;
181+
position: absolute;
182+
top: 0;
183+
right: $toolbar-position;
184+
/* 左侧小三角 */
185+
&:before {
186+
position: absolute;
187+
top: 10px;
188+
left: -10px;
189+
content: ' ';
190+
height: 0;
191+
width: 0;
192+
border: 5px solid transparent;
193+
border-right-color: #2d8cf0;
194+
}
195+
}
196+
}
197+
/* 组件选中时 */
198+
&.active {
199+
margin-bottom: 4px;
200+
201+
.component-wrap {
202+
border: $active-border-width solid var(--el-color-primary) !important;
203+
box-shadow: 0 0 10px 0 rgba(24, 144, 255, 0.3);
204+
margin-bottom: $active-border-width + $active-border-width;
205+
206+
.component-name {
207+
background: var(--el-color-primary);
208+
color: #fff;
209+
/* 防止加了边框之后,位置移动 */
210+
left: $name-position - $active-border-width !important;
211+
top: 0 !important;
212+
&:after {
213+
border-left-color: var(--el-color-primary);
214+
}
215+
}
216+
.component-toolbar {
217+
display: block;
218+
}
219+
}
220+
}
221+
}
222+
</style>

0 commit comments

Comments
 (0)