业务需求:面包屑超出宽度,左侧出现省略号。
实现效果
实现原理
- 先调整面包屑样式,使其弹性布局不换行
- 给面包屑外面盒子一个ref,面包屑同级有个隐藏的span,内容是…省略号
- 通过MutationObserver监听这个盒子的内容改变
- 当内容超出盒子宽度之后,打开省略号,并修改弹性布局主轴从行尾开始
核心代码
MutationObserver对象监听dom元素内容
MutationObserver
代码
import { useEffect, useRef, useState } from "react";
import { Breadcrumb } from "antd";
import "antd/lib/breadcrumb/style/css";
import "./index.css";
function Index(props: any) {
const [breadcrumb, setBreadcrumb] = useState([
{
title: "Home",
href: "1",
},
{
title: "Page1",
href: "1",
},
{
title: "Page2",
href: "1",
},
]);
const [showEllipsis, setShowEllipsis] = useState(false);
const breadCrumbsRef = useRef<any>();
// 观察面包屑dom实现省略号
useEffect(() => {
const targetNode = breadCrumbsRef?.current;
const config = { attributes: false, childList: true, subtree: true };
const callback = function (mutationsList: any, observer: any) {
for (let mutation of mutationsList) {
if (mutation.type === "childList") {
let childWidth = 0;
for (const childNodes of mutation.target.childNodes) {
childWidth += childNodes.clientWidth;
}
if (mutation.target.clientWidth < childWidth) {
mutation.target.style.justifyContent = "flex-end";
setShowEllipsis(true);
} else if (mutation.target.clientWidth >= childWidth) {
mutation.target.style.justifyContent = "flex-start";
setShowEllipsis(false);
}
}
}
};
// 创建一个观察器实例并传入回调函数
const observer = new MutationObserver(callback);
// 以上述配置开始观察目标节点
observer.observe(targetNode, config);
return () => {
// 停止观察
observer.disconnect();
};
}, []);
const onClickIncrease = () => {
breadcrumb.push({
title: `Page${
parseInt(breadcrumb[breadcrumb.length - 1].title.slice(4)) + 1
}`,
href: "",
});
setBreadcrumb([...breadcrumb]);
};
const onClickDecrease = () => {
breadcrumb.pop();
setBreadcrumb([...breadcrumb]);
};
return (
<div className="breadcrumb-wrapper" ref={breadCrumbsRef}>
<span
className={`breadcrumb-ellipsis ${
showEllipsis ? "breadcrumb-ellipsis-show" : ""
}`}
>
....
</span>
<Breadcrumb>
{breadcrumb.map((item, index) => {
return <Breadcrumb.Item key={index}>{item.title}</Breadcrumb.Item>;
})}
</Breadcrumb>
<button onClick={onClickIncrease}>+++</button>
<button onClick={onClickDecrease}>---</button>
</div>
);
}
export default Index;
.breadcrumb-wrapper {
position: relative;
margin: 50px;
width: 300px;
height: 200px;
border: 1px #ccc solid;
}
.breadcrumb-ellipsis {
position: absolute;
left: 0;
top: 0;
background: #fff;
visibility: hidden;
font-size: 12px;
}
.breadcrumb-ellipsis-show{
visibility: initial;
}
.ant-breadcrumb > ol {
display: flex;
flex-wrap: nowrap;
overflow: hidden;
}
其他拓展
相对应的,既然有了省略号了,业务需求想直接跳到首页,总不能一级一级往回点吧。与之相对应UI的设计思路是,鼠标悬浮,有个tooltip,里面存放全部的面包屑路径。这种情况就用andt的tooltip包起来,技术上亲测是可行的。