feat:【mall】diy editor 的 hot-zone 代码优化(50%)

This commit is contained in:
YunaiV
2025-10-28 19:22:27 +08:00
parent a4f7a51ba0
commit 4de0050610
6 changed files with 77 additions and 69 deletions

View File

@@ -2,10 +2,9 @@ import type { StyleValue } from 'vue';
import type { HotZoneItemProperty } from '../../config';
// 热区的最小宽高
export const HOT_ZONE_MIN_SIZE = 100;
export const HOT_ZONE_MIN_SIZE = 100; // 热区的最小宽高
// 控制的类型
/** 控制的类型 */
export enum CONTROL_TYPE_ENUM {
LEFT,
TOP,
@@ -13,14 +12,14 @@ export enum CONTROL_TYPE_ENUM {
HEIGHT,
}
// 定义热区的控制点
/** 定义热区的控制点 */
export interface ControlDot {
position: string;
types: CONTROL_TYPE_ENUM[];
style: StyleValue;
}
// 热区的8个控制点
/** 热区的 8 个控制点 */
export const CONTROL_DOT_LIST = [
{
position: '左上角',
@@ -98,10 +97,10 @@ export const CONTROL_DOT_LIST = [
] as ControlDot[];
// region 热区的缩放
// 热区的缩放比例
export const HOT_ZONE_SCALE_RATE = 2;
// 缩小:缩回适合手机屏幕的大小
export const zoomOut = (list?: HotZoneItemProperty[]) => {
export const HOT_ZONE_SCALE_RATE = 2; // 热区的缩放比例
/** 缩小:缩回适合手机屏幕的大小 */
export function zoomOut(list?: HotZoneItemProperty[]) {
return (
list?.map((hotZone) => ({
...hotZone,
@@ -111,9 +110,10 @@ export const zoomOut = (list?: HotZoneItemProperty[]) => {
height: (hotZone.height /= HOT_ZONE_SCALE_RATE),
})) || []
);
};
// 放大:作用是为了方便在电脑屏幕上编辑
export const zoomIn = (list?: HotZoneItemProperty[]) => {
}
/** 放大:作用是为了方便在电脑屏幕上编辑 */
export function zoomIn(list?: HotZoneItemProperty[]) {
return (
list?.map((hotZone) => ({
...hotZone,
@@ -123,7 +123,8 @@ export const zoomIn = (list?: HotZoneItemProperty[]) => {
height: (hotZone.height *= HOT_ZONE_SCALE_RATE),
})) || []
);
};
}
// endregion
/**

View File

@@ -10,6 +10,8 @@ import { IconifyIcon } from '@vben/icons';
import { ElButton, ElDialog, ElImage } from 'element-plus';
import { AppLinkSelectDialog } from '#/views/mall/promotion/components';
import {
CONTROL_DOT_LIST,
CONTROL_TYPE_ENUM,
@@ -22,7 +24,7 @@ import {
/** 热区编辑对话框 */
defineOptions({ name: 'HotZoneEditDialog' });
// 定义属性
/** 定义属性 */
const props = defineProps({
modelValue: {
type: Array<HotZoneItemProperty>,
@@ -33,51 +35,53 @@ const props = defineProps({
default: '',
},
});
const emit = defineEmits(['update:modelValue']);
const formData = ref<HotZoneItemProperty[]>([]);
// 弹窗的是否显示
const dialogVisible = ref(false);
// 打开弹窗
const dialogVisible = ref(false); // 弹窗的是否显示
/** 打开弹窗 */
const open = () => {
// 放大
formData.value = zoomIn(props.modelValue);
dialogVisible.value = true;
};
// 提供 open 方法,用于打开弹窗
defineExpose({ open });
// 热区容器
const container = ref<HTMLDivElement>();
defineExpose({ open }); // 提供 open 方法,用于打开弹窗
// 增加热区
const handleAdd = () => {
const container = ref<HTMLDivElement>(); // 热区容器
/** 增加热区 */
function handleAdd() {
formData.value.push({
width: HOT_ZONE_MIN_SIZE,
height: HOT_ZONE_MIN_SIZE,
top: 0,
left: 0,
} as HotZoneItemProperty);
};
// 删除热区
const handleRemove = (hotZone: HotZoneItemProperty) => {
formData.value = formData.value.filter((item) => item !== hotZone);
};
}
// 移动热区
const handleMove = (item: HotZoneItemProperty, e: MouseEvent) => {
/** 删除热区 */
function handleRemove(hotZone: HotZoneItemProperty) {
formData.value = formData.value.filter((item) => item !== hotZone);
}
/** 移动热区 */
function handleMove(item: HotZoneItemProperty, e: MouseEvent) {
useDraggable(item, e, (left, top, _, __, moveWidth, moveHeight) => {
setLeft(item, left + moveWidth);
setTop(item, top + moveHeight);
});
};
}
// 调整热区大小、位置
const handleResize = (
/** 调整热区大小、位置 */
function handleResize(
item: HotZoneItemProperty,
ctrlDot: ControlDot,
e: MouseEvent,
) => {
) {
useDraggable(item, e, (left, top, width, height, moveWidth, moveHeight) => {
ctrlDot.types.forEach((type) => {
switch (type) {
@@ -112,23 +116,25 @@ const handleResize = (
}
});
});
};
}
// 设置X轴坐标
const setLeft = (item: HotZoneItemProperty, left: number) => {
/** 设置 X 轴坐标 */
function setLeft(item: HotZoneItemProperty, left: number) {
// 不能超出容器
if (left >= 0 && left <= container.value!.offsetWidth - item.width) {
item.left = left;
}
};
// 设置Y轴坐标
const setTop = (item: HotZoneItemProperty, top: number) => {
}
/** 设置Y轴坐标 */
function setTop(item: HotZoneItemProperty, top: number) {
// 不能超出容器
if (top >= 0 && top <= container.value!.offsetHeight - item.height) {
item.top = top;
}
};
// 设置宽度
}
/** 设置宽度 */
const setWidth = (item: HotZoneItemProperty, width: number) => {
// 不能小于最小宽度 && 不能超出容器右边
if (
@@ -138,7 +144,8 @@ const setWidth = (item: HotZoneItemProperty, width: number) => {
item.width = width;
}
};
// 设置高度
/** 设置高度 */
const setHeight = (item: HotZoneItemProperty, height: number) => {
// 不能小于最小高度 && 不能超出容器底部
if (
@@ -149,13 +156,12 @@ const setHeight = (item: HotZoneItemProperty, height: number) => {
}
};
// 处理对话框关闭
/** 处理对话框关闭 */
const handleSubmit = () => {
// 会自动触发handleClose
dialogVisible.value = false;
};
// 处理对话框关闭
/** 处理对话框关闭 */
const handleClose = () => {
// 缩小
const list = zoomOut(formData.value);
@@ -164,12 +170,16 @@ const handleClose = () => {
const activeHotZone = ref<HotZoneItemProperty>();
const appLinkDialogRef = ref();
const handleShowAppLinkDialog = (hotZone: HotZoneItemProperty) => {
activeHotZone.value = hotZone;
appLinkDialogRef.value.open(hotZone.url);
};
const handleAppLinkChange = (appLink: AppLink) => {
if (!appLink || !activeHotZone.value) return;
if (!appLink || !activeHotZone.value) {
return;
}
activeHotZone.value.name = appLink.name;
activeHotZone.value.url = appLink.path;
};
@@ -231,6 +241,7 @@ const handleAppLinkChange = (appLink: AppLink) => {
</ElButton>
</template>
</ElDialog>
<AppLinkSelectDialog
ref="appLinkDialogRef"
@app-link-change="handleAppLinkChange"

View File

@@ -2,31 +2,22 @@ import type { ComponentStyle, DiyComponent } from '../../../util';
/** 热区属性 */
export interface HotZoneProperty {
// 图片地址
imgUrl: string;
// 导航菜单列表
list: HotZoneItemProperty[];
// 组件样式
style: ComponentStyle;
imgUrl: string; // 图片地址
list: HotZoneItemProperty[]; // 导航菜单列表
style: ComponentStyle; // 组件样式
}
/** 热区项目属性 */
export interface HotZoneItemProperty {
// 链接的名称
name: string;
// 链接
url: string;
//
width: number;
// 高
height: number;
// 上
top: number;
// 左
left: number;
name: string; // 链接的名称
url: string; // 链接
width: number; //
height: number; // 高
top: number; //
left: number; // 左
}
// 定义组件
/** 定义组件 */
export const component = {
id: 'HotZone',
name: '热区',

View File

@@ -5,6 +5,7 @@ import { ElImage } from 'element-plus';
/** 热区 */
defineOptions({ name: 'HotZone' });
const props = defineProps<{ property: HotZoneProperty }>();
</script>

View File

@@ -15,12 +15,14 @@ import HotZoneEditDialog from './components/hot-zone-edit-dialog/index.vue';
defineOptions({ name: 'HotZoneProperty' });
const props = defineProps<{ modelValue: HotZoneProperty }>();
const emit = defineEmits(['update:modelValue']);
const formData = useVModel(props, 'modelValue', emit);
// 热区编辑对话框
const editDialogRef = ref();
// 打开热区编辑对话框
const editDialogRef = ref(); // 热区编辑对话框
/** 打开热区编辑对话框 */
const handleOpenEditDialog = () => {
editDialogRef.value.open();
};
@@ -49,6 +51,7 @@ const handleOpenEditDialog = () => {
设置热区
</ElButton>
</ComponentContainerProperty>
<!-- 热区编辑对话框 -->
<HotZoneEditDialog
ref="editDialogRef"

View File

@@ -1,3 +1,4 @@
export { default as AppLinkSelectDialog } from './app-link-input/app-link-select-dialog.vue';
export { default as AppLinkInput } from './app-link-input/index.vue';
export { default as ColorInput } from './color-input/index.vue';
export { default as DiyEditor } from './diy-editor/index.vue';