历史:
vue2 + Lodop 制作可视化设计页面 实现打印设计功能(一)
前言:
之前本来打算用直接拿之前做的vue2版本改改就发的,但考虑到现在主流都是vue3了,所以从这篇文章开始使用vue3来写,以及最后的demo也使用vue3
考虑到之前发的一些点过于分散,这篇开始打算就从头开始写这个功能,每篇最后发个本篇的示例demo
主要技术栈:vue3+vite+pinia+less+typescript
目录:
- 项目创建及模块定义,简单实现拖拽新增
- 组件点击拖拽移动
- 新增第一个自定义组件-HPText(文本组件)
- 新增HPText组件的菜单,组件菜单设置时组件动态变化
- 框选组件,批量移动
- 引入lodop,打印预览
- 待定...
正文:
创建vue3+vite项目
这个不用多说了,不属于本系列的范围
项目目录
最后项目创建后的目录大概长这样
定义设计页面viewport
<script setup lang="ts">
import {ref,h,resolveComponent} from 'vue'
import {QYComponent} from "../../../domains/qy-component.ts";
const edit = ref(null)
const page = ref({
height: 560,
width: 944,
})
const widgetStore = ref<QYComponent[]>([])
const 测试数据 = [{
uuid:'123',
attr: {
x: 10,
y: 10,
width: 90,
height: 20,
},
}]
const dropToAddCom = (ev) => {
ev.preventDefault()
const rest = edit.value.getBoundingClientRect();
测试数据[0].attr.x = Math.round(ev.clientX - rest.x)
测试数据[0].attr.y = Math.round(ev.clientY - rest.y)
widgetStore.value = [...测试数据];
}
const dragOver = (ev) => {
ev.preventDefault()
}
const handleMouseDown = (ev) => {
}
</script>
<template>
<div class="holder" id="viewport" ref="viewport" data-type="viewport">
<div
:style="{
height: page.height + 'px',
width: page.width + 'px'
}"
ref="edit"
class="screen"
@dragover.prevent="dragOver"
@drop="dropToAddCom($event)"
>
<!-- 组件 -->
<div
v-for="(moduleData,index) in widgetStore"
:style="{
position: 'absolute',
top: `${moduleData.attr.y}px`,
left: `${moduleData.attr.x}px`,
width: `${moduleData.attr.width}px`,
height:`${moduleData.attr.height}px`
}"
>
<component
:is="input"
:com="moduleData"
></component>
</div>
</div>
</div>
</template>
<style scoped>
.holder {
position: relative;
width: 100%;
display: flex;
justify-content: left;
overflow: auto;
font-size: 0;
border: 1px solid #f5f5f5;
border-width: 0 1px;
background-image: linear-gradient(45deg, #f5f5f5 25%, transparent 0, transparent 75%, #f5f5f5 0),
linear-gradient(45deg, #f5f5f5 25%, transparent 0, transparent 75%, #f5f5f5 0);
background-position: 0 0, 13px 13px;
background-size: 26px 26px;
}
.screen {
margin: 20px;
transform-origin: center top;
position: relative;
box-shadow: 0 0 5px 1px #cccccc;
background-color: #ffffff;
background-repeat: no-repeat;
}
.wrapper {
margin: 20px;
position: relative;
}
</style>
定义组件列表components-panel
<script setup lang="ts">
import {ref} from 'vue'
const dragStart = (ev) => {
}
</script>
<template>
<div class="component-main" style="display: flex;flex-direction: column">
<div style="margin: 5px;background: lightskyblue;color: white"
:draggable="true"
@dragstart="dragStart($event)">
文本
</div>
</div>
</template>
<style scoped>
.component-main {
border-radius: 5px;
height: 100%;
width: 200px;
overflow-x: hidden;
overflow-y: auto;
}
</style>
修改App.vue
<script setup lang="ts">
import viewport from './components/print-designer/viewport/index.vue'
import componentsPanel from './components/print-designer/components-panel/index.vue'
</script>
<template>
<div class="main" data-theme="qy-designer">
<components-panel/>
<viewport/>
</div>
</template>
<style scoped>
.main {
display: flex;
flex-direction: row;
width: 100%;
height: 100%;
user-select: none;
}
</style>
效果
注:这里使用的技术点因为已经在第一篇讲了,所以这里就不再赘述了
demo示例