style: background component move to right Panel

This commit is contained in:
ShawnPhang 2024-01-24 17:31:48 +08:00
parent 64a272ef12
commit a2bf3de99a
6 changed files with 88 additions and 37 deletions

View File

@ -11,15 +11,15 @@
[![](https://xp.palxp.cn/images/2023-7-16-1689500112694.gif)](https://design.palxp.cn/) [![](https://xp.palxp.cn/images/2023-7-16-1689500112694.gif)](https://design.palxp.cn/)
- 丝滑的操作体验,丰富的交互细节,基础功能完善 - 丝滑的页面操作体验,丰富的交互细节,基础功能完善
- 采用服务端生成图片,确保多端出图统一性,支持各种 CSS 特性 - 采用服务端生成图片,确保多端出图统一性,支持各种 CSS 特性
- 简易 AI 抠图工具,上传图片一键去除背景 - 简易 AI 抠图工具,上传图片一键去除背景
- 技术栈Vue3 、Vite2 、Vuex 、ElementPlus - 技术栈Vue3 、Vite2 、Vuex 、ElementPlus,开发体验畅快
- 图片生成Puppeteer、Express - 图片生成Puppeteer、Express
### 支持功能 ### 支持功能
- 导入 PSD 文件解析成模板、在线导出图片下载 - 导入 PSD 文件解析成模板、在线导出图片下载
- 元素拖拽、组合、缩放、层级调整、对齐等操作。 - 元素拖拽、组合、缩放、层级调整、对齐等操作。
- 图片素材插入、替换、裁剪,图片容器等功能。 - 图片素材插入、替换、裁剪,图片容器等功能。
- SVG 素材颜色、透明度编辑,文字花字组合。 - SVG 素材颜色、透明度编辑,文字花字组合。

View File

@ -9,7 +9,7 @@ module.exports = {
'ie >= 8', 'ie >= 8',
'last 10 versions', // 所有主流浏览器最近10版本用 'last 10 versions', // 所有主流浏览器最近10版本用
], ],
grid: true, grid: false,
}, },
}, },
} }

View File

@ -2,8 +2,8 @@
* @Author: ShawnPhang * @Author: ShawnPhang
* @Date: 2021-07-17 11:20:22 * @Date: 2021-07-17 11:20:22
* @Description: * @Description:
* @LastEditors: rayadaschn 115447518+rayadaschn@users.noreply.github.com * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-09-01 14:15:14 * @LastEditTime: 2024-01-24 17:07:44
*/ */
export default [ export default [
{ {
@ -31,14 +31,14 @@ export default [
show: false, show: false,
component: 'photo-list-wrap', component: 'photo-list-wrap',
}, },
// {
// name: '背景',
// icon: 'icon-beijing',
// show: false,
// component: 'bg-img-list-wrap',
// },
{ {
name: '背景', name: '工具箱',
icon: 'icon-beijing',
show: false,
component: 'bg-img-list-wrap',
},
{
name: '工具',
icon: 'icon-zujian01', icon: 'icon-zujian01',
show: false, show: false,
component: 'tools-list-wrap', component: 'tools-list-wrap',

View File

@ -3,7 +3,7 @@
<div class="widget-classify"> <div class="widget-classify">
<ul class="classify-wrap"> <ul class="classify-wrap">
<li v-for="(item, index) in widgetClassifyList" :key="index" :class="['classify-item', { 'active-classify-item': activeWidgetClassify === index }]" @click="clickClassify(index)"> <li v-for="(item, index) in widgetClassifyList" :key="index" :class="['classify-item', { 'active-classify-item': activeWidgetClassify === index }]" @click="clickClassify(index)">
<i :class="['iconfont', 'icon', item.icon]" :style="item.style"></i> <div class="icon-box"><i :class="['iconfont', 'icon', item.icon]" :style="item.style" /></div>
<p>{{ item.name }}</p> <p>{{ item.name }}</p>
</li> </li>
</ul> </ul>
@ -16,9 +16,9 @@
</div> </div>
<!-- <div v-show="active" class="side-wrap"><div class="pack__up" @click="active = false">&lt;</div></div> --> <!-- <div v-show="active" class="side-wrap"><div class="pack__up" @click="active = false">&lt;</div></div> -->
<div v-show="active" class="side-wrap"> <div v-show="active" class="side-wrap">
<el-tooltip effect="dark" content="收起侧边栏" placement="right"> <!-- <el-tooltip effect="dark" content="收起侧边栏" placement="right"> -->
<div class="pack__up" @click="active = false"></div> <div class="pack__up" @click="active = false"></div>
</el-tooltip> <!-- </el-tooltip> -->
</div> </div>
</div> </div>
</template> </template>
@ -49,7 +49,7 @@ export default {
onMounted(async () => { onMounted(async () => {
await nextTick() await nextTick()
const { koutu } = route.query const { koutu } = route.query
koutu && (state.activeWidgetClassify = 5) koutu && (state.activeWidgetClassify = 4)
}) })
watch( watch(
@ -125,9 +125,17 @@ export default {
justify-content: center; justify-content: center;
width: 100%; width: 100%;
p { p {
color: #9da3ac; color: #666666;
font-weight: 600;
margin-top: 2px; margin-top: 2px;
} }
.icon-box {
width: 24px;
height: 27px;
display: flex;
align-items: center;
justify-content: center;
}
.icon { .icon {
color: #070707; color: #070707;
} }

View File

@ -3,15 +3,15 @@
* @Date: 2021-08-27 15:16:07 * @Date: 2021-08-27 15:16:07
* @Description: 背景图 * @Description: 背景图
* @LastEditors: ShawnPhang <https://m.palxp.cn> * @LastEditors: ShawnPhang <https://m.palxp.cn>
* @LastEditTime: 2023-11-22 09:56:18 * @LastEditTime: 2024-01-24 16:39:27
--> -->
<template> <template>
<div class="wrap"> <div class="wrap">
<div class="color__box"> <div class="color__box" :style="modelStyle.color">
<div v-for="c in colors" :key="c" :style="{ background: c }" class="color__item" @click="setBGcolor(c)"></div> <div v-for="c in colors" :key="c" :style="{ background: c }" class="color__item" @click="setBGcolor(c)"></div>
</div> </div>
<ul v-if="showList" v-infinite-scroll="loadData" class="infinite-list" :infinite-scroll-distance="150" style="overflow: auto"> <ul v-if="showList" v-infinite-scroll="loadData" class="infinite-list" :infinite-scroll-distance="150" style="overflow: auto">
<div class="list"> <div class="list" :style="modelStyle.list">
<imageTip v-for="(item, i) in bgList" :key="i + 'i'" :detail="item"> <imageTip v-for="(item, i) in bgList" :key="i + 'i'" :detail="item">
<el-image class="list__img" :src="item.thumb" fit="cover" lazy loading="lazy" @click.stop="selectItem(item)" @dragstart="dragStart($event, item)"></el-image> <el-image class="list__img" :src="item.thumb" fit="cover" lazy loading="lazy" @click.stop="selectItem(item)" @dragstart="dragStart($event, item)"></el-image>
</imageTip> </imageTip>
@ -23,11 +23,16 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, reactive, toRefs, watch } from 'vue' import { defineComponent, reactive, toRefs, computed } from 'vue'
import api from '@/api' import api from '@/api'
import { mapActions, useStore } from 'vuex' import { mapActions, useStore } from 'vuex'
export default defineComponent({ export default defineComponent({
props: {
model: {
default: 'widgetPanel'
}
},
setup(props) { setup(props) {
const store = useStore() const store = useStore()
const state = reactive({ const state = reactive({
@ -37,6 +42,19 @@ export default defineComponent({
showList: true, showList: true,
colors: ['#000000ff', '#999999ff', '#CCCCCCff', '#FFFFFFff', '#E65353ff', '#FFD835ff', '#70BC59ff', '#607AF4ff', '#976BEEff'], colors: ['#000000ff', '#999999ff', '#CCCCCCff', '#FFFFFFff', '#E65353ff', '#FFD835ff', '#70BC59ff', '#607AF4ff', '#976BEEff'],
}) })
//
const models: any = {
widgetPanel: {
color: 'padding: 1.2rem 1rem',
list: 'grid-template-columns: auto auto auto;padding: 0 1rem;',
},
stylePanel: {
color: 'padding: 1.2rem 0;',
list: 'grid-template-columns: repeat(3, 76px);',
}
}
const modelStyle = computed(() => models[props.model])
const pageOptions = { page: 0, pageSize: 20 } const pageOptions = { page: 0, pageSize: 20 }
const loadData = () => { const loadData = () => {
@ -91,6 +109,7 @@ export default defineComponent({
load, load,
setBGcolor, setBGcolor,
loadData, loadData,
modelStyle
} }
}, },
methods: { methods: {
@ -135,14 +154,13 @@ export default defineComponent({
// } // }
.list { .list {
width: 100%; width: 100%;
padding: 0 1rem;
display: grid; display: grid;
grid-template-columns: auto auto auto; grid-gap: 5px;
&__img { &__img {
cursor: pointer; cursor: pointer;
width: 92px; width: 100%;
height: 92px; height: 92px;
margin-bottom: 5px; border-radius: 4px;
} }
&__img:hover::before { &__img:hover::before {
content: ' '; content: ' ';
@ -166,7 +184,6 @@ export default defineComponent({
.color { .color {
&__box { &__box {
padding: 1.2rem 1rem;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
} }

View File

@ -1,6 +1,12 @@
<template> <template>
<div id="page-style"> <div id="page-style">
<el-collapse v-model="activeNames"> <div v-if="showBgLib" style="width: 256px;height: 100%;">
<span class="header-back" @click="showBgLib = false">
<i class="iconfont icon-right"></i> 选择背景
</span>
<bg-img-list-wrap style="padding-top: 2rem;" model="stylePanel" />
</div>
<el-collapse v-else v-model="activeNames">
<el-collapse-item title="画布尺寸" name="1"> <el-collapse-item title="画布尺寸" name="1">
<div class="position-size"> <div class="position-size">
<number-input v-model="innerElement.width" label="宽" :maxValue="5000" @finish="(value) => finish('width', value)" /> <number-input v-model="innerElement.width" label="宽" :maxValue="5000" @finish="(value) => finish('width', value)" />
@ -8,6 +14,7 @@
</div> </div>
</el-collapse-item> </el-collapse-item>
<el-collapse-item title="背景设置" name="2"> <el-collapse-item title="背景设置" name="2">
<el-button style="width: 100%; margin: 0 0 1rem 0;" type="primary" link @click="showBgLib = true">在背景库中选择</el-button>
<Tabs :value="mode" @update:value="onChangeMode"> <Tabs :value="mode" @update:value="onChangeMode">
<TabPanel v-for="label in modes" :key="label" :label="label"></TabPanel> <TabPanel v-for="label in modes" :key="label" :label="label"></TabPanel>
</Tabs> </Tabs>
@ -15,16 +22,14 @@
<!-- <bg-img-select :img="innerElement.backgroundImage"/> --> <!-- <bg-img-select :img="innerElement.backgroundImage"/> -->
<div v-if="mode === '图片' && innerElement.backgroundImage" style="margin-top: 2rem"> <div v-if="mode === '图片' && innerElement.backgroundImage" style="margin-top: 2rem">
<el-image style="max-height: 428px" :src="innerElement.backgroundImage" fit="contain"></el-image> <el-image style="max-height: 428px" :src="innerElement.backgroundImage" fit="contain"></el-image>
<el-button style="width: 100%; margin-top: 0.7rem" size="small" @click="deleteBg">删除</el-button> <el-button class="btn-wrap" size="small" @click="deleteBg">删除</el-button>
</div> </div>
<uploader v-show="mode === '图片'" style="width: 100%; margin-top: 0.7rem" @done="uploadImgDone"> <uploader v-show="mode === '图片'" class="btn-wrap" @done="uploadImgDone">
<el-button style="width: 100%" plain>{{ innerElement.backgroundImage ? '换背景' : '上传背景' }}</el-button> <el-button style="width: 100%" plain>{{ innerElement.backgroundImage ? '换背景' : '上传背景' }}</el-button>
</uploader> </uploader>
<el-button v-show="mode === '图片' && innerElement.backgroundImage" style="width: 100%; margin-top: 0.7rem" size="small" @click="downloadBG">{{ downP ? downP + ' %' : '下载背景图' }}</el-button> <el-button v-show="mode === '图片' && innerElement.backgroundImage" class="btn-wrap" size="small" @click="downloadBG">{{ downP ? downP + ' %' : '下载背景图' }}</el-button>
</el-collapse-item> </el-collapse-item>
<!-- <el-collapse-item title="其他设置" name="3">
<el-input v-model="innerElement.name" label="名称" @finish="(value) => finish('name', value)" />
</el-collapse-item> -->
</el-collapse> </el-collapse>
</div> </div>
</template> </template>
@ -52,9 +57,9 @@ export default {
tag: false, tag: false,
ingoreKeys: ['backgroundColor', 'name', 'width', 'height'], ingoreKeys: ['backgroundColor', 'name', 'width', 'height'],
downP: 0, downP: 0,
// canvasRunning: false,
mode: '颜色', mode: '颜色',
modes: ['颜色', '图片'], modes: ['颜色', '图片'],
showBgLib: false
} }
}, },
computed: { computed: {
@ -189,4 +194,25 @@ export default {
.select { .select {
margin-bottom: 10px; margin-bottom: 10px;
} }
.btn-wrap {
width: 100%; margin-top: 0.7rem;
}
.header {
&-back {
cursor: pointer;
display: flex;
align-items: center;
color: #333;
font-size: 14px;
font-weight: 600;
height: 2.9rem;
position: absolute;
z-index: 2;
background: #ffffff;
width: 259px;
.icon-right {
transform: rotate(180deg);
}
}
}
</style> </style>