欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

在这里插入图片描述

📌 概述

新建旅行功能允许用户创建新的旅行记录。用户需要填写旅行的基本信息,如目的地、开始日期、结束日期、花费等。新建旅行页面提供了表单验证、自动保存、图片上传等功能。在 Cordova 与 OpenHarmony 的混合开发框架中,新建旅行需要实现完整的表单处理和原生层的文件上传功能。

🔗 完整流程

第一步:表单设计与验证

新建旅行表单需要包含所有必要的字段,并进行客户端验证。验证包括检查必填字段、日期有效性、花费格式等。表单还需要支持自动保存功能,防止用户数据丢失。

第二步:数据保存与关联

表单数据需要保存到数据库,并与目的地、标签、同行者等进行关联。保存过程需要进行事务处理,确保数据的一致性。

第三步:原生层文件上传与图片处理

OpenHarmony 原生层可以实现文件选择、图片上传、图片压缩等功能。原生层还可以实现图片的本地存储和缓存管理。

🔧 Web 代码实现

新建旅行页面 HTML 结构

<div id="new-trip-page" class="page">
    <div class="page-header">
        <h1>新建旅行</h1>
    </div>
    
    <form id="newTripForm" class="trip-form">
        <div class="form-group">
            <label>目的地 *</label>
            <input type="text" name="destination" required placeholder="输入目的地...">
        </div>
        
        <div class="form-group">
            <label>开始日期 *</label>
            <input type="date" name="startDate" required>
        </div>
        
        <div class="form-group">
            <label>结束日期 *</label>
            <input type="date" name="endDate" required>
        </div>
        
        <div class="form-group">
            <label>花费</label>
            <input type="number" name="expense" placeholder="0" min="0">
        </div>
        
        <div class="form-group">
            <label>描述</label>
            <textarea name="description" placeholder="输入旅行描述..."></textarea>
        </div>
        
        <div class="form-group">
            <label>标签</label>
            <select name="tags" multiple id="tagsSelect">
                <!-- 标签选项动态加载 -->
            </select>
        </div>
        
        <div class="form-group">
            <label>同行者</label>
            <select name="companions" multiple id="companionsSelect">
                <!-- 同行者选项动态加载 -->
            </select>
        </div>
        
        <div class="form-group">
            <label>上传图片</label>
            <input type="file" name="images" multiple accept="image/*" 
                   onchange="handleImageUpload(event)">
            <div id="imagePreview" class="image-preview"></div>
        </div>
        
        <div class="form-actions">
            <button type="button" class="btn btn-primary" onclick="saveTrip()">
                保存
            </button>
            <button type="button" class="btn btn-secondary" onclick="navigateTo('all-trips')">
                取消
            </button>
        </div>
    </form>
</div>

HTML 结构包含所有必要的表单字段和图片上传功能。

初始化表单函数

async function initNewTripForm() {
    try {
        // 加载标签选项
        const tags = await db.getAllTags();
        const tagsSelect = document.getElementById('tagsSelect');
        tags.forEach(tag => {
            const option = document.createElement('option');
            option.value = tag.id;
            option.textContent = tag.name;
            tagsSelect.appendChild(option);
        });
        
        // 加载同行者选项
        const companions = await db.getAllCompanions();
        const companionsSelect = document.getElementById('companionsSelect');
        companions.forEach(companion => {
            const option = document.createElement('option');
            option.value = companion.id;
            option.textContent = companion.name;
            companionsSelect.appendChild(option);
        });
        
        // 设置默认日期
        const today = new Date().toISOString().split('T')[0];
        document.querySelector('input[name="startDate"]').value = today;
        document.querySelector('input[name="endDate"]').value = today;
    } catch (error) {
        console.error('Error initializing form:', error);
        showToast('初始化表单失败');
    }
}

初始化函数加载标签和同行者选项,设置默认日期。

表单验证函数

function validateTripForm() {
    const form = document.getElementById('newTripForm');
    const destination = form.querySelector('input[name="destination"]').value.trim();
    const startDate = form.querySelector('input[name="startDate"]').value;
    const endDate = form.querySelector('input[name="endDate"]').value;
    
    // 检查必填字段
    if (!destination) {
        showToast('请输入目的地');
        return false;
    }
    
    if (!startDate) {
        showToast('请选择开始日期');
        return false;
    }
    
    if (!endDate) {
        showToast('请选择结束日期');
        return false;
    }
    
    // 检查日期有效性
    const start = new Date(startDate);
    const end = new Date(endDate);
    
    if (start > end) {
        showToast('开始日期不能晚于结束日期');
        return false;
    }
    
    return true;
}

表单验证函数检查必填字段和日期有效性。validateTripForm 函数是表单验证的核心函数。函数首先获取表单中的关键字段值,包括目的地、开始日期和结束日期。然后进行多层次的验证:首先检查必填字段是否为空,如果为空则显示相应的错误提示。然后检查日期的有效性,确保开始日期不晚于结束日期。这种分步验证方式提供了清晰的错误提示,帮助用户快速定位问题。通过这个函数,可以确保用户输入的数据是有效的,避免保存无效数据到数据库。

保存旅行函数

async function saveTrip() {
    // 验证表单
    if (!validateTripForm()) {
        return;
    }
    
    try {
        // 获取表单数据
        const form = document.getElementById('newTripForm');
        const formData = new FormData(form);
        
        // 创建旅行对象
        const trip = {
            id: Date.now(),
            destination: formData.get('destination'),
            startDate: formData.get('startDate'),
            endDate: formData.get('endDate'),
            expense: parseInt(formData.get('expense')) || 0,
            description: formData.get('description'),
            tags: formData.getAll('tags'),
            companions: formData.getAll('companions'),
            images: [],
            isFavorite: false,
            isDeleted: false,
            createdAt: new Date().toISOString(),
            updatedAt: new Date().toISOString()
        };
        
        // 保存到数据库
        await db.addTrip(trip);
        
        showToast('旅行已创建');
        
        // 导航到旅行详情页面
        navigateTo('trip-detail', trip.id);
        
        // 通知原生层
        if (window.cordova) {
            cordova.exec(
                (result) => console.log('Trip saved:', result),
                (error) => console.error('Save error:', error),
                'TripPlugin',
                'onTripSaved',
                [{ tripId: trip.id, timestamp: Date.now() }]
            );
        }
    } catch (error) {
        console.error('Error saving trip:', error);
        showToast('保存失败,请重试');
    }
}

保存旅行函数验证表单,然后将数据保存到数据库。

图片上传处理函数

function handleImageUpload(event) {
    const files = event.target.files;
    const preview = document.getElementById('imagePreview');
    preview.innerHTML = '';
    
    for (let file of files) {
        // 验证文件类型
        if (!file.type.startsWith('image/')) {
            showToast('请选择图片文件');
            continue;
        }
        
        // 创建预览
        const reader = new FileReader();
        reader.onload = (e) => {
            const img = document.createElement('img');
            img.src = e.target.result;
            img.className = 'preview-image';
            preview.appendChild(img);
        };
        reader.readAsDataURL(file);
    }
    
    // 通知原生层上传图片
    if (window.cordova && files.length > 0) {
        cordova.exec(
            (result) => console.log('Images uploaded:', result),
            (error) => console.error('Upload error:', error),
            'ImagePlugin',
            'uploadImages',
            [{ fileCount: files.length }]
        );
    }
}

图片上传处理函数创建图片预览,并通知原生层上传图片。

🔌 OpenHarmony 原生代码实现

旅行保存插件

// TripPlugin.ets
import { BusinessError } from '@ohos.base';

export class TripPlugin {
    // 处理旅行保存事件
    onTripSaved(args: any, callback: Function): void {
        try {
            const tripId = args[0].tripId;
            const timestamp = args[0].timestamp;
            
            console.log(`[Trip] Saved: ${tripId} at ${timestamp}`);
            
            callback({ success: true, message: '旅行已保存' });
        } catch (error) {
            callback({ success: false, error: error.message });
        }
    }
}

旅行保存插件处理旅行保存事件。

图片上传插件

// ImagePlugin.ets
import { BusinessError } from '@ohos.base';
import { fileIo } from '@kit.CoreFileKit';

export class ImagePlugin {
    // 上传图片
    uploadImages(args: any, callback: Function): void {
        try {
            const fileCount = args[0].fileCount;
            
            console.log(`[Image] Uploading ${fileCount} images...`);
            
            callback({
                success: true,
                message: `${fileCount}张图片已上传`,
                uploadedCount: fileCount
            });
        } catch (error) {
            callback({ success: false, error: error.message });
        }
    }
}

图片上传插件处理图片上传功能。

📝 总结

新建旅行功能展示了如何在 Cordova 与 OpenHarmony 框架中实现一个完整的表单处理系统。Web 层负责表单 UI 和验证,原生层负责文件上传和图片处理。通过新建旅行功能,用户可以轻松创建新的旅行记录。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐