在移动端中,屏幕的宽度通常会不足,在这样的宽度中可能要放下几个标签,这几个标签需要在一行内显示,标签数量不确定,标签内文字数量不确定。现要求是标签尽可能的往一行内放,如果放不下一个完整的标签,那么该标签会以打点的方式在一行的最后一个。
只有一个标签,字数超出一行打点
该标签只有需要最基础的overflow:hidden;white-space:nowrap;text-overflow:ellipsis;就能实现。
两个标签,字数超出一行打点
.line-box {
box-sizing: border-box;
--column-gap: 4px;
--text-wrap-padding: 4px;
--text-wrap-border-radius: 4px;
--text-font-size: 12px;
--text-color: white;
--text-background: blue;
width: 100px;
height: 40px;
resize: horizontal;
padding: 10px;
}
.w {
display: flex;
flex-wrap: wrap;
overflow: hidden;
}
.tag {
white-space: nowrap;
text-overflow: ellipsis;
/* 第一个作用是使打点生效,第二个作用是作为flex子元素使得在最小尺寸由最小内容宽度决定的时候使最小尺寸失效从而可以无视最小尺寸限制去缩放 */
overflow: hidden;
background-color: var(--text-background);
margin: 0 calc(var(--column-gap) / 2);
color: var(--text-color);
font-size: var(--text-font-size);
border-radius: var(--text-wrap-border-radius);
padding: var(--text-wrap-padding);
/* 使下方的tag超出容器高度隐藏 */
margin-bottom: 50px;
}
.z {
flex: 1;
min-width: 30px;
display: flex;
}
.f1 {
flex: 1;
}
<!-- 两个标签超过打点 -->
<div class="line-box w">
<div class="tag">第一个</div>
<div class="z">
<div class="tag">第二个</div>
<div class="f1"></div>
</div>
</div>
首先要实现宽度超过一个标签,但是不超过两个标签时第一个标签不打点,第二个标签打点。因此第一个标签的宽度需要尽可能的不缩小,第二个标签缩小完之前不能缩小第一个标签。首先两个标签的容器是flex,flex-wrap:wrap是为了第二个标签缩小到一定程度可以换行。因此需要第一个标签的基础尺寸是标签的长度,最小尺寸是0,第二个标签的基础尺寸是0,最小尺寸是30px。并且可以占据除第一个标签外的所有空间。根据flex弹性伸缩规则,当容器的宽度大于子元素的基础尺寸之和,子元素不会出现宽度小于基础尺寸的情况。因此会出现先缩小基础尺寸是0的元素,当容器的宽度比基础尺寸小时,再根据弹性缩放规则是子元素的宽度缩放的比基础尺寸还小。由于第二个标签与第一个标签所拥有的属性应该是一致的,所以需要给第二个标签套一个容器来实现第二个标签所需要的额外功能。该容器就是z,z所具有的功能是让第二个标签占据除第一个标签外的所有宽度,且具有最小尺寸,如果小于最小尺寸,第二个标签会被换到下一行去,这样就看不见了。并且让第二个标签的基础尺寸是0(flex:1 = flex: 1 1 0%;),如果宽度足够宽第二个标签也不会占据太大宽度。因为标签本身的属性是基础宽度为不换行的文本宽度,且不会弹性扩大。
三个标签字数超过一行打点
<div class="line-box w">
<div class="w">
<div class="tag">第一个</div>
<div class="z">
<div class="tag">第二个</div>
</div>
</div>
<div class="z">
<div class="tag">第三个</div>
</div>
</div>
我们已经知道两个标签超过一行打点的方法。这个方法我们直接借用。那么还需要一个标签做成三个标签字数超过一行打点。由数学归纳法得,三个标签超过一行打点=两个标签超过一行打点+一个标签超过一行打点。因此还是需要一个容器,yoi容器的左侧是两个标签的容器,右侧是一个标签的容器。左侧的容器的基础宽度是两个标签不换行的宽度,右侧标签容器的基础宽度是0。因此右侧标签的实现与二个标签超出一行打点的第二个标签的实现是一致的。需要改变的是给两个标签超出一行打点加一个基础宽度是不换行宽度,最小尺寸是0,因此容器作为flex子元素,flex默认值就是0 1 auto。基础宽度是达标的。加入overflow:hidden是为了让最小尺寸变为0;加入flex-wrap:wrap;是为了保持原有的标签宽度太小就换行不显示的功能。
n个标签超过一行打点
现在我们已经找出规律
n个标签超过一行打点 = 容器w_line-box(容器w((n-1)个标签超出一行点) +容器z(标签) )
使用递归得
const fac = (n, arr) => {
if (n <= 0) {
return ''
}
if (n === 1) {
return `<div class="w"><div class="tag">${arr[n]}</div></div>`
}
const len = arr.length
return `<div class="w${n === len ? ' line-box' : ''}"><div class="w">${fac(
n - 1,
arr,
)}</div><div class="z"><div class="tag">${arr[len - n]}</div></div></div>`
}
const arr = [
'塑料科技',
'sdkjfhdsf',
'莱克斯顿',
'塑料科技',
'sdkjfhdsf',
'莱克斯顿',
'塑料科技',
'sdkjfhdsf',
'莱克斯顿',
]
const fragment = document.createDocumentFragment()
document.getElementById('container').innerHTML = fac(arr.length, arr)