其原理,还是利用border属性来实现边线两端的斜边。两个边交叉的地址即为斜边。例如,以下是一个宽100px,边40px的正方形。观察两条相邻边相交的地方,是一条斜边。

<div class="box"></div>
.box{
margin:20px;
width: 100px;
height: 100px;
border-left: 40px solid red;
border-right: 40px solid red;
border-top: 40px solid black;
border-bottom: 40px solid black;
}
但是,这样有个问题是两个边之间没有空隙,无法达到模拟效果,所以七条边需要各自模拟。
首先,假设每个“管”有个一个编号

我们用”.d1″, “.d2″……来命名各个边的样式。我们分别给各个别设定宽、高、位移和定位。
例如1号边:
.d1 {
height: 0;
width: calc($boxW - $space * 2); // 线宽度, $space是两个管之间相邻的缝隙,减掉$space*2 正是为了减掉缝隙宽度。
position: absolute; // 以下四行是定位,固定在顶部
top: 0;
left: math.div($space, 1);
right: 0;
border: $with solid $color; // 这四行是画边线。
border-left-color: transparent;
border-right-color: transparent;
border-bottom: 0;
}
完整代码如下。
样式代码(SASS语法)
@use "sass:math";
.nixie-tube {
$size: 1em; // 字符宽度
$with: 0.2em; // 线宽
$color: #000; // 线颜色
$space: 0.15em; // 线之间的间距
$boxW: $size * 0.8;
$boxH: $size * 1.2;
margin-right: 2px;
height: $boxH;
width: $boxW;
position: relative;
display: inline-block;
line-height: 1;
&.nixie-text-wrapper {
width: auto;
}
/* 数值 1 靠左偏移 3/8, 以便看起来不要跟右侧的数字太近 */
&.n-1 {
transform: translateX(calc($boxW * -0.375));
}
/* 非数字类型,增加视觉误差 */
.nixie-text {
font-size: calc($boxH + 0.1em);
}
/* 每一个管的位置、宽度 */
.d1 {
height: 0;
width: calc($boxW - $space * 2);
position: absolute;
top: 0;
left: math.div($space, 1);
right: 0;
border: $with solid $color;
border-left-color: transparent;
border-right-color: transparent;
border-bottom: 0;
}
.d2 {
height: $with;
width: calc($boxW - $space * 2);
border: none;
position: absolute;
top: calc(($boxH - $with) / 2);
left: math.div($space, 1);
/* 由于线两端不是斜边,所以不能用常规方法。改用before和after两个伪元素来模拟三角形,固定在线的两端。 */
&:before {
content: " ";
height: 0;
position: absolute;
top: 0;
left: 0;
right: 0;
border: calc(math.div($with, 2) + 0.6px) solid $color;
border-left-color: transparent;
border-right-color: transparent;
border-top: 0;
}
&:after {
content: " ";
height: 0;
position: absolute;
left: 0;
right: 0;
bottom: 0;
// top: calc(math.div($with, 2) - 0.5px);
border: calc(math.div($with, 2) + 0.6px) solid $color;
border-left-color: transparent;
border-right-color: transparent;
border-bottom: 0;
}
}
.d3 {
height: 0;
width: calc($boxW - $space * 2);
position: absolute;
bottom: 0;
left: math.div($space, 1);
right: 0;
border: $with solid $color;
border-left-color: transparent;
border-right-color: transparent;
border-top: 0;
}
.d4,
.d6 {
width: 0;
position: absolute;
top: 0;
height: math.div($boxH, 2);
left: 0;
border: $with solid $color;
border-top-color: transparent;
border-bottom-color: transparent;
border-right: 0;
}
.d5,
.d7 {
width: 0;
position: absolute;
top: 0;
height: math.div($boxH, 2);
right: 0;
border: $with solid $color;
border-top-color: transparent;
border-bottom-color: transparent;
border-left: 0;
}
.d6,
.d7 {
top: calc(($boxH) / 2);
}
}
react部分相对简单
import './index.scss'
export default function NixieTube (props) {
let number = props.number;
// 如果不是数字,则直接显示文字。
if (isNaN(number)) {
return (<div className='nixie-tube nixie-text-wrapper'>
<div className='nixie-text'>{number}</div>
</div>)
}
number = parseInt(number);
return (
<div className={'nixie-tube n-' + number}>
{[2, 3, 5, 6, 7, 8, 9, 0].includes(number) && <div className='d1'></div>}
{[2, 3, 4, 5, 6, 8, 9].includes(number) && <div className='d2'></div>}
{[2, 3, 5, 6, 8, 9, 0].includes(number) && <div className='d3'></div>}
{[4, 5, 6, 8, 9, 0].includes(number) && <div className='d4'></div>}
{[1, 2, 3, 4, 7, 8, 9, 0].includes(number) && <div className='d5'></div>}
{[2, 6, 8, 0].includes(number) && <div className='d6'></div>}
{[1, 3, 4, 5, 6, 7, 8, 9, 0].includes(number) && <div className='d7'></div>}
</div>
)
}
使用方法:
由于以上实现仅实现了单个字符的显示,建议二次封装,可以直接显示一段文字
import Nixietube from "@/components/nixietube/index";
export default function (props) {
const renderNixietube = (text) => {
if (!text) {
return null;
}
let chars = text.split('').map((c, i) => {
return <Nixietube number={c} key={i}></Nixietube>
});
return <div className="nixietube-container">{chars}</div>
}
return renderNixietube("这是数码管:123456789" );
}
实际显示效果

其他要注意的地方。字符“1”比较狭窄,看起来会贴近右侧数字,同时跟左侧数字距离较远,看起来会很奇怪。所以写样式时,适当将字符“1”向左偏移30%左右,这样看起来会协调很多。