我有一个组件,目前会呈现出如下所示的内容:
Corvid / 游戏 / 魔兽世界 / 资产 / 角色模型 / 联盟 / 暗夜精灵 / 玛法里奥
我总是希望前两个项目和最后两个项目可见,但是,如果可能的话,我希望中间的所有内容都截断为...
。也就是说,如果上面的字符串要溢出包含的div,它应该具有以下结果
Corvid / 游戏 / ... / 暗夜精灵 / 玛法里奥
我尝试过如下结构:
<div className={styles.container}>
<div className={styles.first}>
{/** Contains first two items */}
</div>
<div className={styles.truncate}>
{/** N arbitrary path items */}
</div>
<div className={styles.last}>
{/** Last two items */}
</div>
</div>
这可以用CSS实现吗?
答案 0 :(得分:11)
有趣的问题 - 遗憾的是,我无法看到可靠的纯CSS解决方案。也就是说,除非可以编辑HTML结构,即使这样会有一些硬编码,我也不相信有一个可靠的CSS解决方案。
但是,这里有3个可能的解决方案:
在下面的示例中,我创建了一个函数truncateBreadcrumbs()
,它接受3个参数:
selector
- 与您要截断的元素匹配的CSS选择器separator
- 用于分隔元素的字符segments
- 要将字符串截断为可以像:
一样使用truncateBreadcrumbs(".js-truncate", "/", 4);
将查找所有具有.js-truncate
类的元素,并将内容截断为4个元素,中间有...
个分隔符,如:
Corvid / Games / ... / Night Elf / Malfurion
也可以使用奇数段,例如5
将生成:
Corvid / Games / World of Warcraft / ... / Night Elf / Malfurion
如果segment
参数等于或大于元素数,则不会发生截断。
这是完整的工作示例:
function truncateBreadcrumbs(selector, separator, segments) {
const els = Array.from(document.querySelectorAll(selector));
els.forEach(el => {
const split = Math.ceil(segments / 2);
const elContent = el.innerHTML.split(separator);
if (elContent.length <= segments) {
return;
}
el.innerHTML = [].concat(
elContent.slice(0, split),
["..."],
elContent.slice(-(segments-split))
).join(` ${separator} `);
});
}
truncateBreadcrumbs(".js-truncate--2", "/", 2);
truncateBreadcrumbs(".js-truncate--4", "/", 4);
truncateBreadcrumbs(".js-truncate--5", "/", 5);
<div class="js-truncate--2">Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion</div>
<div class="js-truncate--4">Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion</div>
<div class="js-truncate--5">Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion</div>
<div class="js-truncate--4">Corvid / Games / Night Elf / Malfurion</div>
您正在使用React(基于className
属性)。如果是这种情况,我们可以创建一个简单的功能组件来截断文本。我已经采用了上面的代码并将其转换为功能组件<Truncate />
,它执行相同的操作:
const Truncate = function(props) {
const { segments, separator } = props;
const split = Math.ceil(segments / 2);
const elContent = props.children.split(separator);
if (elContent.length <= segments) {
return (<div>{props.children}</div>);
}
const newContent = [].concat(
elContent.slice(0, split),
["..."],
elContent.slice(-(segments-split))
).join(` ${separator} `);
return (
<div>{newContent}</div>
)
}
可以用作:
<Truncate segments="4" separator="/">
Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion
</Truncate>
这是完整的工作示例:
const Truncate = function(props) {
const { segments, separator } = props;
const split = Math.ceil(segments / 2);
const elContent = props.children.split(separator);
if (elContent.length <= segments) {
return (<div>{props.children}</div>);
}
const newContent = [].concat(
elContent.slice(0, split),
["..."],
elContent.slice(-(segments-split))
).join(` ${separator} `);
return (
<div>{newContent}</div>
)
}
class App extends React.Component {
render() {
return (
<div>
<Truncate segments="2" separator="/">
Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion
</Truncate>
<Truncate segments="4" separator="/">
Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion
</Truncate>
<Truncate segments="5" separator="/">
Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion
</Truncate>
<Truncate segments="4" separator="/">
Corvid / Games / Night Elf / Malfurion
</Truncate>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
我们还可以创建一个有状态的组件来响应屏幕/元素的宽度。这是一个非常粗略的想法 - 一个测试元素宽度并在必要时截断它的组件。理想情况下,组件只会根据需要截断,而不是截断到固定数量的段。
用法与上述相同:
<Truncate segments="4" separator="/">
Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion
</Truncate>
但区别在于组件测试容器宽度以查看段是否适合,如果不符合则文本被截断。单击“展开代码段”按钮可全屏查看演示,以便您可以调整窗口大小。
class Truncate extends React.Component {
constructor(props) {
super(props);
this.segments = props.segments;
this.separator = props.separator;
this.split = Math.ceil(this.segments / 2);
this.state = {
content: props.children
}
}
componentDidMount = () => {
this.truncate();
window.addEventListener("resize", this.truncate);
}
componentWillUnmount = () => {
window.removeEventListener("resize", this.truncate);
}
truncate = () => {
if (this.div.scrollWidth > this.div.offsetWidth) {
const elContentArr = this.state.content.split(this.separator);
this.setState({
content: [].concat(
elContentArr.slice(0, this.split),
["..."],
elContentArr.slice(-(this.segments - this.split))
).join(` ${this.separator} `)
})
}
}
render() {
return (
<div className="truncate" ref={(el) => { this.div = el; }}>
{this.state.content}
</div>
)
}
}
class App extends React.Component {
render() {
return (
<div>
<Truncate segments="2" separator="/">
Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion
</Truncate>
<Truncate segments="4" separator="/">
Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion
</Truncate>
<Truncate segments="5" separator="/">
Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion
</Truncate>
<Truncate segments="4" separator="/">
Corvid / Games / Night Elf / Malfurion
</Truncate>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById("app"));
.truncate {
display: block;
overflow: visible;
white-space: nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
答案 1 :(得分:6)
这是一种方法,只有在总共超过4项时才有效。
ul { list-style-type: none; }
ul li { display: none; }
ul li:nth-last-child(n+2):after { content: " / "; }
ul li:nth-child(2):after { content: " / ... /"; }
ul li:nth-child(-n+2), ul li:nth-last-of-type(-n+2) { display: inline-block; }
<ul>
<li><a href="#">Corvid</a></li>
<li><a href="#">Games</a></li>
<li><a href="#">World of Warcraft</a></li>
<li><a href="#">Assets</a></li>
<li><a href="#">Character Models</a></li>
<li><a href="#">Alliance</a></li>
<li><a href="#">Night Elf</a></li>
<li><a href="#">Malfurion</a></li>
</ul>
解决方法可能是在选择器前面添加一个类,并且只有在超过4个项目时才会截断。 理想情况下,这将添加到渲染上,但也可以通过javascript添加它,如本例所示
document.querySelectorAll("ul").forEach( el => el.childElementCount > 4 && el.classList.add("truncate") );
ul { list-style-type: none; }
ul li { display: inline-block;}
ul li:nth-last-child(n+2):after { content: " / "; }
ul.truncate li { display: none; }
ul.truncate li:nth-child(2):after { content: " / ... /"; }
ul.truncate li:nth-child(-n+2), ul li:nth-last-of-type(-n+2) { display: inline-block; }
<ul>
<li><a href="#">Corvid</a></li>
<li><a href="#">Games</a></li>
<li><a href="#">World of Warcraft</a></li>
<li><a href="#">Assets</a></li>
<li><a href="#">Character Models</a></li>
<li><a href="#">Alliance</a></li>
<li><a href="#">Night Elf</a></li>
<li><a href="#">Malfurion</a></li>
</ul>
不知道问题中是否有遗漏,但如果你不想改变你的结构,你也可以这样做:
.truncate div { display: inline-block; }
.truncate .mid { display: none; }
.truncate .first:after { content: "... /"; }
<div class="truncate">
<div class="first">
Corvid / Games /
</div>
<div class="mid">
World of Warcraft / Assets / Character Models / Alliance /
</div>
<div class="last">
Night Elf / Malfurion
</div>
</div>
或者如果你想要一个简单的纯js函数
document.querySelectorAll(".turncate").forEach( el => {
const parts = el.innerText.split(" / ");
if(parts.length > 4){
parts.splice(2, parts.length-4); //ensure we only have two first and last items
parts.splice(2, 0, "..."); // add ... after 2 first items.
el.innerText = parts.join(" / ");
}
});
<div class="turncate">
Corvid / Games / World of Warcraft / Assets / Character Models / Alliance / Night Elf / Malfurion
</div>
答案 2 :(得分:3)
.enumeration > div{display:inline-block;font-size:150%}
.enumeration > div:after{content: " / ";color:blue;font-weight:bold;}
.enumeration > div:nth-child(n+3) {display:none;}
.enumeration > div:nth-child(n+2):after {content: " / ... / ";color: red;}
.enumeration > div:nth-last-child(-n+2) {display:inline-block;}
.enumeration > div:nth-last-child(-n+3):after{content:" / ";color:green;}
.enumeration > div:nth-last-child(-n+2):after{content:" / ";color:orange;}
.enumeration > div:last-child:after{content:""}
有点棘手,但它只是css并适用于任何列表大小。 :) (颜色和粗体只是为了更容易看到每个选择器的应用位置。)
.enumeration > div{display:inline-block;font-size:150%}
.enumeration > div:after{content: " / ";color:blue;font-weight:bold;} /*1*/
.enumeration > div:nth-child(n+3) {display:none;}/*2*/
.enumeration > div:nth-child(n+2):after {content: " / ... / ";color: red;}/*3*/
.enumeration > div:nth-last-child(-n+2) {display:inline-block;}/*4*/
.enumeration > div:nth-last-child(-n+3):after{content:" / ";color:green;}/*5*/
.enumeration > div:nth-last-child(-n+2):after{content:" / ";color:orange;}/*6*/
.enumeration > div:last-child:after{content:""}/*7*/
<h2>
More than 4 items list
</h2>
<div class="enumeration">
<div>item 1</div>
<div>item 2</div>
<div>item 3</div>
<div>item 4</div>
<div>item 5</div>
<div>item 6</div>
<div>item 7</div>
<div>item 8</div>
<div>item 9</div>
</div>
<h2>
4 items list
</h2>
<div class="enumeration">
<div>item 1</div>
<div>item 2</div>
<div>item 3</div>
<div>item 4</div>
</div>
<h2>
3 items list
</h2>
<div class="enumeration">
<div>item 1</div>
<div>item 2</div>
<div>item 3</div>
</div>
<h2>
2 items list
</h2>
<div class="enumeration">
<div>item 1</div>
<div>item 2</div>
</div>
<h2>
1 item list
</h2>
<div class="enumeration">
<div>item 1</div>
</div>
答案 3 :(得分:2)
我已经使用伪元素和媒体查询提出了这个概念证明。请在整页上运行代码段并将宽度更改为小于500px。
我已经了解了媒体查询cannot apply to individual elements' widths,因此这可能不太有用,您必须根据浏览器的宽度将max-width
调整为实际值。
DIV.truncate::before {
content: 'World of Warcraft / Assets / Character Models / Alliance';
}
@media (max-width: 500px) {
DIV.truncate::before {
content: '...';
}
}
DIV.container {
font-weight: bold;
font-family: Arial, sans-serif;
font-size: 14px;
white-space: nowrap;
overflow-x: auto;
}
DIV.container>DIV {
display: inline-block;
}
<div class="container">
<div class="first">Corvid / Games /</div>
<div class="truncate"></div>
<div class="last">/ Night Elf / Malfurion</div>
</div>
答案 4 :(得分:2)
您可以使用flex和truncate text的组合:
.grid-container {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
width: 320px;
margin-top: 30vh;
margin-right: auto;
margin-left: auto;
}
.grid-item {
overflow: hidden;
height: 1.5em;
line-height: 1.5em;
}
.grid-item.expand {
-webkit-box-flex: 1;
-webkit-flex: 1;
-ms-flex: 1;
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
}
<div class="grid-container">
<div class="grid-item" style="background: red">Corvid / Games </div>
<div class="expand grid-item">/ World of Warcraft / Assets / Character Models / Alliance </div>
<div class="grid-item" style="background: blue">/ Night Elf / Malfurion</div>
</div>
Flex将使中心元素宽度动态化,文本溢出将使其截断。 如果不是你想要的,请解释更多。
答案 5 :(得分:2)
这使用了我从Lea Verou获得的技巧 有关SCSS示例,请参阅https://codepen.io/HerrSerker/pen/JOaqjL
ul.breadcrumb, ul.breadcrumb > li {
list-style: none;
margin: 0;
padding: 0;
}
ul.breadcrumb > li {
display: inline-block;
}
/* this adds the slash between the `<li>` */
ul.breadcrumb > li:not(:last-child):after {
content: ' /';
}
/* this is the second `<li>`, but only if there are 5 or more `<li>` */
/* 5 = 2 + 4 - 1 */
ul.breadcrumb > li:nth-child(2):nth-last-child(n+4):after {
content: ' / … /';
}
/* these are `<li>` No. 3 up to 3rd to last `<li>`, but only if there are 5 or more `<li>` */
/* 5 = 3 + 3 - 1 */
ul.breadcrumb > li:nth-child(n+3):nth-last-child(n+3) {
display: none;
}
<ul class="breadcrumb">
<li>Corvid</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
<li>Character Models</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
<li>Character Models</li>
<li>Alliance</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
<li>Character Models</li>
<li>Alliance</li>
<li>Night Elf</li>
</ul>
<ul class="breadcrumb">
<li>Corvid</li>
<li>Games</li>
<li>World of Warcraft</li>
<li>Assets</li>
<li>Character Models</li>
<li>Alliance</li>
<li>Night Elf</li>
<li>Malfurion</li>
</ul>