2026-10-03 起,文章分享改成了分享海报,实现见《Canvas分享海报》。下面记录的是三月版分享卡片的做法。
前言
在个人博客中,分享功能是提升内容传播效率的重要组件。本文将详细介绍如何为博客实现一个优雅的分享卡片功能,包括卡片UI设计、Canvas绘制,二维码生成等核心技术点。
效果预览
![]()
功能需求
分享卡片需要满足以下需求:
- 点击分享按钮弹出分享卡片
- 卡片包含文章标题、摘要、创建时间、作者信息
- 包含可扫描的二维码
- 支持将卡片保存为图片
- 良好的响应式设计,适配PC和移动端
技术方案
1. HTML结构
分享卡片的弹窗使用HTML Overlay实现:
<div id="shareImageModal" class="share-image-modal">
<div class="share-image-content">
<h3 class="share-image-title">分享卡片</h3>
<canvas id="shareImageCanvas" width="375" height="480"></canvas>
<div class="share-image-actions">
<button id="downloadImageBtn" class="share-image-btn primary">
<i class="download icon"></i> 保存图片
</button>
<button id="closeShareModalBtn" class="share-image-btn secondary">关闭</button>
</div>
</div>
</div>
2. Canvas绘制核心逻辑
使用Canvas API绘制分享卡片是关键环节。以下是核心绘制流程:
function generateShareImage() {
var canvas = document.getElementById('shareImageCanvas');
var ctx = canvas.getContext('2d');
// 设置画布尺寸
var width = 375;
var height = 480;
canvas.width = width * 2;
canvas.height = height * 2;
ctx.scale(2, 2);
// 绘制背景
ctx.fillStyle = '#FAFAFA';
ctx.fillRect(0, 0, width, height);
// 绘制卡片
// ... 详细绘制代码见下文
}
3. 文本换行处理
Canvas不原生支持文本自动换行,需要自定义函数:
function wrapText(ctx, text, x, y, maxWidth, lineHeight, maxLines, center, centerY) {
var words = text.split('');
var line = '';
var lines = [];
// 逐词计算换行
for (var n = 0; n < words.length; n++) {
var testLine = line + words[n];
var metrics = ctx.measureText(testLine);
if (metrics.width > maxWidth && n > 0) {
lines.push(line);
line = words[n];
} else {
line = testLine;
}
}
lines.push(line);
// 限制最大行数
if (lines.length > maxLines) {
lines = lines.slice(0, maxLines);
lines[maxLines - 1] = lines[maxLines - 1].substring(0, lines[maxLines - 1].length - 3) + '...';
}
// 绘制文本
for (var k = 0; k < lines.length; k++) {
var lineX = x;
if (center) {
var lineWidth = ctx.measureText(lines[k]).width;
lineX = x - lineWidth / 2;
}
ctx.fillText(lines[k], lineX, y + k * lineHeight);
}
}
4. 二维码生成
使用qrcode.js库生成可扫描的二维码:
// 创建临时容器
var qrContainer = document.createElement('div');
qrContainer.style.display = 'none';
document.body.appendChild(qrContainer);
// 生成二维码
var qr = new QRCode(qrContainer, {
text: articleUrl,
width: qrSize,
height: qrSize,
colorDark: '#1a1a1a',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H
});
// 等待生成完成后绘制到主Canvas
setTimeout(function() {
var qrImg = qrContainer.querySelector('img');
ctx.drawImage(qrImg, qrX, qrY, qrSize, qrSize);
document.body.removeChild(qrContainer);
}, 150);
UI设计细节
1. 视觉层次
分享卡片采用简约优雅的设计风格:
- 顶部装饰线:红色竖线作为视觉焦点
- 标题区域:使用衬线字体,水平垂直居中
- 摘要区域:灰色背景区分,限制显示255字符
- 底部信息栏:浅灰背景,包含作者、时间和二维码
2. 色彩系统
var COLOR = {
title: '#1A1A1A',
body: '#4A4A4A',
caption: '#8E8E8E',
accent: '#C0392B',
divider: '#E8E8E8',
cardBg: '#FFFFFF'
};
3. 字体排版
var FONT = {
title: 'bold 18px "Noto Serif SC", "Songti SC", "SimSun", serif',
body: '14px "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif',
caption: '11px "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif'
};
功能实现
1. 获取文章信息
// 获取文章标题
var articleTitle = document.querySelector('.post-title a');
var title = articleTitle ? articleTitle.textContent.trim() : '文章标题';
// 获取文章摘要
var aiSummaryText = document.getElementById('aiTypewriter');
var summary = aiSummaryText ? aiSummaryText.textContent.trim() : '暂无摘要';
// 获取文章创建时间
var timeElement = document.querySelector('time[itemprop="datePublished"]');
var createTime = timeElement ? timeElement.textContent.trim() : '';
// 获取文章链接
var articleHref = document.getElementById("articleHref");
var articleUrl = articleHref ? articleHref.href : window.location.href;
2. 图片下载
function downloadShareImage() {
var canvas = document.getElementById('shareImageCanvas');
var link = document.createElement('a');
link.download = '分享卡片.png';
link.href = canvas.toDataURL('image/png');
link.click();
}
响应式适配
CSS媒体查询
@media (max-width: 767px) {
.share-image-content {
padding: 20px;
width: 100%;
max-width: 350px;
}
.share-image-title {
font-size: 18px;
}
}
性能优化
- Canvas渲染:使用2倍缩放确保高清显示
- 二维码生成:异步处理,避免阻塞主线程
- 图片下载:使用Canvas的toDataURL方法
- 字体加载:使用系统字体栈,避免加载延迟
总结
本文详细介绍了博客分享卡片功能的设计与实现,涵盖了从需求分析、UI设计到代码实现的完整流程。核心难点在于Canvas文本换行处理,二维码生成以及多端适配。通过合理的技术选型和代码优化,最终实现了一个功能完善、体验良好的分享功能。

评论区 3