提交 7e9f67bf 作者: test

feat: 实现覆盖所有模块使用场景下的图例组件

上级 1d87e0fb
<!-- 底部 Bar 组件 -->
<script setup lang="ts">
//
</script>
<template>
<view class="wrap bottom-bar">
<!-- -->
</view>
</template>
<style lang="scss" scoped>
//
</style>
<!-- 浮动过滤组件 -->
<script setup lang="ts">
//
</script>
<template>
<view class="wrap float-filter">
<!-- -->
</view>
</template>
<style lang="scss" scoped>
//
</style>
<!-- 左侧控制组件 -->
<script setup lang="ts">
//
</script>
<template>
<view class="wrap left-bar">
<!-- -->
</view>
</template>
<style lang="scss" scoped>
//
</style>
<!-- 图例组件 -->
<script setup lang="ts">
//
import { isArray } from 'lodash-es'
import { createReusableTemplate } from '@vueuse/core'
interface OptionItem {
// 颜色
color?: string
// 图标
icon?: string
// 标签
label?: string
// 多子项
items?: OptionItem[]
}
interface Option {
// 选项
items: OptionItem[] | OptionItem[][]
// label 样式
labelStyle?: Recordable
// 色块样式
blockStyle?: Recordable
}
const props = defineProps({
// 显示
show: {
type: Boolean,
default: true,
},
// 展开
expand: {
type: Boolean,
default: false,
},
// 标题
title: {
type: String,
default: '',
},
// JSON 数据
option: {
type: Object as PropType<Option>,
default: () => ({}),
},
})
const data = reactive({
// 显示
show: props.show,
// 展开
expand: props.expand,
// 标题
title: props.title,
// JSON 数据
option: props.option,
})
watch(
() => props.show,
(show) => (data.show = show),
)
watch(
() => props.title,
(title) => (data.title = title),
)
watch(
() => props.option,
(option) => (data.option = option),
{ deep: true },
)
const [DefineTemplate, ReuseTemplate] = createReusableTemplate<{ item: Recordable; sub?: boolean }>()
</script>
<template>
<view class="wrap legend" @click="data.expand = !data.expand">
<!-- 展开/收起 -->
<view class="expand-action" v-show="!data.expand">
<view class="text">图例</view>
<Icon icon="ic-round-keyboard-arrow-up" color="#1890ff" size="42" />
</view>
<!-- 内容 -->
<view class="expand-content" v-show="data.expand">
<!-- 标题 -->
<view v-if="data.title" class="title">{{ data.title }}</view>
<!-- JSON -->
<template v-if="isArray(data.option.items?.[0])">
<view v-for="(item, index) in data.option.items" :key="index" class="item-wrap">
<view v-for="(subItem, subIndex) in item" :key="subIndex" class="items">
<ReuseTemplate :item="subItem" />
</view>
</view>
</template>
<template v-else>
<view class="item-wrap">
<view v-for="(item, index) in data.option.items" :key="index" class="items">
<ReuseTemplate :item="item" />
</view>
</view>
</template>
<!-- 复用渲染组件 -->
<DefineTemplate v-slot="{ item, sub }">
<view class="item">
<!-- 图标 -->
<view v-if="item.icon" class="icon">
<CacheImage :src="item.icon" width="34" height="34" />
</view>
<!-- 色块 -->
<view
v-if="item.color"
class="color"
:style="{ backgroundColor: item.color, ...data.option.blockStyle }"
/>
<!-- 标签 -->
<view v-if="item.label" class="label" :style="!sub && { ...data.option.labelStyle }">
{{ item.label }}
</view>
<!-- 子项集合 -->
<view v-if="item.items" class="sub-items">
<view v-for="(subItem, index) in item.items" :key="index" class="item">
<ReuseTemplate :item="subItem" :sub="true" />
</view>
</view>
</view>
</DefineTemplate>
</view>
</view>
</template>
<style lang="scss" scoped>
//
.legend {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 12rpx 20rpx;
background-color: #fff;
border-radius: 10rpx;
box-shadow: 0 0 15rpx rgba(0, 0, 0, 0.3);
.expand-action {
display: flex;
justify-content: center;
align-items: center;
font-size: 26rpx;
color: #1890ff;
.text {
margin-right: 6rpx;
}
}
.expand-content {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-size: 24rpx;
color: #555;
.title {
margin-bottom: 15rpx;
font-weight: bold;
}
.option {
display: flex;
.item-wrap {
+ .item-wrap {
margin-left: 15rpx;
}
.item {
display: flex;
align-items: center;
justify-content: flex-start;
.icon {
display: flex;
justify-content: center;
align-items: center;
margin-right: 8rpx;
padding: 4rpx;
}
.color {
width: 32rpx;
height: 12rpx;
margin-right: 8rpx;
padding: 4rpx;
}
.label {
color: #777;
letter-spacing: 1px;
white-space: pre-wrap;
text-align: center;
}
}
.sub-items {
display: flex;
.item {
flex-direction: column;
margin: 2rpx 5rpx;
}
}
}
}
}
}
</style>
<!-- 前后切换组件 -->
<script setup lang="ts">
//
</script>
<template>
<view class="wrap switch-control">
<!-- -->
</view>
</template>
<style lang="scss" scoped>
//
</style>
<!-- 顶部 Bar 组件 -->
<script setup lang="ts">
//
</script>
<template>
<view class="wrap top-bar">
<!-- -->
</view>
</template>
<style lang="scss" scoped>
//
</style>
// 页面通用配置信息或一些抽象方法
// 单色块图例配置
// export const defaultLegendConfig = {
// expand: true,
// title: '单位: mm',
// option: {
// blockStyle: {
// border: '1px solid #ccc',
// },
// items: [
// {
// color: '#FFFFFF',
// label: '0-0.1',
// },
// {
// color: '#A3F48A',
// label: '0.1-9.0',
// },
// {
// color: '#35AB02',
// label: '10-24.9',
// },
// {
// color: '#61B9F9',
// label: '25-49.9',
// },
// {
// color: '#0403FF',
// label: '50-99.9',
// },
// {
// color: '#FA02FA',
// label: '100-249.9',
// },
// {
// color: '#810042',
// label: '>=250',
// },
// ],
// },
// }
// 多色块图例配置
export const defaultLegendConfig = {
expand: true,
title: '单位: mm',
option: {
blockStyle: {
border: '1px solid #ccc',
},
items: [
[
{
color: '#FFFFFF',
label: '0-0.1',
},
{
color: '#A3F48A',
label: '0.1-9.0',
},
{
color: '#35AB02',
label: '10-24.9',
},
{
color: '#61B9F9',
label: '25-49.9',
},
{
color: '#0403FF',
label: '50-99.9',
},
{
color: '#FA02FA',
label: '100-249.9',
},
{
color: '#810042',
label: '>=250',
},
],
[
{
color: '#FFFFFF',
label: '0-0.1',
},
{
color: '#A3F48A',
label: '0.1-9.0',
},
{
color: '#35AB02',
label: '10-24.9',
},
{
color: '#61B9F9',
label: '25-49.9',
},
{
color: '#0403FF',
label: '50-99.9',
},
{
color: '#FA02FA',
label: '100-249.9',
},
{
color: '#810042',
label: '>=250',
},
],
],
},
}
// 单边图标图例
// export const defaultLegendConfig = {
// expand: true,
// title: '',
// option: {
// items: [
// {
// icon: '/static/icons/legend/ice-snow/snow.cover.png',
// label: '积雪',
// },
// {
// icon: '/static/icons/legend/ice-snow/wire.icing.png',
// label: '电线积冰',
// },
// {
// icon: '/static/icons/legend/ice-snow/glaze.png',
// label: '雨淞',
// },
// {
// icon: '/static/icons/legend/ice-snow/sleet.png',
// label: '雨夹雪',
// },
// {
// icon: '/static/icons/legend/ice-snow/snow.png',
// label: '雪',
// },
// ],
// },
// }
// 单边多图标图例
// export const defaultLegendConfig = {
// expand: true,
// title: '',
// option: {
// labelStyle: {
// width: '85rpx',
// },
// items: [
// {
// label: '闪电',
// items: [
// {
// icon: '/static/icons/legend/strong-convection/lightning.png',
// },
// ],
// },
// {
// label: '冰雹\n(mm)',
// items: [
// {
// icon: '/static/icons/legend/strong-convection/hail.0-5.png',
// label: '0-5',
// },
// {
// icon: '/static/icons/legend/strong-convection/hail.5-10.png',
// label: '5-10',
// },
// {
// icon: '/static/icons/legend/strong-convection/hail.10-20.png',
// label: '10-20',
// },
// {
// icon: '/static/icons/legend/strong-convection/hail.+20.png',
// label: '>=20',
// },
// ],
// },
// {
// label: '大风\n(m/s)',
// items: [
// {
// icon: '/static/icons/legend/strong-convection/wind.17-25.png',
// label: '17-25',
// },
// {
// icon: '/static/icons/legend/strong-convection/wind.25-30.png',
// label: '25-30',
// },
// {
// icon: '/static/icons/legend/strong-convection/wind.+30.png',
// label: '>=30',
// },
// ],
// },
// {
// label: '强降水\n(mm)',
// items: [
// {
// icon: '/static/icons/legend/strong-convection/rain.20-30.png',
// label: '20-30',
// },
// {
// icon: '/static/icons/legend/strong-convection/rain.30-50.png',
// label: '30-50',
// },
// {
// icon: '/static/icons/legend/strong-convection/rain.50-80.png',
// label: '50-80',
// },
// {
// icon: '/static/icons/legend/strong-convection/rain.+80.png',
// label: '>=80',
// },
// ],
// },
// ],
// },
// }
<!-- 页面组件 -->
<script setup lang="ts">
// 组件
import Legend from './components/Legend.vue'
import { defaultLegendConfig } from './config'
import { useShare } from '@/hooks/page/useShare'
useShare()
const { expand, title, option } = defaultLegendConfig
</script>
<template>
......@@ -14,10 +20,22 @@
<!-- 交互组件集 -->
<view class="interaction">
<!-- -->
<!-- Legend 组件 -->
<Legend :expand="expand" :title="title" :option="option" />
</view>
</view>
</template>
<style lang="scss" scoped>
//
.interaction {
:deep(.legend) {
position: absolute;
left: 30rpx;
bottom: 30rpx;
z-index: 99;
}
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论