旅行记录应用最近旅行页面 - Cordova & OpenHarmony 混合开发实战
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。
📌 概述
最近旅行页面展示用户最近查看或编辑过的旅行记录。这个页面提供了快速访问常用旅行的便利,提升了用户体验。最近旅行功能需要记录用户的访问历史,并按照时间顺序排序。在 Cordova 与 OpenHarmony 的混合开发框架中,我们需要实现访问历史的记录、查询和展示功能。
🔗 完整流程
第一步:访问历史记录与时间戳管理
最近旅行功能需要记录用户每次访问旅行的时间。当用户查看或编辑旅行时,需要更新该旅行的最后访问时间。这个时间戳用于排序最近旅行列表,确保最近访问的旅行显示在最前面。
访问历史的记录可以在数据库中维护一个 lastViewedAt 字段,每次用户访问旅行时更新这个字段。
第二步:最近旅行列表的加载与排序
最近旅行页面需要从数据库中查询所有旅行,然后按照 lastViewedAt 字段进行降序排序,取前 N 条记录作为最近旅行列表。这个过程需要高效的数据库查询和排序算法。
最近旅行列表通常显示的数量有限(如前 20 条),这样可以减少 DOM 节点数量,提高渲染性能。
第三步:原生层访问历史优化与缓存
OpenHarmony 原生层可以实现访问历史的缓存和优化。原生层可以维护一个内存缓存,存储最近访问的旅行列表,避免频繁的数据库查询。原生层还可以实现访问历史的清理机制,定期清理过期的访问记录。
🔧 Web 代码实现
最近旅行页面 HTML 结构
<div id="recent-page" class="page">
<div class="page-header">
<h1>最近旅行</h1>
<button class="btn-icon" onclick="clearRecentHistory()">🗑️</button>
</div>
<div class="recent-container">
<div class="recent-list" id="recentList">
<!-- 最近旅行列表动态加载 -->
</div>
<div class="empty-state" id="emptyState" style="display: none;">
<div class="empty-icon">🕐</div>
<p>还没有浏览过任何旅行</p>
</div>
</div>
</div>
HTML 结构包含最近旅行列表和清空历史按钮。用户可以一键清空所有访问历史。
记录访问时间函数
async function recordTripView(tripId) {
try {
// 获取旅行数据
const trip = await db.getTrip(tripId);
if (trip) {
// 更新最后访问时间
trip.lastViewedAt = new Date().toISOString();
// 保存到数据库
await db.updateTrip(trip);
// 更新最近旅行列表
loadRecentTrips();
// 通知原生层
if (window.cordova) {
cordova.exec(
(result) => console.log('View recorded:', result),
(error) => console.error('Record error:', error),
'RecentPlugin',
'onTripViewed',
[{ tripId: tripId, timestamp: Date.now() }]
);
}
}
} catch (error) {
console.error('Error recording trip view:', error);
}
}
这个函数在用户访问旅行时被调用,更新旅行的最后访问时间。函数还通知原生层记录访问事件,用于原生层的缓存更新。
加载最近旅行列表函数
async function loadRecentTrips() {
try {
// 从数据库查询所有旅行
const allTrips = await db.getAllTrips();
// 按最后访问时间排序(降序)
const recentTrips = allTrips
.filter(trip => trip.lastViewedAt)
.sort((a, b) => {
const timeA = new Date(a.lastViewedAt).getTime();
const timeB = new Date(b.lastViewedAt).getTime();
return timeB - timeA;
})
.slice(0, 20); // 只取前20条
// 处理空状态
if (recentTrips.length === 0) {
document.getElementById('emptyState').style.display = 'block';
document.getElementById('recentList').innerHTML = '';
return;
}
document.getElementById('emptyState').style.display = 'none';
// 渲染最近旅行列表
renderRecentList(recentTrips);
} catch (error) {
console.error('Error loading recent trips:', error);
showToast('加载最近旅行失败');
}
}
这个函数从数据库查询所有旅行,筛选出有访问时间的旅行,然后按访问时间降序排序。函数只取前 20 条记录,避免过多的 DOM 节点。
最近旅行列表渲染函数
function renderRecentList(trips) {
const container = document.getElementById('recentList');
container.innerHTML = '';
trips.forEach(trip => {
const recentElement = document.createElement('div');
recentElement.className = 'recent-item';
// 计算距离现在的时间差
const lastViewedTime = new Date(trip.lastViewedAt);
const timeAgo = getTimeAgoString(lastViewedTime);
recentElement.innerHTML = `
<div class="recent-header">
<h3>${trip.destination}</h3>
<span class="time-ago">${timeAgo}</span>
</div>
<div class="recent-body">
<p class="trip-description">${trip.description || '暂无描述'}</p>
<div class="trip-meta">
<span>📅 ${formatDate(trip.startDate)}</span>
<span>💰 ¥${trip.expense}</span>
</div>
</div>
<div class="recent-footer">
<button class="btn-small" onclick="navigateTo('trip-detail', ${trip.id})">
查看详情
</button>
<button class="btn-small" onclick="editTrip(${trip.id})">
编辑
</button>
</div>
`;
container.appendChild(recentElement);
});
}
最近旅行列表渲染函数为每个旅行创建一个 DOM 元素,并显示距离现在的时间差(如"2小时前"、"3天前"等)。这样用户可以快速了解旅行的访问时间。
时间差计算函数
function getTimeAgoString(date) {
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffMins = Math.floor(diffMs / 60000);
const diffHours = Math.floor(diffMs / 3600000);
const diffDays = Math.floor(diffMs / 86400000);
if (diffMins < 1) {
return '刚刚';
} else if (diffMins < 60) {
return `${diffMins}分钟前`;
} else if (diffHours < 24) {
return `${diffHours}小时前`;
} else if (diffDays < 30) {
return `${diffDays}天前`;
} else {
return formatDate(date);
}
}
时间差计算函数将时间戳转换为人类可读的格式,如"2小时前"、"3天前"等。这样提升了用户体验,用户可以快速了解旅行的访问时间。
清空访问历史函数
async function clearRecentHistory() {
if (!confirm('确定要清空所有访问历史吗?')) {
return;
}
try {
// 获取所有旅行
const allTrips = await db.getAllTrips();
// 清空所有旅行的访问时间
for (let trip of allTrips) {
trip.lastViewedAt = null;
await db.updateTrip(trip);
}
// 重新加载列表
loadRecentTrips();
showToast('访问历史已清空');
// 通知原生层
if (window.cordova) {
cordova.exec(
(result) => console.log('History cleared:', result),
(error) => console.error('Clear error:', error),
'RecentPlugin',
'onHistoryCleared',
[{ timestamp: Date.now() }]
);
}
} catch (error) {
console.error('Error clearing history:', error);
showToast('清空历史失败');
}
}
清空访问历史函数将所有旅行的 lastViewedAt 字段设置为 null,然后重新加载列表。函数还通知原生层清空缓存。
🔌 OpenHarmony 原生代码实现
最近旅行缓存插件
// RecentPlugin.ets
import { BusinessError } from '@ohos.base';
export class RecentPlugin {
private recentCache: Map<number, number> = new Map(); // tripId -> timestamp
private maxRecentCount: number = 20;
// 处理旅行访问事件
onTripViewed(args: any, callback: Function): void {
try {
const tripId = args[0].tripId;
const timestamp = args[0].timestamp;
// 更新缓存
this.recentCache.set(tripId, timestamp);
// 如果缓存超过限制,删除最旧的记录
if (this.recentCache.size > this.maxRecentCount) {
let oldestKey = null;
let oldestTime = Infinity;
this.recentCache.forEach((time, key) => {
if (time < oldestTime) {
oldestTime = time;
oldestKey = key;
}
});
if (oldestKey !== null) {
this.recentCache.delete(oldestKey);
}
}
callback({ success: true, message: '访问记录已更新' });
} catch (error) {
callback({ success: false, error: error.message });
}
}
// 处理历史清空事件
onHistoryCleared(args: any, callback: Function): void {
try {
this.recentCache.clear();
console.log('[Recent] History cleared');
callback({ success: true, message: '缓存已清空' });
} catch (error) {
callback({ success: false, error: error.message });
}
}
// 获取最近旅行列表
getRecentTrips(callback: Function): void {
try {
const recentTrips = Array.from(this.recentCache.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, this.maxRecentCount)
.map(([tripId, timestamp]) => ({ tripId, timestamp }));
callback({ success: true, data: recentTrips });
} catch (error) {
callback({ success: false, error: error.message });
}
}
}
最近旅行缓存插件在原生层维护一个访问历史缓存。缓存使用 Map 数据结构,存储旅行 ID 和访问时间戳。当缓存超过限制时,自动删除最旧的记录。
🕐 访问历史的应用场景
访问历史功能在很多应用中都很常见,如浏览器的历史记录、文件管理器的最近文件等。在旅行记录应用中,访问历史可以帮助用户快速回到最近查看的旅行。这对于经常编辑同一个旅行的用户特别有用。
访问历史还可以用于分析用户的行为。通过分析用户的访问历史,可以了解用户最关注的旅行,从而提供更好的推荐。
📈 时间戳的管理与优化
时间戳是访问历史的核心。每次用户访问旅行时,需要更新该旅行的最后访问时间。但是频繁的数据库更新会影响性能。可以使用批量更新或异步更新来优化性能。
时间戳的精度也需要考虑。如果精度太高,会导致数据库中有很多相似的时间戳。如果精度太低,用户无法区分最近访问的旅行。通常使用秒级精度就足够了。
🎯 最近旅行列表的个性化
最近旅行列表可以根据用户的偏好进行个性化。例如,可以根据用户的访问频率调整列表的长度。经常访问旅行的用户可能需要更长的列表,而很少访问旅行的用户可能只需要较短的列表。
最近旅行列表也可以根据用户的访问模式进行排序。除了按访问时间排序,还可以按访问频率排序,让用户最常访问的旅行显示在最前面。
🔄 访问历史的同步
如果应用支持多设备同步,访问历史也需要同步。用户在一个设备上访问旅行后,其他设备上的最近旅行列表应该相应更新。这需要实现跨设备的数据同步机制。
访问历史的同步也需要考虑冲突解决。如果用户在两个设备上同时访问不同的旅行,应该如何处理?通常可以使用时间戳来解决冲突,最新的访问时间优先。
🗑️ 访问历史的清理
访问历史会不断增长,需要定期清理。可以实现自动清理机制,删除超过一定时间(如 90 天)的访问记录。用户也应该能够手动清理访问历史。
清理访问历史时,需要小心不要删除重要的数据。应该只删除访问时间戳,而不是删除旅行本身。
💾 访问历史的存储
访问历史可以存储在本地数据库中,也可以存储在云端。本地存储速度快,但容量有限。云端存储容量大,但需要网络连接。
可以使用混合方案,将最近的访问历史存储在本地,较旧的访问历史存储在云端。这样可以兼顾性能和容量。
🔐 访问历史的隐私
访问历史可能包含用户的隐私信息。用户应该能够控制访问历史的可见性。例如,用户可以选择不记录某些旅行的访问历史,或者选择定期自动清理访问历史。
如果应用支持多用户,访问历史应该是用户私有的,其他用户无法看到。
📝 总结
最近旅行页面展示了如何在 Cordova 与 OpenHarmony 框架中实现一个访问历史管理系统。Web 层负责 UI 渲染和时间戳管理,原生层负责缓存管理和性能优化。通过时间戳和缓存机制,实现了高效的最近旅行列表展示。在实现过程中,需要重点关注时间戳管理、性能优化、隐私保护等方面,确保访问历史功能能够提供最佳的用户体验。
更多推荐

所有评论(0)