提交 9577149b 作者: test

feat: 新增 AffixFilterWidget 小部件

上级 cd13ae66
......@@ -14,5 +14,6 @@ export { default as AffixFilterWidget } from './src/AffixFilter.vue'
* 3. 水情监测
* 4. 卫星云图
* 5. 形势场
* 6. 雷达拼图
* ...
*/
<!-- 吸附过滤器组件 -->
<script setup lang="ts">
//
import type { Option } from './types'
const props = defineProps({
// 是否显示
show: {
type: Boolean,
default: true,
},
// 布局
layout: {
type: String,
default: 'horizontal',
},
// 风格
style: {
type: String,
default: 'button',
},
// 距离顶部的距离
top: {
type: String,
default: '125rpx',
},
// 距离左侧的距离
left: {
type: String,
default: '30rpx',
},
// 选项
options: {
type: Array as PropType<Option[]>,
default: () => [],
},
})
const emits = defineEmits(['register'])
const positionTop = computed(() => data.top)
const positionLeft = computed(() => data.left)
const data = reactive({
show: props.show,
layout: props.layout,
style: props.style,
top: props.top,
left: props.left,
options: props.options,
})
function toggleShow(show?: boolean) {
data.show = show ?? !data.show
}
function setProps(value: Partial<typeof props>) {
Object.assign(data, value)
}
const zIndex = computed(() => (model.show ? 200 : 110))
const model = reactive({
show: false,
activeOption: null as Option | null,
})
function optionClick(option: Option) {
console.log(option)
model.activeOption = option
model.show = true
}
function getItemLabel(option: Option) {
return option.items.find((item) => item.checked)?.text ?? option.placeholder
}
function optionChange(e: { text: string; value: string }) {
const currentOptionChecked = model.activeOption?.items.find((item) => item.checked)
data.options = data.options.map((option) => {
if (option.key === model.activeOption?.key) {
option.items = option.items.map((item) => {
item.checked = item.value === e.value
return item
})
}
return option
})
// 判断是否真的发生了变化
if (
currentOptionChecked?.value !==
data.options.find((option) => option.key === model.activeOption?.key)?.items.find((item) => item.checked)
?.value
) {
model.activeOption?.onChange?.(
{
key: model.activeOption.key,
value: toRaw(model.activeOption.items.find((item) => item.checked)),
},
data.options.map((option) => {
return {
key: option.key,
value: toRaw(option.items.find((item) => item.checked)),
}
}),
)
}
closePicker()
}
function closePicker() {
model.activeOption = null
model.show = false
}
emits('register', {
setProps,
toggleShow,
})
</script>
<template>
<view class="wrap affix-filter">
<view class="wrap affix-filter" :class="[data.layout, data.style]">
<!-- -->
<view class="filter-item flex-center" v-for="option in data.options" :key="option.key">
<view class="fui-filter__item flex-center" @tap="optionClick(option)">
<text>{{ getItemLabel(option) }}</text>
<view class="ml-10rpx icon" :class="{ open: model.activeOption?.key === option.key }">
<fui-icon name="turningdown" :size="32" color="#999" />
</view>
</view>
</view>
<!-- 复用选择器 -->
<fui-picker
linkage
:options="model.activeOption?.items"
:show="model.show"
@change="optionChange"
@cancel="closePicker"
/>
</view>
</template>
<style lang="scss" scoped>
//
@import '../../common.scss';
.affix-filter {
display: flex;
box-sizing: border-box;
position: absolute;
top: v-bind(positionTop);
left: v-bind(positionLeft);
z-index: v-bind(zIndex);
&.vertical {
flex-direction: column;
.filter-item + .filter-item {
margin-top: 30rpx;
}
}
&.horizontal {
.filter-item + .filter-item {
margin-left: 30rpx;
}
}
&.bar {
width: 100%;
background-color: white;
left: 0;
padding: 10rpx 30rpx;
.filter-item {
flex: 1;
box-shadow: none !important;
}
}
.filter-item {
background-color: white;
padding: 15rpx 30rpx;
font-size: 28rpx;
color: #333;
border-radius: 10rpx;
box-shadow: 0 0 15rpx rgba(0, 0, 0, 0.1);
.icon {
@include animate();
transform: rotate(0deg);
&.open {
transform: rotate(180deg);
}
}
}
}
</style>
......@@ -2,7 +2,7 @@ import { registerWidgetFactory, unpackWidgetInstance } from '../../utils'
import type { AffixFilterInstance, AffixFilterProps, OptionItem } from './types'
// 组件名称
export const name = 'LegendWidget'
export const name = 'AffixFilterWidget'
/**
* 吸附过滤器组件
......
import type { BasicWidgetInstance, BasicWidgetProps } from '../../utils'
export interface CheckedOption {
key: string
value: OptionItem
}
export interface OptionItem {
text: string
value: string
checked?: boolean
disabled?: boolean
[key: string]: any
}
export interface Option {
// 标识
key: string
// 提示信息
placeholder?: string
// 选项
items: OptionItem[]
// 选项改变时的回调
onChange?: (checkedOption: CheckedOption, checkedOptions: CheckedOption[]) => void
}
export interface AffixFilterProps extends BasicWidgetProps {
// 布局方式,水平或垂直
layout: 'horizontal' | 'vertical'
// 选项,仅支持 Select
option: Option
/**
* 布局方式,水平或垂直
* @default horizontal
*/
layout?: 'horizontal' | 'vertical'
/**
* 风格,按钮或者条形
* @default button
*/
style?: 'button' | 'bar'
/**
* 距离顶部的距离 rpx
* @default 130rpx
*/
top?: string
/**
* 距离左侧的距离 rpx
* @default 30rpx
*/
left?: string
/**
* 过滤选项集合,仅支持 Select
*/
options: Option[]
}
export interface AffixFilterInstance extends BasicWidgetInstance<AffixFilterProps> {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论