flat: 暂存
This commit is contained in:
360
components/selectFilter/selectFilter.vue
Normal file
360
components/selectFilter/selectFilter.vue
Normal file
@@ -0,0 +1,360 @@
|
||||
<template>
|
||||
<uni-popup
|
||||
ref="popup"
|
||||
type="bottom"
|
||||
borderRadius="10px 10px 0 0"
|
||||
background-color="#FFFFFF"
|
||||
@maskClick="maskClickFn"
|
||||
:mask-click="maskClick"
|
||||
>
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<view class="btn-cancel" @click="cancel">取消</view>
|
||||
<view class="title">
|
||||
<text>{{ title }}</text>
|
||||
<text style="color: #256bfa">·{{ count }}</text>
|
||||
</view>
|
||||
<view class="btn-confirm" @click="confirm"> </view>
|
||||
</view>
|
||||
<view class="popup-list">
|
||||
<view class="content-wrapper">
|
||||
<!-- 左侧筛选类别 -->
|
||||
<scroll-view class="filter-nav" scroll-y>
|
||||
<view
|
||||
v-for="(item, index) in filterOptions"
|
||||
:key="index"
|
||||
class="nav-item button-click"
|
||||
:class="{ active: activeTab === item.key }"
|
||||
@click="scrollTo(item.key)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 右侧筛选内容 -->
|
||||
<scroll-view class="filter-content" :scroll-into-view="activeTab" scroll-y>
|
||||
<template v-for="(item, index) in filterOptions" :key="index">
|
||||
<view class="content-item">
|
||||
<view class="item-title" :id="item.key">{{ item.label }}</view>
|
||||
<checkbox-group class="check-content" @change="(e) => handleSelect(item.key, e)">
|
||||
<label
|
||||
v-for="option in item.options"
|
||||
:key="option.value"
|
||||
class="checkbox-item button-click"
|
||||
:class="{
|
||||
checkedstyle: selectedValues[item.key]?.includes(String(option.value)),
|
||||
}"
|
||||
>
|
||||
<checkbox
|
||||
style="display: none"
|
||||
:value="String(option.value)"
|
||||
:checked="selectedValues[item.key]?.includes(String(option.value))"
|
||||
/>
|
||||
<text class="option-label">{{ option.label }}</text>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
</view>
|
||||
</template>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="popup-bottom">
|
||||
<view class="btn-cancel btn-feel" @click="cleanup">清除</view>
|
||||
<view class="btn-confirm btn-feel" @click="confirm">确认</view>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, nextTick, onBeforeMount } from 'vue';
|
||||
import useDictStore from '@/stores/useDictStore';
|
||||
const { getTransformChildren } = useDictStore();
|
||||
|
||||
const area = ref(true);
|
||||
const maskClick = ref(false);
|
||||
const maskClickFn = ref(null);
|
||||
|
||||
const title = ref('标题');
|
||||
const confirmCallback = ref(null);
|
||||
const cancelCallback = ref(null);
|
||||
const changeCallback = ref(null);
|
||||
const popup = ref(null);
|
||||
const selectedValues = reactive({});
|
||||
const count = ref(0);
|
||||
// 当前激活的筛选类别
|
||||
const activeTab = ref('');
|
||||
const filterOptions = ref([]);
|
||||
|
||||
const open = (newConfig = {}) => {
|
||||
const { title: configTitle, success, cancel, change, data, maskClick: configMaskClick = false } = newConfig;
|
||||
|
||||
// reset();
|
||||
|
||||
if (configTitle) title.value = configTitle;
|
||||
if (typeof success === 'function') confirmCallback.value = success;
|
||||
if (typeof cancel === 'function') cancelCallback.value = cancel;
|
||||
if (typeof change === 'function') changeCallback.value = change;
|
||||
|
||||
if (configMaskClick) {
|
||||
maskClick.value = configMaskClick;
|
||||
maskClickFn.value = cancel;
|
||||
}
|
||||
|
||||
getoptions();
|
||||
|
||||
nextTick(() => {
|
||||
popup.value?.open();
|
||||
});
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
popup.value?.close();
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
handleClick(cancelCallback.value);
|
||||
};
|
||||
|
||||
const confirm = () => {
|
||||
handleClick(confirmCallback.value);
|
||||
};
|
||||
|
||||
const handleClick = async (callback) => {
|
||||
if (typeof callback !== 'function') {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await callback(selectedValues);
|
||||
if (result !== false) close();
|
||||
} catch (error) {
|
||||
console.error('confirmCallback 执行出错:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理选项选择
|
||||
const handleSelect = (key, e) => {
|
||||
selectedValues[key] = e.detail.value.map(String);
|
||||
let va = 0;
|
||||
for (const [key, value] of Object.entries(selectedValues)) {
|
||||
va += value.length;
|
||||
}
|
||||
count.value = va;
|
||||
};
|
||||
|
||||
const cleanup = () => {
|
||||
Object.keys(selectedValues).forEach((key) => {
|
||||
delete selectedValues[key];
|
||||
});
|
||||
};
|
||||
|
||||
const scrollTo = (key) => {
|
||||
activeTab.value = key;
|
||||
};
|
||||
|
||||
function getoptions() {
|
||||
const arr = [
|
||||
getTransformChildren('education', '学历要求'),
|
||||
getTransformChildren('experience', '工作经验'),
|
||||
getTransformChildren('scale', '公司规模'),
|
||||
];
|
||||
if (area.value) {
|
||||
arr.push(getTransformChildren('area', '区域'));
|
||||
}
|
||||
filterOptions.value = arr;
|
||||
activeTab.value = 'education';
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
maskClick.value = false;
|
||||
confirmCallback.value = null;
|
||||
cancelCallback.value = null;
|
||||
changeCallback.value = null;
|
||||
Object.keys(selectedValues).forEach((key) => delete selectedValues[key]);
|
||||
};
|
||||
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
open,
|
||||
close,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.popup-content {
|
||||
color: #000000;
|
||||
height: 80vh;
|
||||
}
|
||||
.popup-bottom {
|
||||
padding: 40rpx 28rpx 20rpx 28rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
.btn-cancel {
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #666d7f;
|
||||
line-height: 90rpx;
|
||||
width: 33%;
|
||||
min-width: 222rpx;
|
||||
height: 90rpx;
|
||||
background: #f5f5f5;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
text-align: center;
|
||||
}
|
||||
.btn-confirm {
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
width: 67%;
|
||||
height: 90rpx;
|
||||
margin-left: 28rpx;
|
||||
line-height: 90rpx;
|
||||
background: #256bfa;
|
||||
min-width: 444rpx;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
}
|
||||
}
|
||||
.popup-list {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
height: calc(80vh - 100rpx - 150rpx);
|
||||
overflow: hidden;
|
||||
.picker-view {
|
||||
width: 100%;
|
||||
height: 500rpx;
|
||||
margin-top: 20rpx;
|
||||
.uni-picker-view-mask {
|
||||
background: rgba(0, 0, 0, 0);
|
||||
}
|
||||
.item {
|
||||
line-height: 84rpx;
|
||||
height: 84rpx;
|
||||
text-align: center;
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #cccccc;
|
||||
}
|
||||
.item-active {
|
||||
color: #333333;
|
||||
}
|
||||
.uni-picker-view-indicator:after {
|
||||
border-color: #e3e3e3;
|
||||
}
|
||||
.uni-picker-view-indicator:before {
|
||||
border-color: #e3e3e3;
|
||||
}
|
||||
}
|
||||
// .list {
|
||||
// .row {
|
||||
// font-weight: 400;
|
||||
// font-size: 32rpx;
|
||||
// color: #333333;
|
||||
// line-height: 84rpx;
|
||||
// text-align: center;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 40rpx 40rpx 10rpx 40rpx;
|
||||
.title {
|
||||
font-weight: 500;
|
||||
font-size: 36rpx;
|
||||
color: #333333;
|
||||
text-align: center;
|
||||
}
|
||||
.btn-cancel {
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #666d7f;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
.btn-confirm {
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
color: #256bfa;
|
||||
}
|
||||
}
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.filter-nav {
|
||||
width: 200rpx;
|
||||
background-color: #ffffff;
|
||||
|
||||
.nav-item {
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
text-align: center;
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #666d7f;
|
||||
&.active {
|
||||
font-weight: 500;
|
||||
font-size: 28rpx;
|
||||
color: #256bfa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter-content {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
.content-item {
|
||||
margin-top: 40rpx;
|
||||
.item-title {
|
||||
font-weight: 400;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
}
|
||||
.content-item:first-child {
|
||||
margin-top: 0rpx;
|
||||
}
|
||||
|
||||
.check-content {
|
||||
display: grid;
|
||||
grid-template-columns: 50% 50%;
|
||||
place-items: center;
|
||||
|
||||
.checkbox-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 20rpx 20rpx 0 0;
|
||||
text-align: center;
|
||||
background-color: #d9d9d9;
|
||||
width: 228rpx;
|
||||
height: 80rpx;
|
||||
background: #e8eaee;
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
|
||||
.option-label {
|
||||
font-size: 28rpx;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.checkedstyle {
|
||||
width: 224rpx;
|
||||
height: 76rpx;
|
||||
background: rgba(37, 107, 250, 0.06);
|
||||
border-radius: 12rpx 12rpx 12rpx 12rpx;
|
||||
border: 2rpx solid #256bfa;
|
||||
color: #256bfa;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user