feat:【mall】diy editor 的 navigation-bar 优化
This commit is contained in:
@@ -22,7 +22,7 @@ import {
|
|||||||
MagicCubeEditor,
|
MagicCubeEditor,
|
||||||
} from '#/views/mall/promotion/components';
|
} from '#/views/mall/promotion/components';
|
||||||
|
|
||||||
// 导航栏属性面板
|
/** 导航栏单元格属性面板 */
|
||||||
defineOptions({ name: 'NavigationBarCellProperty' });
|
defineOptions({ name: 'NavigationBarCellProperty' });
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -35,13 +35,19 @@ const props = defineProps({
|
|||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
const cellList = useVModel(props, 'modelValue', emit);
|
const cellList = useVModel(props, 'modelValue', emit);
|
||||||
|
|
||||||
// 单元格数量:小程序6个(右侧胶囊按钮占了2个),其它平台8个
|
/**
|
||||||
|
* 计算单元格数量
|
||||||
|
* 1. 小程序:6 个(因为右侧有胶囊按钮占据 2 个格子的空间)
|
||||||
|
* 2. 其它平台:8 个(全部空间可用)
|
||||||
|
*/
|
||||||
const cellCount = computed(() => (props.isMp ? 6 : 8));
|
const cellCount = computed(() => (props.isMp ? 6 : 8));
|
||||||
|
|
||||||
// 转换为Rect格式的数据
|
/** 转换为 Rect 格式的数据:MagicCubeEditor 组件需要 Rect 格式的数据来渲染热区 */
|
||||||
const rectList = computed<Rect[]>(() => {
|
const rectList = computed<Rect[]>(() => {
|
||||||
return cellList.value.map((cell) => ({
|
return cellList.value.map((cell) => ({
|
||||||
left: cell.left,
|
left: cell.left,
|
||||||
@@ -53,18 +59,19 @@ const rectList = computed<Rect[]>(() => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
// 选中的热区
|
const selectedHotAreaIndex = ref(0); // 选中的热区
|
||||||
const selectedHotAreaIndex = ref(0);
|
|
||||||
const handleHotAreaSelected = (
|
/** 处理热区被选中事件 */
|
||||||
|
function handleHotAreaSelected(
|
||||||
cellValue: NavigationBarCellProperty,
|
cellValue: NavigationBarCellProperty,
|
||||||
index: number,
|
index: number,
|
||||||
) => {
|
) {
|
||||||
selectedHotAreaIndex.value = index;
|
selectedHotAreaIndex.value = index;
|
||||||
if (!cellValue.type) {
|
if (!cellValue.type) {
|
||||||
cellValue.type = 'text';
|
cellValue.type = 'text';
|
||||||
cellValue.textColor = '#111111';
|
cellValue.textColor = '#111111';
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -141,5 +148,3 @@ const handleHotAreaSelected = (
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
|
||||||
|
|||||||
@@ -2,56 +2,35 @@ import type { DiyComponent } from '../../../util';
|
|||||||
|
|
||||||
/** 顶部导航栏属性 */
|
/** 顶部导航栏属性 */
|
||||||
export interface NavigationBarProperty {
|
export interface NavigationBarProperty {
|
||||||
// 背景类型
|
bgType: 'color' | 'img'; // 背景类型
|
||||||
bgType: 'color' | 'img';
|
bgColor: string; // 背景颜色
|
||||||
// 背景颜色
|
bgImg: string; // 图片链接
|
||||||
bgColor: string;
|
styleType: 'inner' | 'normal'; // 样式类型:默认 | 沉浸式
|
||||||
// 图片链接
|
alwaysShow: boolean; // 常驻显示
|
||||||
bgImg: string;
|
mpCells: NavigationBarCellProperty[]; // 小程序单元格列表
|
||||||
// 样式类型:默认 | 沉浸式
|
otherCells: NavigationBarCellProperty[]; // 其它平台单元格列表
|
||||||
styleType: 'inner' | 'normal';
|
|
||||||
// 常驻显示
|
|
||||||
alwaysShow: boolean;
|
|
||||||
// 小程序单元格列表
|
|
||||||
mpCells: NavigationBarCellProperty[];
|
|
||||||
// 其它平台单元格列表
|
|
||||||
otherCells: NavigationBarCellProperty[];
|
|
||||||
// 本地变量
|
|
||||||
_local: {
|
_local: {
|
||||||
// 预览顶部导航(小程序)
|
previewMp: boolean; // 预览顶部导航(小程序)
|
||||||
previewMp: boolean;
|
previewOther: boolean; // 预览顶部导航(非小程序)
|
||||||
// 预览顶部导航(非小程序)
|
}; // 本地变量
|
||||||
previewOther: boolean;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 顶部导航栏 - 单元格 属性 */
|
/** 顶部导航栏 - 单元格 属性 */
|
||||||
export interface NavigationBarCellProperty {
|
export interface NavigationBarCellProperty {
|
||||||
// 类型:文字 | 图片 | 搜索框
|
type: 'image' | 'search' | 'text'; // 类型:文字 | 图片 | 搜索框
|
||||||
type: 'image' | 'search' | 'text';
|
width: number; // 宽度
|
||||||
// 宽度
|
height: number; // 高度
|
||||||
width: number;
|
top: number; // 顶部位置
|
||||||
// 高度
|
left: number; // 左侧位置
|
||||||
height: number;
|
text: string; // 文字内容
|
||||||
// 顶部位置
|
textColor: string; // 文字颜色
|
||||||
top: number;
|
imgUrl: string; // 图片地址
|
||||||
// 左侧位置
|
url: string; // 图片链接
|
||||||
left: number;
|
placeholder: string; // 搜索框:提示文字
|
||||||
// 文字内容
|
borderRadius: number; // 搜索框:边框圆角半径
|
||||||
text: string;
|
|
||||||
// 文字颜色
|
|
||||||
textColor: string;
|
|
||||||
// 图片地址
|
|
||||||
imgUrl: string;
|
|
||||||
// 图片链接
|
|
||||||
url: string;
|
|
||||||
// 搜索框:提示文字
|
|
||||||
placeholder: string;
|
|
||||||
// 搜索框:边框圆角半径
|
|
||||||
borderRadius: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义组件
|
/** 定义组件 */
|
||||||
export const component = {
|
export const component = {
|
||||||
id: 'NavigationBar',
|
id: 'NavigationBar',
|
||||||
name: '顶部导航栏',
|
name: '顶部导航栏',
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ defineOptions({ name: 'NavigationBar' });
|
|||||||
|
|
||||||
const props = defineProps<{ property: NavigationBarProperty }>();
|
const props = defineProps<{ property: NavigationBarProperty }>();
|
||||||
|
|
||||||
// 背景
|
/** 计算背景样式 */
|
||||||
const bgStyle = computed(() => {
|
const bgStyle = computed(() => {
|
||||||
const background =
|
const background =
|
||||||
props.property.bgType === 'img' && props.property.bgImg
|
props.property.bgType === 'img' && props.property.bgImg
|
||||||
@@ -26,27 +26,31 @@ const bgStyle = computed(() => {
|
|||||||
: props.property.bgColor;
|
: props.property.bgColor;
|
||||||
return { background };
|
return { background };
|
||||||
});
|
});
|
||||||
// 单元格列表
|
|
||||||
|
/** 获取当前预览的单元格列表 */
|
||||||
const cellList = computed(() =>
|
const cellList = computed(() =>
|
||||||
props.property._local?.previewMp
|
props.property._local?.previewMp
|
||||||
? props.property.mpCells
|
? props.property.mpCells
|
||||||
: props.property.otherCells,
|
: props.property.otherCells,
|
||||||
);
|
);
|
||||||
// 单元格宽度
|
|
||||||
|
/** 计算单元格宽度 */
|
||||||
const cellWidth = computed(() => {
|
const cellWidth = computed(() => {
|
||||||
return props.property._local?.previewMp
|
return props.property._local?.previewMp
|
||||||
? (375 - 80 - 86) / 6
|
? (375 - 80 - 86) / 6
|
||||||
: (375 - 90) / 8;
|
: (375 - 90) / 8;
|
||||||
});
|
});
|
||||||
// 获得单元格样式
|
|
||||||
const getCellStyle = (cell: NavigationBarCellProperty) => {
|
/** 获取单元格样式 */
|
||||||
|
function getCellStyle(cell: NavigationBarCellProperty) {
|
||||||
return {
|
return {
|
||||||
width: `${cell.width * cellWidth.value + (cell.width - 1) * 10}px`,
|
width: `${cell.width * cellWidth.value + (cell.width - 1) * 10}px`,
|
||||||
left: `${cell.left * cellWidth.value + (cell.left + 1) * 10}px`,
|
left: `${cell.left * cellWidth.value + (cell.left + 1) * 10}px`,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
} as StyleValue;
|
} as StyleValue;
|
||||||
};
|
}
|
||||||
// 获得搜索框属性
|
|
||||||
|
/** 获取搜索框属性配置 */
|
||||||
const getSearchProp = computed(() => (cell: NavigationBarCellProperty) => {
|
const getSearchProp = computed(() => (cell: NavigationBarCellProperty) => {
|
||||||
return {
|
return {
|
||||||
height: 30,
|
height: 30,
|
||||||
|
|||||||
@@ -2,19 +2,31 @@
|
|||||||
import type { NavigationBarProperty } from './config';
|
import type { NavigationBarProperty } from './config';
|
||||||
|
|
||||||
import { useVModel } from '@vueuse/core';
|
import { useVModel } from '@vueuse/core';
|
||||||
|
import {
|
||||||
|
ElCard,
|
||||||
|
ElCheckbox,
|
||||||
|
ElForm,
|
||||||
|
ElFormItem,
|
||||||
|
ElRadio,
|
||||||
|
ElRadioGroup,
|
||||||
|
ElTooltip,
|
||||||
|
} from 'element-plus';
|
||||||
|
|
||||||
|
import UploadImg from '#/components/upload/image-upload.vue';
|
||||||
|
import { ColorInput } from '#/views/mall/promotion/components';
|
||||||
|
|
||||||
import NavigationBarCellProperty from './components/cell-property.vue';
|
import NavigationBarCellProperty from './components/cell-property.vue';
|
||||||
|
|
||||||
// 导航栏属性面板
|
/** 导航栏属性面板 */
|
||||||
defineOptions({ name: 'NavigationBarProperty' });
|
defineOptions({ name: 'NavigationBarProperty' });
|
||||||
|
|
||||||
const props = defineProps<{ modelValue: NavigationBarProperty }>();
|
const props = defineProps<{ modelValue: NavigationBarProperty }>();
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
// 表单校验
|
|
||||||
const rules = {
|
const rules = {
|
||||||
name: [{ required: true, message: '请输入页面名称', trigger: 'blur' }],
|
name: [{ required: true, message: '请输入页面名称', trigger: 'blur' }],
|
||||||
};
|
}; // 表单校验
|
||||||
|
|
||||||
const formData = useVModel(props, 'modelValue', emit);
|
const formData = useVModel(props, 'modelValue', emit);
|
||||||
if (!formData.value._local) {
|
if (!formData.value._local) {
|
||||||
@@ -23,47 +35,47 @@ if (!formData.value._local) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<el-form label-width="80px" :model="formData" :rules="rules">
|
<ElForm label-width="80px" :model="formData" :rules="rules">
|
||||||
<el-form-item label="样式" prop="styleType">
|
<ElFormItem label="样式" prop="styleType">
|
||||||
<el-radio-group v-model="formData!.styleType">
|
<ElRadioGroup v-model="formData!.styleType">
|
||||||
<el-radio value="normal">标准</el-radio>
|
<ElRadio value="normal">标准</ElRadio>
|
||||||
<el-tooltip
|
<ElTooltip
|
||||||
content="沉侵式头部仅支持微信小程序、APP,建议页面第一个组件为图片展示类组件"
|
content="沉侵式头部仅支持微信小程序、APP,建议页面第一个组件为图片展示类组件"
|
||||||
placement="top"
|
placement="top"
|
||||||
>
|
>
|
||||||
<el-radio value="inner">沉浸式</el-radio>
|
<ElRadio value="inner">沉浸式</ElRadio>
|
||||||
</el-tooltip>
|
</ElTooltip>
|
||||||
</el-radio-group>
|
</ElRadioGroup>
|
||||||
</el-form-item>
|
</ElFormItem>
|
||||||
<el-form-item
|
<ElFormItem
|
||||||
label="常驻显示"
|
label="常驻显示"
|
||||||
prop="alwaysShow"
|
prop="alwaysShow"
|
||||||
v-if="formData.styleType === 'inner'"
|
v-if="formData.styleType === 'inner'"
|
||||||
>
|
>
|
||||||
<el-radio-group v-model="formData!.alwaysShow">
|
<ElRadioGroup v-model="formData!.alwaysShow">
|
||||||
<el-radio :value="false">关闭</el-radio>
|
<ElRadio :value="false">关闭</ElRadio>
|
||||||
<el-tooltip
|
<ElTooltip
|
||||||
content="常驻显示关闭后,头部小组件将在页面滑动时淡入"
|
content="常驻显示关闭后,头部小组件将在页面滑动时淡入"
|
||||||
placement="top"
|
placement="top"
|
||||||
>
|
>
|
||||||
<el-radio :value="true">开启</el-radio>
|
<ElRadio :value="true">开启</ElRadio>
|
||||||
</el-tooltip>
|
</ElTooltip>
|
||||||
</el-radio-group>
|
</ElRadioGroup>
|
||||||
</el-form-item>
|
</ElFormItem>
|
||||||
<el-form-item label="背景类型" prop="bgType">
|
<ElFormItem label="背景类型" prop="bgType">
|
||||||
<el-radio-group v-model="formData.bgType">
|
<ElRadioGroup v-model="formData.bgType">
|
||||||
<el-radio value="color">纯色</el-radio>
|
<ElRadio value="color">纯色</ElRadio>
|
||||||
<el-radio value="img">图片</el-radio>
|
<ElRadio value="img">图片</ElRadio>
|
||||||
</el-radio-group>
|
</ElRadioGroup>
|
||||||
</el-form-item>
|
</ElFormItem>
|
||||||
<el-form-item
|
<ElFormItem
|
||||||
label="背景颜色"
|
label="背景颜色"
|
||||||
prop="bgColor"
|
prop="bgColor"
|
||||||
v-if="formData.bgType === 'color'"
|
v-if="formData.bgType === 'color'"
|
||||||
>
|
>
|
||||||
<ColorInput v-model="formData.bgColor" />
|
<ColorInput v-model="formData.bgColor" />
|
||||||
</el-form-item>
|
</ElFormItem>
|
||||||
<el-form-item label="背景图片" prop="bgImg" v-else>
|
<ElFormItem label="背景图片" prop="bgImg" v-else>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<UploadImg
|
<UploadImg
|
||||||
v-model="formData.bgImg"
|
v-model="formData.bgImg"
|
||||||
@@ -74,44 +86,42 @@ if (!formData.value._local) {
|
|||||||
/>
|
/>
|
||||||
<span class="mb-2 ml-2 text-xs text-gray-400">建议宽度:750</span>
|
<span class="mb-2 ml-2 text-xs text-gray-400">建议宽度:750</span>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</ElFormItem>
|
||||||
<el-card class="property-group" shadow="never">
|
<ElCard class="property-group" shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span>内容(小程序)</span>
|
<span>内容(小程序)</span>
|
||||||
<el-form-item prop="_local.previewMp" class="mb-0">
|
<ElFormItem prop="_local.previewMp" class="mb-0">
|
||||||
<el-checkbox
|
<ElCheckbox
|
||||||
v-model="formData._local.previewMp"
|
v-model="formData._local.previewMp"
|
||||||
@change="
|
@change="
|
||||||
formData._local.previewOther = !formData._local.previewMp
|
formData._local.previewOther = !formData._local.previewMp
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
预览
|
预览
|
||||||
</el-checkbox>
|
</ElCheckbox>
|
||||||
</el-form-item>
|
</ElFormItem>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<NavigationBarCellProperty v-model="formData.mpCells" is-mp />
|
<NavigationBarCellProperty v-model="formData.mpCells" is-mp />
|
||||||
</el-card>
|
</ElCard>
|
||||||
<el-card class="property-group" shadow="never">
|
<ElCard class="property-group" shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span>内容(非小程序)</span>
|
<span>内容(非小程序)</span>
|
||||||
<el-form-item prop="_local.previewOther" class="mb-0">
|
<ElFormItem prop="_local.previewOther" class="mb-0">
|
||||||
<el-checkbox
|
<ElCheckbox
|
||||||
v-model="formData._local.previewOther"
|
v-model="formData._local.previewOther"
|
||||||
@change="
|
@change="
|
||||||
formData._local.previewMp = !formData._local.previewOther
|
formData._local.previewMp = !formData._local.previewOther
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
预览
|
预览
|
||||||
</el-checkbox>
|
</ElCheckbox>
|
||||||
</el-form-item>
|
</ElFormItem>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<NavigationBarCellProperty v-model="formData.otherCells" :is-mp="false" />
|
<NavigationBarCellProperty v-model="formData.otherCells" :is-mp="false" />
|
||||||
</el-card>
|
</ElCard>
|
||||||
</el-form>
|
</ElForm>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user