parent
b2e9e9273d
commit
8cb041b57a
45
src/components/DiyEditor/components/ComponentContainer.vue
Normal file
45
src/components/DiyEditor/components/ComponentContainer.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div
|
||||
:style="{
|
||||
...style,
|
||||
background: property.bgType === 'color' ? property.bgColor : `url(${property.bgImg})`
|
||||
}"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ComponentStyle } from '@/components/DiyEditor/util'
|
||||
|
||||
/**
|
||||
* 组件容器
|
||||
* 用于包裹组件,为组件提供 背景、外边距、内边距、边框等样式
|
||||
*/
|
||||
defineOptions({ name: 'ComponentContainer' })
|
||||
|
||||
const props = defineProps<{ property: ComponentStyle }>()
|
||||
|
||||
const style = computed(() => {
|
||||
if (!props.property) {
|
||||
return {}
|
||||
}
|
||||
return {
|
||||
marginTop: `${props.property.marginTop || 0}px`,
|
||||
marginBottom: `${props.property.marginBottom || 0}px`,
|
||||
marginLeft: `${props.property.marginLeft || 0}px`,
|
||||
marginRight: `${props.property.marginRight || 0}px`,
|
||||
paddingTop: `${props.property.paddingTop || 0}px`,
|
||||
paddingRight: `${props.property.paddingRight || 0}px`,
|
||||
paddingBottom: `${props.property.paddingBottom || 0}px`,
|
||||
paddingLeft: `${props.property.paddingLeft || 0}px`,
|
||||
borderTopLeftRadius: `${props.property.borderTopLeftRadius || 0}px`,
|
||||
borderTopRightRadius: `${props.property.borderTopRightRadius || 0}px`,
|
||||
borderBottomRightRadius: `${props.property.borderBottomRightRadius || 0}px`,
|
||||
borderBottomLeftRadius: `${props.property.borderBottomLeftRadius || 0}px`,
|
||||
overflow: 'hidden'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<el-tabs stretch>
|
||||
<el-tab-pane label="内容">
|
||||
<slot></slot>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="样式" lazy>
|
||||
<el-card header="组件样式" class="property-group">
|
||||
<el-form :model="formData" label-width="80px">
|
||||
<el-form-item label="组件背景" prop="bgType">
|
||||
<el-radio-group v-model="formData.bgType">
|
||||
<el-radio label="color">纯色</el-radio>
|
||||
<el-radio label="img">图片</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="选择颜色" prop="bgColor" v-if="formData.bgType === 'color'">
|
||||
<ColorInput v-model="formData.bgColor" />
|
||||
</el-form-item>
|
||||
<el-form-item label="上传图片" prop="bgImg" v-else>
|
||||
<UploadImg v-model="formData.bgImg" :limit="1">
|
||||
<template #tip>建议宽度 750px</template>
|
||||
</UploadImg>
|
||||
</el-form-item>
|
||||
<el-tree :data="treeData" :expand-on-click-node="false">
|
||||
<template #default="{ node, data }">
|
||||
<el-form-item
|
||||
:label="data.label"
|
||||
:prop="data.prop"
|
||||
:label-width="node.level === 1 ? '80px' : '62px'"
|
||||
class="tree-form-item w-full m-b-0!"
|
||||
>
|
||||
<el-slider
|
||||
v-model="formData[data.prop]"
|
||||
:max="100"
|
||||
:min="0"
|
||||
show-input
|
||||
input-size="small"
|
||||
:show-input-controls="false"
|
||||
@input="handleSliderChange(data.prop)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</template>
|
||||
</el-tree>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ComponentStyle, usePropertyForm } from '@/components/DiyEditor/util'
|
||||
|
||||
/**
|
||||
* 组件容器属性
|
||||
* 用于包裹组件,为组件提供 背景、外边距、内边距、边框等样式
|
||||
*/
|
||||
defineOptions({ name: 'ComponentContainer' })
|
||||
|
||||
const props = defineProps<{ modelValue: ComponentStyle }>()
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const { formData } = usePropertyForm(props.modelValue, emit)
|
||||
|
||||
const treeData = [
|
||||
{
|
||||
label: '外部边距',
|
||||
prop: 'margin',
|
||||
children: [
|
||||
{
|
||||
label: '上',
|
||||
prop: 'marginTop'
|
||||
},
|
||||
{
|
||||
label: '右',
|
||||
prop: 'marginRight'
|
||||
},
|
||||
{
|
||||
label: '下',
|
||||
prop: 'marginBottom'
|
||||
},
|
||||
{
|
||||
label: '左',
|
||||
prop: 'marginLeft'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '内部边距',
|
||||
prop: 'padding',
|
||||
children: [
|
||||
{
|
||||
label: '上',
|
||||
prop: 'paddingTop'
|
||||
},
|
||||
{
|
||||
label: '右',
|
||||
prop: 'paddingRight'
|
||||
},
|
||||
{
|
||||
label: '下',
|
||||
prop: 'paddingBottom'
|
||||
},
|
||||
{
|
||||
label: '左',
|
||||
prop: 'paddingLeft'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '边框圆角',
|
||||
prop: 'borderRadius',
|
||||
children: [
|
||||
{
|
||||
label: '上左',
|
||||
prop: 'borderTopLeftRadius'
|
||||
},
|
||||
{
|
||||
label: '上右',
|
||||
prop: 'borderTopRightRadius'
|
||||
},
|
||||
{
|
||||
label: '下右',
|
||||
prop: 'borderBottomRightRadius'
|
||||
},
|
||||
{
|
||||
label: '下左',
|
||||
prop: 'borderBottomLeftRadius'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const handleSliderChange = (prop: string) => {
|
||||
switch (prop) {
|
||||
case 'margin':
|
||||
formData.value.marginTop = formData.value.margin
|
||||
formData.value.marginRight = formData.value.margin
|
||||
formData.value.marginBottom = formData.value.margin
|
||||
formData.value.marginLeft = formData.value.margin
|
||||
break
|
||||
case 'padding':
|
||||
formData.value.paddingTop = formData.value.padding
|
||||
formData.value.paddingRight = formData.value.padding
|
||||
formData.value.paddingBottom = formData.value.padding
|
||||
formData.value.paddingLeft = formData.value.padding
|
||||
break
|
||||
case 'borderRadius':
|
||||
formData.value.borderTopLeftRadius = formData.value.borderRadius
|
||||
formData.value.borderTopRightRadius = formData.value.borderRadius
|
||||
formData.value.borderBottomRightRadius = formData.value.borderRadius
|
||||
formData.value.borderBottomLeftRadius = formData.value.borderRadius
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.tree-form-item {
|
||||
:deep(.el-slider__runway) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
:deep(.el-input-number) {
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-aside class="editor-left" width="260px">
|
||||
<el-aside class="editor-left" width="261px">
|
||||
<el-scrollbar>
|
||||
<el-collapse v-model="extendGroups">
|
||||
<el-collapse-item
|
||||
|
@ -29,7 +29,7 @@ export const component = {
|
||||
title: '页面标题',
|
||||
description: '',
|
||||
navBarHeight: 35,
|
||||
backgroundColor: '#f5f5f5',
|
||||
backgroundColor: '#fff',
|
||||
backgroundImage: '',
|
||||
styleType: 'default',
|
||||
alwaysShow: true,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DiyComponent } from '@/components/DiyEditor/util'
|
||||
import { ComponentStyle, DiyComponent } from '@/components/DiyEditor/util'
|
||||
|
||||
/** 搜索框属性 */
|
||||
export interface SearchProperty {
|
||||
@ -7,10 +7,10 @@ export interface SearchProperty {
|
||||
borderRadius: number // 框体样式
|
||||
placeholder: string // 占位文字
|
||||
placeholderPosition: PlaceholderPosition // 占位文字位置
|
||||
backgroundColor: string // 背景颜色
|
||||
borderColor: string // 框体颜色
|
||||
backgroundColor: string // 框体颜色
|
||||
textColor: string // 字体颜色
|
||||
hotKeywords: string[] // 热词
|
||||
style: ComponentStyle
|
||||
}
|
||||
|
||||
// 文字位置
|
||||
@ -27,9 +27,17 @@ export const component = {
|
||||
borderRadius: 0,
|
||||
placeholder: '搜索商品',
|
||||
placeholderPosition: 'left',
|
||||
backgroundColor: 'rgb(249, 249, 249)',
|
||||
borderColor: 'rgb(255, 255, 255)',
|
||||
backgroundColor: 'rgb(238, 238, 238)',
|
||||
textColor: 'rgb(150, 151, 153)',
|
||||
hotKeywords: []
|
||||
hotKeywords: [],
|
||||
style: {
|
||||
bgType: 'color',
|
||||
bgColor: '#fff',
|
||||
marginBottom: 8,
|
||||
paddingTop: 8,
|
||||
paddingRight: 8,
|
||||
paddingBottom: 8,
|
||||
paddingLeft: 8
|
||||
} as ComponentStyle
|
||||
}
|
||||
} as DiyComponent<SearchProperty>
|
||||
|
@ -2,8 +2,6 @@
|
||||
<div
|
||||
class="search-bar"
|
||||
:style="{
|
||||
background: property.backgroundColor,
|
||||
border: `1px solid ${property.backgroundColor}`,
|
||||
color: property.textColor
|
||||
}"
|
||||
>
|
||||
@ -12,7 +10,7 @@
|
||||
class="inner"
|
||||
:style="{
|
||||
height: `${property.height}px`,
|
||||
background: property.borderColor,
|
||||
background: property.backgroundColor,
|
||||
borderRadius: `${property.borderRadius}px`
|
||||
}"
|
||||
>
|
||||
@ -44,13 +42,11 @@ defineProps<{ property: SearchProperty }>()
|
||||
|
||||
<style scoped lang="scss">
|
||||
.search-bar {
|
||||
position: relative;
|
||||
width: 375px;
|
||||
/* 搜索框 */
|
||||
.inner {
|
||||
position: relative;
|
||||
width: calc(100% - 16px);
|
||||
min-height: 28px;
|
||||
margin: 5px auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
|
@ -1,78 +1,77 @@
|
||||
<template>
|
||||
<el-text tag="p"> 搜索热词 </el-text>
|
||||
<el-text type="info" size="small"> 拖动左侧的小圆点可以调整热词顺序 </el-text>
|
||||
<ComponentContainerProperty v-model="formData.style">
|
||||
<el-text tag="p"> 搜索热词 </el-text>
|
||||
<el-text type="info" size="small"> 拖动左侧的小圆点可以调整热词顺序 </el-text>
|
||||
|
||||
<!-- 表单 -->
|
||||
<el-form label-width="80px" :model="formData" class="m-t-8px">
|
||||
<div v-if="formData.hotKeywords.length">
|
||||
<VueDraggable
|
||||
:list="formData.hotKeywords"
|
||||
item-key="index"
|
||||
handle=".drag-icon"
|
||||
:forceFallback="true"
|
||||
:animation="200"
|
||||
>
|
||||
<template #item="{ index }">
|
||||
<div class="mb-4px flex flex-row items-center gap-4px rounded bg-gray-100 p-8px">
|
||||
<Icon icon="ic:round-drag-indicator" class="drag-icon cursor-move" />
|
||||
<el-input v-model="formData.hotKeywords[index]" placeholder="请输入热词" />
|
||||
<Icon icon="ep:delete" class="text-red-500" @click="deleteHotWord(index)" />
|
||||
</div>
|
||||
</template>
|
||||
</VueDraggable>
|
||||
</div>
|
||||
<el-form-item label-width="0">
|
||||
<el-button @click="handleAddHotWord" type="primary" plain class="m-t-8px w-full">
|
||||
添加热词
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="框体样式">
|
||||
<el-radio-group v-model="formData!.borderRadius">
|
||||
<el-tooltip content="方形" placement="top">
|
||||
<el-radio-button :label="0">
|
||||
<Icon icon="tabler:input-search" />
|
||||
</el-radio-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="圆形" placement="top">
|
||||
<el-radio-button :label="10">
|
||||
<Icon icon="iconoir:input-search" />
|
||||
</el-radio-button>
|
||||
</el-tooltip>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="提示文字" prop="placeholder">
|
||||
<el-input v-model="formData.placeholder" />
|
||||
</el-form-item>
|
||||
<el-form-item label="文本位置" prop="placeholderPosition">
|
||||
<el-radio-group v-model="formData!.placeholderPosition">
|
||||
<el-tooltip content="居左" placement="top">
|
||||
<el-radio-button label="left">
|
||||
<Icon icon="ant-design:align-left-outlined" />
|
||||
</el-radio-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="居中" placement="top">
|
||||
<el-radio-button label="center">
|
||||
<Icon icon="ant-design:align-center-outlined" />
|
||||
</el-radio-button>
|
||||
</el-tooltip>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="扫一扫" prop="showScan">
|
||||
<el-switch v-model="formData!.showScan" />
|
||||
</el-form-item>
|
||||
<el-form-item label="框体高度" prop="height">
|
||||
<el-slider v-model="formData!.height" :max="50" :min="28" show-input input-size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="背景颜色" prop="backgroundColor">
|
||||
<ColorInput v-model="formData.backgroundColor" />
|
||||
</el-form-item>
|
||||
<el-form-item label="框体颜色" prop="borderColor">
|
||||
<ColorInput v-model="formData.borderColor" />
|
||||
</el-form-item>
|
||||
<el-form-item class="lef" label="文本颜色" prop="textColor">
|
||||
<ColorInput v-model="formData.textColor" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 表单 -->
|
||||
<el-form label-width="80px" :model="formData" class="m-t-8px">
|
||||
<div v-if="formData.hotKeywords.length">
|
||||
<VueDraggable
|
||||
:list="formData.hotKeywords"
|
||||
item-key="index"
|
||||
handle=".drag-icon"
|
||||
:forceFallback="true"
|
||||
:animation="200"
|
||||
>
|
||||
<template #item="{ index }">
|
||||
<div class="mb-4px flex flex-row items-center gap-4px rounded bg-gray-100 p-8px">
|
||||
<Icon icon="ic:round-drag-indicator" class="drag-icon cursor-move" />
|
||||
<el-input v-model="formData.hotKeywords[index]" placeholder="请输入热词" />
|
||||
<Icon icon="ep:delete" class="text-red-500" @click="deleteHotWord(index)" />
|
||||
</div>
|
||||
</template>
|
||||
</VueDraggable>
|
||||
</div>
|
||||
<el-form-item label-width="0">
|
||||
<el-button @click="handleAddHotWord" type="primary" plain class="m-t-8px w-full">
|
||||
添加热词
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="框体样式">
|
||||
<el-radio-group v-model="formData!.borderRadius">
|
||||
<el-tooltip content="方形" placement="top">
|
||||
<el-radio-button :label="0">
|
||||
<Icon icon="tabler:input-search" />
|
||||
</el-radio-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="圆形" placement="top">
|
||||
<el-radio-button :label="10">
|
||||
<Icon icon="iconoir:input-search" />
|
||||
</el-radio-button>
|
||||
</el-tooltip>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="提示文字" prop="placeholder">
|
||||
<el-input v-model="formData.placeholder" />
|
||||
</el-form-item>
|
||||
<el-form-item label="文本位置" prop="placeholderPosition">
|
||||
<el-radio-group v-model="formData!.placeholderPosition">
|
||||
<el-tooltip content="居左" placement="top">
|
||||
<el-radio-button label="left">
|
||||
<Icon icon="ant-design:align-left-outlined" />
|
||||
</el-radio-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="居中" placement="top">
|
||||
<el-radio-button label="center">
|
||||
<Icon icon="ant-design:align-center-outlined" />
|
||||
</el-radio-button>
|
||||
</el-tooltip>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="扫一扫" prop="showScan">
|
||||
<el-switch v-model="formData!.showScan" />
|
||||
</el-form-item>
|
||||
<el-form-item label="框体高度" prop="height">
|
||||
<el-slider v-model="formData!.height" :max="50" :min="28" show-input input-size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="框体颜色" prop="backgroundColor">
|
||||
<ColorInput v-model="formData.backgroundColor" />
|
||||
</el-form-item>
|
||||
<el-form-item class="lef" label="文本颜色" prop="textColor">
|
||||
<ColorInput v-model="formData.textColor" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ComponentContainerProperty>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -427,11 +427,13 @@ $phone-width: 375px;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
/* 属性面板分组 */
|
||||
.property-group {
|
||||
/* 属性分组 */
|
||||
:deep(.el-card__header) {
|
||||
:deep(.property-group) {
|
||||
margin: 0 -20px;
|
||||
/* 属性分组名称 */
|
||||
.el-card__header {
|
||||
border: none;
|
||||
background: var(--el-bg-color-page);
|
||||
padding: 8px 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,34 @@ export interface DiyComponentLibrary {
|
||||
components: string[]
|
||||
}
|
||||
|
||||
// 组件样式
|
||||
export interface ComponentStyle {
|
||||
// 背景类型
|
||||
bgType: 'color' | 'img'
|
||||
// 背景颜色
|
||||
bgColor: string
|
||||
// 背景图片
|
||||
bgImg: string
|
||||
// 外边距
|
||||
margin: number
|
||||
marginTop: number
|
||||
marginRight: number
|
||||
marginBottom: number
|
||||
marginLeft: number
|
||||
// 内边距
|
||||
padding: number
|
||||
paddingTop: number
|
||||
paddingRight: number
|
||||
paddingBottom: number
|
||||
paddingLeft: number
|
||||
// 边框圆角
|
||||
borderRadius: number
|
||||
borderTopLeftRadius: number
|
||||
borderTopRightRadius: number
|
||||
borderBottomRightRadius: number
|
||||
borderBottomLeftRadius: number
|
||||
}
|
||||
|
||||
// 页面配置
|
||||
export interface PageConfig {
|
||||
// 页面属性
|
||||
|
Loading…
Reference in New Issue
Block a user