準備一張 1px × 20px 的基礎圖片 (如藍色漸層),透過設定 <img> 的 width 屬性拉伸寬度,即可以極小資源實現視覺進度條。配合資料庫票數計算百分比,動態決定寬度。
CREATE TABLE TvoteNum (
Vid INT PRIMARY KEY, -- 選項 ID
Vname VARCHAR(50), -- 選項名稱
Vnum INT DEFAULT 0 -- 得票數
);
-- 範例資料
INSERT INTO TvoteNum VALUES (1, '贊成', 120), (2, '反對', 80), (3, '棄權', 30), (4, '無意見', 20);
<%@ Page Language="C#" %>
<html>
<body>
<h2>投票結果</h2>
<table>
<asp:Repeater ID="rptVotes" runat="server">
<ItemTemplate>
<tr>
<td style="width:120px;"><%# Eval("Vname") %></td>
<td style="width:80px;"><%# Eval("Vnum") %> 票</td>
<td style="width:310px; background:#eee; height:20px; position:relative;">
<img src="images/bar.png" alt=""
style="height:20px; position:absolute; left:0; top:0;"
width='<%# GetBarWidth(Eval("Vnum")) %>' />
<span style="position:absolute; left:5px; top:0; color:white; font-weight:bold;">
<%# Eval("Percentage", "{0:P1}") %>
&span>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
</body>
</html>
public partial class VoteResult : System.Web.UI.Page
{
private int _totalVotes = 0;
private const int MaxBarWidth = 310; // 進度條最大寬度 (px)
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BindVoteData();
}
}
private void BindVoteData()
{
string connStr = ConfigurationManager.ConnectionStrings("VoteDB").ConnectionString;
using (SqlConnection conn = new SqlConnection(connStr))
{
// 1. 取得所有選項票數
string sql = "SELECT Vid, Vname, Vnum FROM TvoteNum ORDER BY Vid";
SqlDataAdapter da = new SqlDataAdapter(sql, conn);
DataTable dt = new DataTable();
da.Fill(dt);
// 2. 計算總票數
_totalVotes = dt.AsEnumerable().Sum(row => row.Field("Vnum"));
// 3. 計算百分比並加入資料表 (供 Repeater 繫結)
dt.Columns.Add("Percentage", typeof(double));
foreach (DataRow row in dt.Rows)
{
int votes = row.Field("Vnum");
row["Percentage"] = _totalVotes > 0 ? (double)votes / _totalVotes : 0;
}
rptVotes.DataSource = dt;
rptVotes.DataBind();
}
}
// 供 Eval 呼叫:計算進度條寬度
protected int GetBarWidth(object votesObj)
{
int votes = Convert.ToInt32(votesObj);
if (_totalVotes == 0) return 0;
double ratio = (double)votes / _totalVotes;
return (int)Math.Floor(ratio * MaxBarWidth);
}
}
| 技術點 | 說明 |
|---|---|
| 單一像素圖片 | bar.png (1x20px),體積極小 (<1KB),瀏覽器快取後重複使用零流量。 |
| CSS 定位 | 容器 position:relative,圖片 position:absolute; left:0 確保從左邊緣拉伸。 |
| 百分比顯示 | 重疊 span 顯示百分比文字,顏色對比確保可讀。 |
| 資料繫結分離 | 邏輯集中於 GetBarWidth 方法,標記僅呼叫 <%# GetBarWidth(...) %>,職責清晰。 |
| 總票數快取 | _totalVotes 為頁面層級變數,DataBind 期間多次呼叫 GetBarWidth 共用同一總數,避免重複查詢。 |
<div class="progress-bar" style="width: 310px; height: 20px; background: #eee; border-radius: 10px; overflow: hidden;">
<div class="progress-fill" style="width: <%# GetBarWidth(...) %>px; height: 100%; background: linear-gradient(90deg, #3498db, #2980b9); border-radius: 10px; transition: width 0.5s ease;">
<span style="display: inline-block; width: 100%; text-align: right; padding-right: 5px; color: white; font-weight: bold; line-height: 20px;"><%# Eval("Percentage", "{0:P1}") %></span>
</div>
</div>
transition)、圓角、漸層。' 前端 JavaScript (SignalR)
var voteHub = $.connection.voteHub;
voteHub.client.updateResult = function(data) {
// data: { Vid: 1, Vnum: 125, Total: 255 }
var row = $('tr[data-vid="' + data.Vid + '"]');
var width = Math.floor(data.Vnum / data.Total * 310);
row.find('.progress-fill').css('width', width + 'px');
row.find('.percentage').text((data.Vnum / data.Total * 100).toFixed(1) + '%');
};
$.connection.hub.start();
伺服器端投票寫入後,呼叫 Clients.All.updateResult(new { Vid, Vnum, Total }) 推送更新,無需重整頁面。
利用單一像素圖片拉伸或 CSS3 彈性盒子實現投票進度條,核心在於**後端計算百分比、前端映射寬度**。現代開發建議採用 CSS3 純樣式方案,配合 SignalR 實現即時動態更新,提升使用者參與感與互動體驗。