????????開(kāi)發(fā)“連線題”并沒(méi)什么難點(diǎn),這里主要分享的是:實(shí)現(xiàn)過(guò)程中的一點(diǎn)點(diǎn)布局設(shè)計(jì)上的小心思。想要的效果大體長(zhǎng)這樣(如下圖所示):

????????乍一看似乎需要獲取每個(gè)元素的位置信息、計(jì)算連線的端點(diǎn)坐標(biāo),似乎很繁瑣,而且每次頁(yè)面尺寸變化時(shí),都得重新計(jì)算。其實(shí),事情可以比想象中簡(jiǎn)單很多…
一、方案設(shè)計(jì)
????????1.1 將連線題分為上中下三個(gè)區(qū)塊,其中:
????????1)上下區(qū)塊均使用flex(justify-content: space-around)
????????2)中間區(qū)塊為canvas,在style屬性中將width和height設(shè)置為100%
.row-1 { justify-content: space-around; }
.row-2 {
????????height: 0; flex-grow: 1;
????????canvas { width: 100%; height: 100%; }
}
.row-3 { justify-content: space-around; }

? ??????1.2 這樣設(shè)置以后,有幾點(diǎn)好處:
????????1)計(jì)算直線端點(diǎn)(元素中點(diǎn))坐標(biāo)就會(huì)變得很輕松,只需要排序百分比與canvas的內(nèi)容寬度相乘即可。
let x1 = (上方元素下標(biāo) * 2 + 1) / (上方元素總數(shù) * 2) * canvas.width
let x2 = (下方元素下標(biāo) * 2 + 1) / (下方元素總數(shù) * 2) * canvas.width
// 連線上方端點(diǎn)坐標(biāo): (x1, 0)
// 連線下方端點(diǎn)坐標(biāo): (x2, canvas.height)
????????2)頁(yè)面resize時(shí)無(wú)需重新計(jì)算,頁(yè)面也不會(huì)亂。當(dāng)然如果resize前后差異較大,可能連線粗細(xì)程度會(huì)不美觀。
????????經(jīng)測(cè),一般不重新繪制也問(wèn)題不大;如果要求高的話,可以在resize時(shí)重新繪制一下。(下圖是第一張圖在網(wǎng)頁(yè)resize后的效果,線條經(jīng)過(guò)拉伸變細(xì)了)

????????3)如果你連canvas的尺寸也懶得初始化,也是可以的,只不過(guò)效果會(huì)差些(線條有點(diǎn)模糊,粗細(xì)不美觀),Chrome中canvas默認(rèn)內(nèi)容尺寸是300*100,效果如下圖所示(截圖可能視覺(jué)效果不明顯):

二、代碼實(shí)現(xiàn)
????????線條繪制的相關(guān)代碼如下:
????????Html
<canvas ref="canvas" :width="cvsWidth" :height="cvsHeight"></canvas>
????????Js
// 動(dòng)態(tài)調(diào)整canvas的內(nèi)容尺寸(必要時(shí),可在每次resize時(shí)重復(fù)調(diào)用)
initCanvas() {
? if (!this.$refs.canvas) return
? let cvsInfo = this.$refs.canvas.getBoundingClientRect()
? this.cvsWidth = parseInt(cvsInfo.width)
? this.cvsHeight = parseInt(cvsInfo.height)
},
// 繪制連線
drawLine() {
? if (!this.$refs.canvas) return
? let count = this.dataList.length
? let ctx = this.$refs.canvas.getContext("2d");
? let cvsWidth = this.$refs.canvas.width
? let cvsHeight = this.$refs.canvas.height
? ctx.clearRect(0, 0, cvsWidth, cvsHeight);
? ctx.lineWidth = 4;
? ctx.lineCap = 'round';
? ctx.strokeStyle = '#FF9C0A'
? for (let k in this.answerDict) {
? ? let _i1 = parseInt(k)
? ? let _i2 = this.answerDict[k]
? ? let _i1_x = (_i1 * 2 + 1) / (count * 2) * cvsWidth
? ? let _i2_x = (_i2 * 2 + 1) / (count * 2) * cvsWidth
? ? ctx.beginPath()
? ? ctx.moveTo(_i1_x, 0);
? ? ctx.lineTo(_i2_x, cvsHeight);
? ? ctx.stroke()
? }
},