需求如下:
移动端顶部菜单Tab个数要适配屏幕,且不能有滚动操作,将剩余的选项展示在更多下拉菜单当中。
项目使用的是react+antd-mobile,组件中也没找到有对应的组件;自己封装了菜单逻辑,实现了效果
思路:
- 由于项目是没有多语言的,一个12px的汉字占据位置的宽度大概是18px;
- 需要知道菜单tabs的总宽度,然后匹配每个tab有多少个字,再加上间距,如果宽度超过tabs的总宽度,就展示更多菜单,然后将剩余的tabs以列表形式展示在下拉菜单当中
- tabs数据当中,给个当前宽度能展示最大个数的标识,我用isMax表示;
有了以上思路,我们可以利用innerWidth去计算,实现以上逻辑。代码如下:
js部分:首先我们处理tabs数据,通过innerWidth计算出可以展示tab的最大个数,给最大个数的那条数据添加一个isMax标识:
const fetchDepthData = (year: any) => {
getInfoWealthByYear({ year }).then((res: any) => {
if (res?.success) {
const DATA = res.data || [];
DATA.forEach((e: any) => {
if (e.equalCheck === 1) {
e.names = e.names + '等';
}
});
const _data = DATA.map((e: any, index: any) => {
return {
label: e.researchArea,
value: index,
width: e.researchArea.length * 18,
checked: false,
};
}).filter(
(ele: any, index: any, self: any) =>
self.findIndex((e: any) => e.label === ele.label) === index,
);
let currentWidth = 0;
let _max = window.innerWidth - 280;
for (let i = 0; i < _data.length; i++) {
currentWidth += _data[i].label.length * 18 + 12;
if (currentWidth >= _max) {
_data[i].isMax = true;
break;
}
}
if (DATA.length) {
_data[0].checked = true;
setResearchAreas(_data);
setWealthData(
DATA.filter((e: any) => e.researchArea === _data[0].label),
);
setdepthData(DATA);
}
} else {
setResearchAreas([]);
setWealthData([]);
setdepthData([]);
}
});
};
html部分:在渲染时,要查找isMax的数据,然后将剩余的数据展示在下拉菜单当中;
<div
style={{
display: 'flex',
flex: '1',
justifyContent: 'space-between',
height: '100%',
alignItems: 'center',
padding: '0',
}}
>
{researchAreas
.slice(0, researchAreas.findIndex((t: any) => t.isMax) + 1)
.map((e: any) => (
<div
key={e}
className={styles.subMenu}
style={{
width: e.width + 'px',
padding: '0 6px',
color: e.checked ? '#1677ff' : '#333',
}}
onClick={() => {
areaClick(e);
}}
>
{e.label}
</div>
))}
<div
style={{
display:
researchAreas.length >
researchAreas.findIndex((t: any) => t.isMax) + 1
? 'block'
: 'none',
}}
>
<Dropdown ref={dropDownRefDep}>
<Dropdown.Item key="type" title="更多">
<div className={styles.yearDropDown}>
{researchAreas
.slice(researchAreas.findIndex((t: any) => t.isMax) + 1)
.map((ele: any) =>
ele.label ? (
<div
className={styles.depDropdown}
key={ele.value}
onClick={() => {
researchAreas.forEach((t: any) => {
t.checked = t.label === ele.label;
});
setWealthData(
depthData.filter(
(e: any) => e.researchArea === ele.label,
),
);
setResearchAreas([...researchAreas]);
setTimeout(() => {
dropDownRefDep.current?.close();
}, 200);
}}
style={{
height: '30px',
lineHeight: '30px',
margin: '0 12px',
}}
>
<span
style={ele.checked ? { color: '#1677ff' } : {}}
>
{ele.label}
</span>
</div>
) : (
''
),
)}
</div>
</Dropdown.Item>
</Dropdown>
</div>
</div>
效果如下:
竖屏:
横屏: