Skip to content

Commit

Permalink
feat: 新增组件对齐方式 (#136)
Browse files Browse the repository at this point in the history
* feat: 新增组件对齐方式

* fix: 修复单文件上下对齐失效的问题

* fix: 修复垂直等间距和水平等间距对齐,修复对齐没有新增快照,导致撤销不正常的问题

* fix: 修复对齐的时候,areaData的外框没有重新计算的问题

* fix: 修复对齐的时候,当多个组件过于密集导致间距为负数,会导致一直可以对齐的问题.在多次对齐之后会趋于一个稳定值,而不是一直在对齐.
  • Loading branch information
husiqiang authored Aug 31, 2024
1 parent e10cf63 commit 8538ed1
Show file tree
Hide file tree
Showing 5 changed files with 409 additions and 24 deletions.
41 changes: 41 additions & 0 deletions src/components/Editor/GroupComponentBox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<template>
<div
:style="{
left: left + 'px',
top: top + 'px',
width: width + 'px',
height: height + 'px',
}"
class="area"
></div>
</template>

<script>
export default {
props: {
width: {
type: Number,
default: 0,
},
height: {
type: Number,
default: 0,
},
left: {
type: Number,
default: 0,
},
top: {
type: Number,
default: 0,
},
},
}
</script>

<style lang="scss" scoped>
.area {
border: 1px solid #70c0ff;
position: absolute;
}
</style>
10 changes: 7 additions & 3 deletions src/components/Editor/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
:width="width"
:height="height"
/>
<!-- 选择的组件包裹层 -->
<GroupComponentBox v-if="areaData?.components?.length" v-bind="areaData.style" />
</div>
</template>

Expand All @@ -81,12 +83,13 @@ import { $, isPreventDrop } from '@/utils/utils'
import ContextMenu from './ContextMenu'
import MarkLine from './MarkLine'
import Area from './Area'
import GroupComponentBox from './GroupComponentBox'
import eventBus from '@/utils/eventBus'
import Grid from './Grid'
import { changeStyleWithScale } from '@/utils/translate'
export default {
components: { Shape, ContextMenu, MarkLine, Area, Grid },
components: { Shape, ContextMenu, MarkLine, Area, Grid, GroupComponentBox },
props: {
isEdit: {
type: Boolean,
Expand All @@ -113,6 +116,7 @@ export default {
'canvasStyleData',
'editor',
'isDarkMode',
'areaData',
]),
mounted() {
// 获取编辑器元素
Expand Down Expand Up @@ -167,7 +171,6 @@ export default {
this.hideArea()
return
}
this.createGroup()
}
Expand All @@ -176,7 +179,7 @@ export default {
},
hideArea() {
this.isShowArea = 0
this.isShowArea = false
this.width = 0
this.height = 0
Expand Down Expand Up @@ -243,6 +246,7 @@ export default {
},
components: areaData,
})
this.isShowArea = false // 关闭选框
},
getSelectArea() {
Expand Down
180 changes: 160 additions & 20 deletions src/components/Toolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,37 @@
/>
</label>

<el-button style="margin-left: 10px;" @click="preview(false)">预览</el-button>
<el-button style="margin-left: 10px;" @click="preview(false)">
预览
</el-button>
<el-button @click="save">保存</el-button>
<el-button @click="clearCanvas">清空画布</el-button>
<el-button :disabled="!areaData.components.length" @click="compose">组合</el-button>
<el-button :disabled="!areaData.components.length" @click="compose">
组合
</el-button>
<el-button
:disabled="!curComponent || curComponent.isLock || curComponent.component != 'Group'"
:disabled="
!curComponent ||
curComponent.isLock ||
curComponent.component != 'Group'
"
@click="decompose"
>
拆分
</el-button>

<el-button :disabled="!curComponent || curComponent.isLock" @click="lock">锁定</el-button>
<el-button :disabled="!curComponent || !curComponent.isLock" @click="unlock">解锁</el-button>
<el-button
:disabled="!curComponent || curComponent.isLock"
@click="lock"
>
锁定
</el-button>
<el-button
:disabled="!curComponent || !curComponent.isLock"
@click="unlock"
>
解锁
</el-button>
<el-button @click="preview(true)">截图</el-button>

<div class="canvas-config">
Expand All @@ -39,7 +57,8 @@
</div>
<div class="canvas-config">
<span>画布比例</span>
<input v-model="scale" @input="handleScaleChange" /> %
<input v-model="scale" @input="handleScaleChange" />
%
</div>
<el-switch
v-model="switchValue"
Expand All @@ -48,12 +67,37 @@
inactive-icon-class="el-icon-moon"
active-color="#000"
@change="handleToggleDarkMode"
></el-switch>
<el-dropdown
v-if="showComponentAlign"
:hide-on-click="false"
class="align-dropdown"
trigger="click"
@command="handleComponentAlign"
>
</el-switch>
<el-button type="primary">
对齐方式
<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="item in alignList"
:key="item.value"
:command="item.value"
:disabled="item.isDisabled? areaData.components.length < 3 : false"
>
{{ item.label }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>

<!-- 预览 -->
<Preview v-if="isShowPreview" :is-screenshot="isScreenshot" @close="handlePreviewChange" />
<Preview
v-if="isShowPreview"
:is-screenshot="isScreenshot"
@close="handlePreviewChange"
/>
<AceEditor v-if="isShowAceEditor" @closeEditor="closeEditor" />

<el-dialog
Expand All @@ -68,8 +112,7 @@
type="textarea"
:rows="20"
placeholder="请输入 JSON 数据"
>
</el-input>
></el-input>
<div slot="footer" class="dialog-footer">
<el-button @click="isShowDialog = false">取 消</el-button>
<el-upload
Expand All @@ -96,7 +139,10 @@ import AceEditor from '@/components/Editor/AceEditor.vue'
import { commonStyle, commonAttr } from '@/custom-component/component-list'
import eventBus from '@/utils/eventBus'
import { $ } from '@/utils/utils'
import changeComponentsSizeWithScale, { changeComponentSizeWithScale } from '@/utils/changeComponentsSizeWithScale'
import changeComponentsSizeWithScale, {
changeComponentSizeWithScale,
} from '@/utils/changeComponentsSizeWithScale'
import { getComponentRotatedStyle } from '@/utils/style'
export default {
components: { Preview, AceEditor },
Expand All @@ -111,9 +157,60 @@ export default {
isShowDialog: false,
jsonData: '',
isExport: false,
alignList: [
{
label: '左对齐',
value: 'leftAlign',
},
{
label: '水平居中',
value: 'centerAlign',
},
{
label: '右对齐',
value: 'rightAlign',
},
{
label: '顶对齐',
value: 'topAlign',
},
{
label: '垂直居中',
value: 'middleAlign',
},
{
label: '底对齐',
value: 'bottomAlign',
},
{
label: '水平等间距',
value: 'horizontalSpacing',
isDisabled: true,
},
{
label: '垂直等间距',
value: 'verticalSpacing',
isDisabled: true,
},
],
}
},
computed: mapState(['componentData', 'canvasStyleData', 'areaData', 'curComponent', 'curComponentIndex', 'isDarkMode']),
computed: {
...mapState([
'componentData',
'canvasStyleData',
'areaData',
'curComponent',
'curComponentIndex',
'isDarkMode',
]),
showComponentAlign() {
return (
(this.curComponent && !this.curComponent.isLock)
|| this.areaData.components.length > 1
)
},
},
created() {
eventBus.$on('preview', this.preview)
eventBus.$on('save', this.save)
Expand All @@ -126,6 +223,32 @@ export default {
}
},
methods: {
handleComponentAlign(command) {
this.$store.commit(command)
// 每次对齐后记录一次快照
this.$store.commit('recordSnapshot')
// 如果是多组件对齐, 则需要重新计算选中区域的大小和位置
let top = Infinity, left = Infinity
let right = -Infinity, bottom = -Infinity
if (this.areaData.components.length > 1) {
this.areaData.components.forEach(component => {
let style = getComponentRotatedStyle(component.style)
if (style.left < left) left = style.left
if (style.top < top) top = style.top
if (style.right > right) right = style.right
if (style.bottom > bottom) bottom = style.bottom
})
this.$store.commit('setAreaData', {
style: {
left,
top,
width: right - left,
height: bottom - top,
},
components: this.areaData.components,
})
}
},
handleToggleDarkMode(value) {
if (value !== null) {
this.$store.commit('toggleDarkMode', value)
Expand Down Expand Up @@ -235,13 +358,22 @@ export default {
},
save() {
localStorage.setItem('canvasData', JSON.stringify(this.componentData))
localStorage.setItem('canvasStyle', JSON.stringify(this.canvasStyleData))
localStorage.setItem(
'canvasData',
JSON.stringify(this.componentData),
)
localStorage.setItem(
'canvasStyle',
JSON.stringify(this.canvasStyleData),
)
this.$message.success('保存成功')
},
clearCanvas() {
this.$store.commit('setCurComponent', { component: null, index: null })
this.$store.commit('setCurComponent', {
component: null,
index: null,
})
this.$store.commit('setComponentData', [])
this.$store.commit('recordSnapshot')
},
Expand All @@ -261,19 +393,23 @@ export default {
try {
const data = JSON.parse(this.jsonData)
if (!Array.isArray(data)) {
this.$message.error('数据格式错误,组件数据必须是一个数组')
this.$message.error('数据格式错误,组件数据必须是一个数组')
return
}
if (this.isExport) {
this.downloadFileUtil(this.jsonData, 'application/json', 'data.json')
this.downloadFileUtil(
this.jsonData,
'application/json',
'data.json',
)
} else {
this.$store.commit('setComponentData', data)
}
this.isShowDialog = false
} catch (error) {
this.$message.error('数据格式错误,请传入合法的 JSON 格式数据')
this.$message.error('数据格式错误,请传入合法的 JSON 格式数据')
}
},
Expand Down Expand Up @@ -322,6 +458,10 @@ export default {
border-color: var(--ace-bg-color);
border-bottom: 1px solid var(--border-color);
.align-dropdown {
margin-left: 10px;
}
.canvas-config {
display: inline-block;
margin-left: 10px;
Expand Down
Loading

0 comments on commit 8538ed1

Please sign in to comment.