Files
jobslink-user-clent/components/vertical-menu/vertical-menu.vue
2024-02-17 18:22:11 +08:00

474 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="u-wrap">
<view class="u-menu-wrap">
<scroll-view scroll-y scroll-with-animation class="u-tab-view menu-scroll-view" :scroll-top="scrollTop"
:scroll-into-view="itemId">
<view v-for="(item, index) in tabbar" :key="index" class="u-tab-item"
:class="[current == index ? 'u-tab-item-active' : '']" @tap.stop="swichMenu(index)">
<text class="u-line-1">{{ item.name }}</text>
</view>
</scroll-view>
<scroll-view :scroll-top="scrollRightTop" scroll-y scroll-with-animation class="right-box"
@scroll="rightScroll">
<view class="page-view">
<view class="class-item" :id="'item' + index" v-for="(item, index) in tabbar" :key="index">
<view class="item-title">
<text>{{ item.name }}</text>
</view>
<view class="item-container">
<view @click="clickFunc({ 'type': 'address' })" v-if="item.name === `省市区县`"
class="thumb-box thumb-box1">
<u-cell-group>
<u-cell icon="map" :title="areaModal.address" :isLink="true"
arrow-direction="down"></u-cell>
</u-cell-group>
</view>
<view @click="clickFunc({ 'type': 'industry' })" v-else-if="item.name === `行业`"
class="thumb-box thumb-box1">
<u-cell-group>
<u-cell icon="calendar" :title="industryModal.industry" :isLink="true"
arrow-direction="down"></u-cell>
</u-cell-group>
</view>
<view @click="clickFunc({
'type': 'normal', 'bigObj': item, 'smallObj': item1
})" v-else
:class="submitData[item.name] === item1.id ? `selected-box thumb-box` : `thumb-box`"
v-for="(item1, index1) in item.data" :key="index1">
<view class="item-menu-name">{{ item1.name }}</view>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
<view class="buttonWrapper">
<view class="cancelButton" @click="closePopUp">取消</view>
<view class="sureButton" @click="subMitPopUp({submitData,areaModal,industryModal})">确定</view>
</view>
<!-- 省市 -->
<data-picker :show="areaModal.addressShow" @confirm='confirmAddress' @cancel='areaModal.addressShow = false'
@close='areaModal.addressShow = false' :defaultNames="areaModal.defaultNames" :indexs="areaModal.indexs"
:defaultIds="areaModal.defaultIds" :showToolbar="false" :showBottombar="true"
:labelName="areaModal.labelName"></data-picker>
<!-- 行业 -->
<u-picker @confirm="pickerIndustryFunc" keyName="name" @cancel="industryModal.industryShow = false"
:show="industryModal.industryShow" :columns="industryModal.industryList"></u-picker>
</view>
</template>
<script>
import classifyData from './classifyData.js';
import { getTrade } from '@/api/resume.js'
export default {
props: {
closePopUp: {
type: Function,
required: true
},
subMitPopUp: {
type: Function,
required: true
},
},
components: {
// vTabs,
// companyList, verticalMenu
},
data() {
return {
scrollTop: 0,
oldScrollTop: 0,
current: 0,
menuHeight: 0,
menuItemHeight: 0,
itemId: "0",
tabbar: classifyData,
menuItemPos: 0,
arr: [],
scrollRightTop: 0,
timer: null,
areaModal: {
address: '',
addressShow: false,
title: 'Hello',
// indexs: [0, 0, 8],
// defaultIds: [1, 110000, 110106],
defaultNames: ['北京市', '北京市', '东城区'],
labelName: "areaName"
},
industryModal: {
industry: "",
industryList: [[]],
industryShow: false,
},
submitData: {},
}
},
created: function () {
this.getData()
this.getMenuItemTop()
},
methods: {
getData: function () {
getTrade().then(res => {
console.log(res.data.data);
const newData = this.tabbar;
newData.map(item => {
if (item.name === "行业") {
item.data = res.data.data
}
})
this.tabbar = newData;
this.industryModal.industry = res.data.data[0]?.name
this.industryModal.industryList = [res.data.data]
})
},
// 点击左边的栏目切换
async swichMenu(index) {
if (this.arr.length == 0) {
await this.getMenuItemTop();
}
if (index == this.current) return;
this.scrollRightTop = this.oldScrollTop;
this.$nextTick(() => {
this.scrollRightTop = this.arr[index];
// scrollRightTop = newarrTop
this.current = index;
this.leftMenuStatus(index);
})
},
// 获取一个目标元素的高度
getElRect(elClass, dataVal) {
new Promise((resolve, reject) => {
// const query = uni.createSelectorQuery().in(this);
const query = uni.createSelectorQuery()
query.select('.' + elClass).fields({
size: true
}, res => {
// 如果节点尚未生成res值为null循环调用执行
if (!res) {
setTimeout(() => {
this.getElRect(elClass);
}, 10);
return;
}
if (dataVal == 'menuHeight') {
this.menuHeight = res.height;
}
if (dataVal == 'menuItemHeight') {
this.menuItemHeight = res.height;
}
resolve();
}).exec();
})
},
// 观测元素相交状态
async observer() {
this.tabbar.map((val, index) => {
let observer = uni.createIntersectionObserver(this);
// 检测右边scroll-view的id为itemxx的元素与right-box的相交状态
// 如果跟.right-box底部相交就动态设置左边栏目的活动状态
observer.relativeTo('.right-box', {
top: 0
}).observe('#item' + index, res => {
if (res.intersectionRatio > 0) {
let id = res.id.substring(4);
this.leftMenuStatus(id);
}
})
})
},
// 设置左边菜单的滚动状态
async leftMenuStatus(index) {
this.current = index;
// 如果为0意味着尚未初始化
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
await this.getElRect('menu-scroll-view', 'menuHeight');
await this.getElRect('u-tab-item', 'menuItemHeight');
}
// console.log(index, this.arr[index]);
// 将菜单活动item垂直居中
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
},
// 右边菜单滚动
async rightScroll(e) {
this.oldScrollTop = e.detail.scrollTop;
if (this.arr.length == 0) {
await this.getMenuItemTop();
}
if (this.timer) return;
if (!this.menuHeight) {
await this.getElRect('menu-scroll-view', 'menuHeight');
}
setTimeout(() => { // 节流
this.timer = null;
// scrollHeight为右边菜单垂直中点位置
let scrollHeight = e.detail.scrollTop + this.menuHeight / 2;
for (let i = 0; i < this.arr.length; i++) {
let height1 = this.arr[i];
let height2 = this.arr[i + 1];
// 如果不存在height2意味着数据循环已经到了最后一个设置左边菜单为最后一项即可
if (!height2 || scrollHeight >= height1 && scrollHeight < height2) {
this.leftMenuStatus(i - 1);
return;
}
}
}, 50)
},
// 获取右边菜单每个item到顶部的距离
getMenuItemTop() {
new Promise(resolve => {
let selectorQuery = uni.createSelectorQuery();
console.log(selectorQuery);
selectorQuery.selectAll('.class-item').boundingClientRect((rects) => {
console.log(rects);
// 如果节点尚未生成rects值为[](因为用selectAll所以返回的是数组),循环调用执行
if (!rects.length) {
setTimeout(() => {
this.getMenuItemTop();
}, 10);
return;
}
rects.forEach((rect) => {
// 这里减去rects[0].top是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
this.arr.push(rect.top - rects[0].top);
resolve();
})
}).exec()
})
},
clickFunc({ type, bigObj, smallObj }) {
switch (type) {
case "industry":
this.industryModal.industryShow = true;
break;
case "address":
this.areaModal.addressShow = true
break;
default:
this.$set(this.submitData, bigObj.name, smallObj.id);
console.log(this.submitData);
break;
}
},
changeHandler(e) {
const {
columnIndex,
value,
values, // values为当前变化列的数组内容
index,
// 微信小程序无法将picker实例传出来只能通过ref操作
picker = this.$refs.uPicker
} = e
// 当第一列值发生变化时,变化第二列(后一列)对应的选项
if (columnIndex === 0) {
// picker为选择器this实例变化第二列对应的选项
picker.setColumnValues(1, this.columnData[index])
}
},
confirmAddress(val) {
console.log(val);
var valArr = val.value;
this.areaModal.address = [...new Set(val.value)].join(' / ')
console.log(this.areaModal.address);
this.areaModal.addressShow = false
},
pickerIndustryFunc(val) {
console.log(val);
this.industryModal.industry = val.value[0].name;
this.industryModal.industryShow = false
}
}
}
</script>
<style lang="scss" scoped>
.u-wrap {
height: calc(100vh);
/* #ifdef H5 */
height: calc(100vh - var(--window-top));
/* #endif */
display: flex;
flex-direction: column;
}
.u-search-box {
padding: 18rpx 30rpx;
}
.u-menu-wrap {
flex: 100;
display: flex;
overflow: hidden;
}
.u-search-inner {
background-color: rgb(234, 234, 234);
border-radius: 100rpx;
display: flex;
align-items: center;
padding: 10rpx 16rpx;
}
.u-search-text {
font-size: 26rpx;
color: #ccc;
margin-left: 10rpx;
}
.u-tab-view {
width: 200rpx;
height: 100%;
}
.u-tab-item {
height: 110rpx;
background: #f6f6f6;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
font-size: 26rpx;
color: #444;
font-weight: 400;
line-height: 1;
}
.u-tab-item-active {
position: relative;
color: #000;
font-size: 30rpx;
font-weight: 600;
background: #fff;
}
.u-tab-item-active::before {
content: "";
position: absolute;
border-left: 4px solid skyblue;
height: 32rpx;
left: 0;
top: 39rpx;
}
.u-tab-view {
height: 100%;
}
.right-box {
background-color: rgb(250, 250, 250);
}
.page-view {
padding: 16rpx;
}
.class-item {
margin-bottom: 30rpx;
background-color: #fff;
padding: 16rpx;
border-radius: 8rpx;
}
.class-item:last-child {
// min-height: 100vh;
}
.item-title {
font-size: 28rpx;
font-weight: bold;
}
.item-menu-name {
font-weight: normal;
font-size: 26rpx;
}
.item-container {
display: flex;
flex-wrap: wrap;
}
.thumb-box {
width: 43%;
line-height: 80rpx;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
flex-direction: column;
margin-top: 25rpx;
margin-left: 20rpx;
background-color: #f3f4f8;
border: 1px solid #f3f4f8;
color: #666666;
}
.thumb-box1 {
width: 90%;
}
.selected-box {
background-color: #e3eafe;
border: 1px solid #92adfb;
color: #92adfb !important;
}
.item-menu-image {
width: 120rpx;
height: 120rpx;
}
.buttonWrapper {
// position: absolute;
// bottom: 10px;
display: flex;
justify-content: space-around;
margin-bottom: -10px;
margin-top: 10px;
}
.cancelButton {
padding: 15rpx 30rpx;
background-color: #f3f4f8;
border-radius: 5px;
color: #9b9b9b;
}
.sureButton {
padding: 15rpx 150rpx;
background-color: #4171f9;
color: #fff;
border-radius: 5px;
}
</style>