feat: add generate html feature

This commit is contained in:
Jeremy Yu 2024-12-28 02:06:12 +08:00
parent 14d4005528
commit ef06021e0b
4 changed files with 225 additions and 11 deletions

View File

@ -10,7 +10,8 @@
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>迅排设计 - 轻松创意,迅捷排版,感受云上设计带来的乐趣!</title>
<script> var _hmt = _hmt || [] </script>
</head>

View File

@ -7,14 +7,14 @@
-->
<template>
<div id="main">
<div id="page-design" ref="page_design" :style="{ paddingTop: dPaddingTop + 'px', minWidth: (dPage.width * dZoom) / 100 + dPresetPadding * 2 + 'px' }">
<div id="page-design" ref="page_design" :style="{ paddingTop: dPaddingTop + 'px', minWidth: (dPage.width * dZoom) / 100 + (padding ?? dPresetPadding) * 2 + 'px' }">
<div
id="out-page"
class="out-page"
:style="{
padding: dPresetPadding + 'px',
width: (dPage.width * dZoom) / 100 + dPresetPadding * 2 + 'px',
height: (dPage.height * dZoom) / 100 + dPresetPadding * 2 + 'px',
padding: padding ?? dPresetPadding + 'px',
width: (dPage.width * dZoom) / 100 + (padding ?? dPresetPadding) * 2 + 'px',
height: (dPage.height * dZoom) / 100 + (padding ?? dPresetPadding) * 2 + 'px',
opacity: 1 - (dZoom < 100 ? dPage.tag : 0),
}"
>
@ -22,7 +22,7 @@
<resize-page :width="(dPage.width * dZoom) / 100" :height="(dPage.height * dZoom) / 100" />
<watermark :customStyle="{ height: (dPage.height * dZoom) / 100 + 'px' }">
<div
:id="pageDesignCanvasId"
:id="props.pageDesignCanvasId"
class="design-canvas"
:data-type="dPage.type"
:data-uuid="dPage.uuid"
@ -66,7 +66,7 @@
</template>
<script lang="ts" setup>
import { onMounted } from 'vue'
import { computed, onMounted } from 'vue'
import { getTarget } from '@/common/methods/target'
import setWidgetData from '@/common/methods/DesignFeatures/setWidgetData'
import PointImg from '@/utils/plugins/pointImg'
@ -78,10 +78,17 @@ import { storeToRefs } from 'pinia'
import { TPageState } from '@/store/design/canvas/d'
import resizePage from './comps/resize.vue'
import watermark from './comps/pageWatermark.vue'
import { TdWidgetData } from '@/store/design/widget'
//
type TProps = {
pageDesignCanvasId: string
/** 以下参数仅用于图片渲染html */
padding?: number
/** 用于生成渲染图片 */
renderDPage?: TPageState
renderDWdigets?: TdWidgetData[]
zoom?: number
}
type TParentData = {
@ -95,12 +102,16 @@ const controlStore = useControlStore()
const widgetStore = useWidgetStore()
const canvasStore = useCanvasStore()
const { pageDesignCanvasId } = defineProps<TProps>()
const props = defineProps<TProps>()
const { dPage } = storeToRefs(useCanvasStore())
const { dZoom, dPresetPadding, dPaddingTop, dScreen } = storeToRefs(canvasStore)
const { dPage: curDPage } = storeToRefs(useCanvasStore())
const { dZoom: curZoom, dPresetPadding, dPaddingTop, dScreen } = storeToRefs(canvasStore)
const { dDraging, showRotatable, dAltDown, dSpaceDown } = storeToRefs(controlStore)
const { dWidgets, dActiveElement, dSelectWidgets, dHoverUuid } = storeToRefs(widgetStore)
const { dWidgets: curWidgets, dActiveElement, dSelectWidgets, dHoverUuid } = storeToRefs(widgetStore)
const dPage = computed(() => props.renderDPage ?? curDPage.value)
const dWidgets = computed(() => props.renderDWdigets ?? curWidgets.value)
const dZoom = computed(() => props.zoom ?? curZoom.value)
let _dropIn: string | null = ''
let _srcCache: string | null = ''

View File

@ -37,6 +37,11 @@ export default [
name: 'Draw',
component: () => import(/* webpackChunkName: 'draw' */ '@/views/Draw.vue'),
},
{
path: "/html",
name: "Html",
component: () => import(/* webpackChunkName: 'html' */ '@/views/Html.vue'),
},
{
path: '/psd',
name: 'Psd',

197
src/views/Html.vue Normal file
View File

@ -0,0 +1,197 @@
<!--
* @Author: Jeremy Yu
* @Date: 2024-12-27 00:02:46
* @Description: 图片生成HTML页面
* @LastEditors: Jeremy Yu <https://book.yzmblog.top>
* @LastEditTime: 2024-12-28 12:28:00
-->
<template>
<div ref="pageDesignIndex">
<div class="page-design-index-wrap" id="page-draw-html-wrap">
<template v-for="x in pageGroup" :key="x.pageData.uuid">
<design-board
class="page-design-wrap fixed-canvas"
pageDesignCanvasId="page-design-canvas"
:padding="0"
:renderDWdigets="x.dWidgets"
:renderDPage="x.pageData"
:zoom="x.zoom * 100"
/>
</template>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, nextTick, ref, onUnmounted } from 'vue'
import api from '@/api'
import Preload from '@/utils/plugins/preload'
import FontFaceObserver from 'fontfaceobserver'
import { fontWithDraw, font2style } from '@/utils/widgets/loadFontRule'
import designBoard from '@/components/modules/layout/designBoard/index.vue'
import { useRoute } from 'vue-router'
import { TPageState } from '@/store/design/canvas/d'
import { TdWidgetData } from '@/store/design/widget'
const route = useRoute()
const pageGroup = ref<{pageData: TPageState, dWidgets: TdWidgetData[], zoom: number}[]>([])
onMounted(() => {
nextTick(() => {
load()
window.addEventListener("resize", handleResize, false);
})
})
onUnmounted(() => {
window.removeEventListener("resize", handleResize, false);
})
async function load() {
let backgroundImage = ''
let loadFlag = false
const { id, tempid }: any = route.query
if (id || tempid) {
const postData = {
id: id || tempid
}
const { data } = await api.home[id ? 'getWorks' : 'getTempDetail'](postData)
let contentGroup = JSON.parse(data)
contentGroup = Array.isArray(contentGroup) ? contentGroup : [contentGroup]
for (let i = 0; i < contentGroup.length; i++) {
const { global, layers } = contentGroup[i]
let content = {page: global, widgets: layers}
const widgets = content.widgets
const zoom = controlScale(content.page?.width)
//
backgroundImage = content.page?.backgroundImage
backgroundImage && delete content.page.backgroundImage
await nextTick()
pageGroup.value.push({
pageData: content.page,
dWidgets: widgets,
zoom,
})
const imgsData: HTMLImageElement[] = []
const svgsData: HTMLImageElement[] = []
const fontLoaders: Promise<void>[] = []
const fontContent: Record<string, string> = {}
let fontData: string[] = []
widgets.forEach((item: any) => {
if (item.fontClass && item.fontClass.value) {
const loader = new FontFaceObserver(item.fontClass.value)
fontData.push(item.fontClass)
fontLoaders.push(loader.load(null, 30000)) //
//
if (fontContent[item.fontClass.value]) {
fontContent[item.fontClass.value] += item.text
} else {
fontContent[item.fontClass.value] = item.text
}
}
// svg
try {
if (item.svgUrl && item.type === 'w-svg') {
const cNodes: any = (window as any).document.getElementById(item.uuid).childNodes
svgsData.push(cNodes)
} else if (item.imgUrl && !item.isNinePatch) {
const cNodes: any = (window as any).document.getElementById(item.uuid).childNodes
for (const el of cNodes) {
if (el.className && el.className.includes('img__box')) {
imgsData.push(el.firstChild)
}
}
}
} catch (e) {}
})
//
if (backgroundImage) {
const preloadBg = new Preload([backgroundImage])
await preloadBg.imgs()
}
try {
fontWithDraw && (await font2style(fontContent, fontData))
// console.log('1. base64 yes')
const preload = new Preload(imgsData)
await preload.doms()
// console.log('2. image yes')
const preload2 = new Preload(svgsData)
await preload2.svgs()
// console.log('3. svg yes')
} catch (e) {
console.log(e)
}
try {
await Promise.all(fontLoaders)
// console.log('4. font yes')
} catch (e) {
// console.log(e)
}
loadFlag = true
console.log('--> now u can start generate artboard to html!')
setTimeout(() => {
try {
;(window as any).loadFinishToInject('done')
} catch (err) {}
}, 100)
}
}
//
setTimeout(() => {
!loadFlag && (window as any).loadFinishToInject('done')
}, 60000)
}
function controlScale(width: number) {
const winWidth = document.documentElement.clientWidth
let curZoom = (winWidth / width);
curZoom = curZoom > 1 ? 1 : curZoom
return curZoom
}
function handleResize() {
pageGroup.value = pageGroup.value.map(val => {
val.zoom = controlScale(val.pageData.width);
return val
})
}
</script>
<style lang="less" scoped>
@import url('@/assets/styles/design.less');
#page-draw-html-wrap {
width: 100vw;
height: 100vh;
overflow: scroll;
offset: 0px;
scrollbar-width: none; /* Firefox 隐藏滚动条 */
#main {
overflow: hidden;
}
}
#page-draw-html-wrap::-webkit-scrollbar {
display: none; /* WebKit 浏览器隐藏滚动条 */
}
</style>
<style lang="less">
.layer-hover {
outline: 0 !important;
}
</style>