子组件:/components/timeline/timeline-item
<view class="timeline-item">
<view class="timeline-item-dot"></view>
<text class="label">{{ label }}</text>
<view class="value">
<text>{{ value }}</text>
<text wx:if="{{ unit }}" class="unit">{{ unit }}</text>
</view>
</view>
Component({
// ---- 建立与父组件的关系 ----
relations: {
'../timeline': {
type: 'parent' // 关联的父组件
}
},
// ---- 定义组件可接收的外部属性 ----
properties: {
label: String,
value: String,
unit: String
}
});
@text-color-label: #888888;
@text-color-value: #333333;
@font-size-base: 16px;
.timeline-item {
display: flex;
align-items: center;
margin-bottom: 28px;
font-family: sans-serif;
&:last-child {
margin-bottom: 0;
}
}
.timeline-item-dot {
width: 8px;
height: 8px;
box-sizing: border-box;
border: 2px solid @primary-color;
background: rgb(255, 255, 255);
flex-shrink: 0;
border-radius: 50%;
margin-right: 7px;
z-index: 1;
}
.label {
color: rgb(131, 131, 131);
font-family: 思源黑体 CN;
font-size: 14px;
font-weight: 400;
line-height: 21px;
letter-spacing: 0px;
text-align: left;
margin-right: auto;
}
.value {
display: flex;
align-items: baseline;
color: rgb(29, 34, 30);
font-family: 思源黑体 CN;
font-size: 14px;
font-weight: 400;
line-height: 21px;
letter-spacing: 0px;
text-align: right;
.unit {
font-size: 0.9em;
color: @text-color-value;
margin-left: 4px;
font-weight: 400;
}
}
父组件:/components/timeline/timeline
<view class="timeline">
<!-- 链接点的装饰线 -->
<view class="timeline-line" style="{{ lineStyle }}"></view>
<slot></slot>
</view>
Component({
relations: {
'./timeline-item/timeline-item': {
type: 'child', // 关联的子组件
linked() {
// 每当有 timeline-item 插入时,重新计算线条
if (this.data.timer) clearTimeout(this.data.timer);
this.data.timer = setTimeout(() => {
this.updateLinePosition();
}, 30);
},
unlinked() {
// 每当有 timeline-item 移除时,重新计算线条
if (this.data.timer) clearTimeout(this.data.timer);
this.data.timer = setTimeout(() => {
this.updateLinePosition();
}, 30);
}
}
},
data: {
lineStyle: '',
timer: 0
},
methods: {
updateLinePosition() {
// 使用 wx.nextTick 确保在 DOM 更新后再执行查询
wx.nextTick(() => {
const query = wx.createSelectorQuery().in(this);
// 查询所有子组件的圆点 FIXME: 找不到子组件
query.selectAll('.timeline-item-dot').boundingClientRect();
// 查询父容器 .timeline 的位置信息,而不是线条自身
query.select('.timeline').boundingClientRect();
query.exec((res) => {
const [dots, wrapper] = res;
console.debug(dots, wrapper);
// 至少需要两个节点才能形成一条线
if (dots && dots.length > 1 && wrapper) {
const firstDot = dots[0];
const lastDot = dots[dots.length - 1];
const lineTop = firstDot.top + firstDot.height / 2 - wrapper.top;
const lineHeight = lastDot.top + lastDot.height / 2 - (firstDot.top + firstDot.height / 2);
this.setData({
lineStyle: `top: ${lineTop}px; height: ${lineHeight}px;`
});
} else {
// 如果子项少于2个,则不显示线条
this.setData({ lineStyle: 'height: 0;' });
}
});
});
}
}
});
.timeline {
position: relative;
background-color: #ffffff;
}
.timeline-line {
position: absolute;
left: 20.5px; // 与 timeline-item 的圆点中心对齐
width: 1px;
box-sizing: border-box;
border: 1px solid rgb(235, 235, 235);
z-index: 0;
// top 和 height 由 TS 动态设定
}
