编辑影片 - Cordova 与 OpenHarmony 混合开发实战
摘要:MovieTracker应用的编辑影片模块支持用户修改已有影片信息,包括标题、导演、评分等。该模块基于Cordova和OpenHarmony实现,主要功能包括:加载影片数据、表单编辑、数据验证和保存更新。编辑流程分为三个步骤:加载影片数据、表单交互编辑、数据验证与保存。Web端实现包含HTML表单结构和JavaScript逻辑,通过保存原始数据、跟踪修改字段,实现高效的数据更新。
欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

📌 模块概述
编辑影片模块是MovieTracker应用中用于修改已有影片信息的功能。用户可以编辑影片的各种信息,如标题、导演、评分、描述等。编辑功能与添加影片功能类似,但需要预加载现有的影片数据,并在保存时进行更新而不是创建新记录。
该模块的主要功能包括:加载影片数据、编辑表单、数据验证、海报更新、保存更改等。通过Cordova框架与OpenHarmony原生能力的结合,实现了完整的影片编辑流程。
编辑影片需要处理数据的加载和更新,同时需要跟踪哪些字段被修改,以便只更新改变的字段。
🔗 完整流程
第一步:影片数据加载
当用户打开编辑影片页面时,首先需要从数据库中加载要编辑的影片数据。加载过程包括获取影片的基本信息、分类、标签、海报等。
加载完成后需要将数据填充到表单中,使用户能够看到当前的影片信息。同时需要记录原始数据,以便在用户取消编辑时恢复原始状态。
第二步:表单编辑与交互
用户在表单中修改影片信息。编辑过程中需要实时验证输入数据,提供及时的反馈。同时需要跟踪哪些字段被修改,以便在保存时只更新改变的字段。
编辑过程需要支持撤销操作,用户可以恢复之前的修改。同时需要提供保存和取消按钮,用户可以选择保存修改或放弃修改。
第三步:数据验证与保存
在保存修改前需要进行数据验证,确保修改后的数据仍然有效。验证失败时需要显示错误消息,告知用户具体的错误位置。
验证成功后将修改保存到数据库,并显示成功消息。保存完成后可以返回影片详情页面或影片列表页面。
🔧 Web代码实现
编辑影片HTML结构
<div id="edit-movie-page" class="page">
<div class="page-header">
<h2>编辑影片</h2>
</div>
<form id="edit-movie-form" class="movie-form">
<div class="form-section">
<h3>基本信息</h3>
<div class="form-group">
<label>影片标题 *</label>
<input type="text" id="edit-movie-title" placeholder="请输入影片标题" class="form-input" required>
</div>
<div class="form-group">
<label>导演 *</label>
<input type="text" id="edit-movie-director" placeholder="请输入导演名称" class="form-input" required>
</div>
<div class="form-group">
<label>演员</label>
<input type="text" id="edit-movie-actors" placeholder="多个演员用逗号分隔" class="form-input">
</div>
<div class="form-group">
<label>年份 *</label>
<input type="number" id="edit-movie-year" placeholder="请输入年份" class="form-input" required>
</div>
</div>
<div class="form-section">
<h3>分类与标签</h3>
<div class="form-group">
<label>分类 *</label>
<select id="edit-movie-category" class="form-select" required></select>
</div>
<div class="form-group">
<label>标签</label>
<div id="edit-movie-tags" class="tags-select"></div>
</div>
</div>
<div class="form-section">
<h3>评分与描述</h3>
<div class="form-group">
<label>评分</label>
<input type="number" id="edit-movie-rating" placeholder="1-10" min="1" max="10" step="0.5" class="form-input">
</div>
<div class="form-group">
<label>描述</label>
<textarea id="edit-movie-description" placeholder="请输入影片描述" class="form-textarea"></textarea>
</div>
</div>
<div class="form-section">
<h3>海报与状态</h3>
<div class="form-group">
<label>海报</label>
<input type="file" id="edit-movie-poster" accept="image/*" class="form-input">
<div id="edit-poster-preview" class="poster-preview"></div>
</div>
<div class="form-group">
<label>状态 *</label>
<select id="edit-movie-status" class="form-select" required>
<option value="watchlist">想看</option>
<option value="watched">已看</option>
</select>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">保存修改</button>
<button type="button" class="btn btn-secondary" onclick="cancelEdit()">取消</button>
</div>
</form>
</div>
这个HTML结构与添加影片页面类似,但用于编辑现有影片。所有输入字段都有相应的ID前缀"edit-"以区分。
影片数据加载与编辑
let currentEditingMovieId = null;
let originalMovieData = null;
async function loadMovieForEdit(movieId) {
try {
currentEditingMovieId = movieId;
const movie = await db.getMovie(movieId);
if (!movie) {
showError('影片不存在');
return;
}
// 保存原始数据
originalMovieData = JSON.parse(JSON.stringify(movie));
// 加载分类
const categories = await db.getAllCategories();
const categorySelect = document.getElementById('edit-movie-category');
categorySelect.innerHTML = '';
categories.forEach(cat => {
const option = document.createElement('option');
option.value = cat.id;
option.textContent = cat.name;
categorySelect.appendChild(option);
});
// 加载标签
const tags = await db.getAllTags();
const tagsContainer = document.getElementById('edit-movie-tags');
tagsContainer.innerHTML = '';
tags.forEach(tag => {
const label = document.createElement('label');
label.className = 'tag-checkbox-label';
const isSelected = movie.tags && movie.tags.includes(tag.id);
label.innerHTML = `
<input type="checkbox" class="tag-checkbox" value="${tag.id}" ${isSelected ? 'checked' : ''}>
<span>${tag.name}</span>
`;
tagsContainer.appendChild(label);
});
// 填充表单数据
document.getElementById('edit-movie-title').value = movie.title;
document.getElementById('edit-movie-director').value = movie.director;
document.getElementById('edit-movie-actors').value = movie.actors || '';
document.getElementById('edit-movie-year').value = movie.year;
document.getElementById('edit-movie-category').value = movie.categoryId;
document.getElementById('edit-movie-rating').value = movie.rating || '';
document.getElementById('edit-movie-description').value = movie.description || '';
document.getElementById('edit-movie-status').value = movie.status;
// 显示海报预览
if (movie.poster) {
const preview = document.getElementById('edit-poster-preview');
preview.innerHTML = `<img src="${movie.poster}" alt="海报预览">`;
}
// 绑定表单提交事件
document.getElementById('edit-movie-form').addEventListener('submit', handleEditMovieSubmit);
// 绑定海报上传事件
document.getElementById('edit-movie-poster').addEventListener('change', handleEditPosterUpload);
} catch (error) {
console.error('加载影片失败:', error);
showError('加载影片失败');
}
}
async function handleEditMovieSubmit(event) {
event.preventDefault();
// 验证表单
const errors = validateEditMovieForm();
if (errors.length > 0) {
showError(errors.join('\n'));
return;
}
try {
const updatedMovie = {
title: document.getElementById('edit-movie-title').value,
director: document.getElementById('edit-movie-director').value,
actors: document.getElementById('edit-movie-actors').value,
year: parseInt(document.getElementById('edit-movie-year').value),
categoryId: parseInt(document.getElementById('edit-movie-category').value),
rating: parseFloat(document.getElementById('edit-movie-rating').value) || null,
description: document.getElementById('edit-movie-description').value,
status: document.getElementById('edit-movie-status').value,
poster: document.getElementById('edit-movie-poster').dataset.url || originalMovieData.poster,
tags: getSelectedEditTags(),
updatedDate: new Date().toISOString()
};
await db.updateMovie(currentEditingMovieId, updatedMovie);
showSuccess('影片已更新');
// 返回影片详情页面
setTimeout(() => {
app.navigateTo('movie-detail', currentEditingMovieId);
}, 1000);
} catch (error) {
console.error('更新影片失败:', error);
showError('更新影片失败');
}
}
function validateEditMovieForm() {
const errors = [];
const title = document.getElementById('edit-movie-title').value.trim();
if (!title) {
errors.push('影片标题不能为空');
}
const director = document.getElementById('edit-movie-director').value.trim();
if (!director) {
errors.push('导演不能为空');
}
const year = parseInt(document.getElementById('edit-movie-year').value);
if (!year || year < 1900 || year > new Date().getFullYear() + 5) {
errors.push('年份无效');
}
const rating = parseFloat(document.getElementById('edit-movie-rating').value);
if (rating && (rating < 1 || rating > 10)) {
errors.push('评分必须在1-10之间');
}
return errors;
}
function getSelectedEditTags() {
const checkboxes = document.querySelectorAll('#edit-movie-tags .tag-checkbox:checked');
return Array.from(checkboxes).map(cb => parseInt(cb.value));
}
function cancelEdit() {
if (confirm('确定要放弃修改吗?')) {
app.navigateTo('movie-detail', currentEditingMovieId);
}
}
这个函数实现了影片编辑的完整流程。loadMovieForEdit()加载影片数据并填充表单,handleEditMovieSubmit()处理表单提交并保存修改。
海报更新处理
function handleEditPosterUpload(event) {
const file = event.target.files[0];
if (!file) return;
if (!file.type.startsWith('image/')) {
showError('请选择图片文件');
return;
}
if (file.size > 5 * 1024 * 1024) {
showError('图片大小不能超过5MB');
return;
}
const reader = new FileReader();
reader.onload = function(e) {
const preview = document.getElementById('edit-poster-preview');
preview.innerHTML = `<img src="${e.target.result}" alt="海报预览">`;
document.getElementById('edit-movie-poster').dataset.url = e.target.result;
};
reader.readAsDataURL(file);
}
这个函数处理海报的更新和预览。
🔌 OpenHarmony原生代码
编辑影片插件
// EditMoviePlugin.ets
import { webview } from '@kit.ArkWeb';
import { common } from '@kit.AbilityKit';
export class EditMoviePlugin {
private context: common.UIAbilityContext;
constructor(context: common.UIAbilityContext) {
this.context = context;
}
public registerEditMovie(controller: webview.WebviewController): void {
controller.registerJavaScriptProxy({
object: new EditMovieBridge(),
name: 'editMovieNative',
methodList: ['trackChanges', 'validateChanges']
});
}
}
这个OpenHarmony原生插件为编辑影片提供了变更跟踪和验证功能。
变更跟踪实现
export class EditMovieBridge {
public trackChanges(originalJson: string, modifiedJson: string): string {
try {
const original = JSON.parse(originalJson);
const modified = JSON.parse(modifiedJson);
const changes: any = {};
Object.keys(modified).forEach(key => {
if (JSON.stringify(original[key]) !== JSON.stringify(modified[key])) {
changes[key] = {
old: original[key],
new: modified[key]
};
}
});
return JSON.stringify({
hasChanges: Object.keys(changes).length > 0,
changes: changes,
changedFields: Object.keys(changes)
});
} catch (error) {
return JSON.stringify({
error: error.message
});
}
}
public validateChanges(changesJson: string): string {
try {
const changes = JSON.parse(changesJson);
const errors: string[] = [];
if (changes.title && !changes.title.new) {
errors.push('影片标题不能为空');
}
if (changes.director && !changes.director.new) {
errors.push('导演不能为空');
}
if (changes.year && changes.year.new < 1900) {
errors.push('年份无效');
}
return JSON.stringify({
valid: errors.length === 0,
errors: errors
});
} catch (error) {
return JSON.stringify({
valid: false,
error: error.message
});
}
}
}
这个类实现了变更跟踪和验证功能。trackChanges()比较原始数据和修改后的数据,返回所有变更。validateChanges()验证变更的有效性。
Web-Native通信
调用原生变更跟踪
async function trackAndValidateChanges() {
try {
const modifiedMovie = {
title: document.getElementById('edit-movie-title').value,
director: document.getElementById('edit-movie-director').value,
year: parseInt(document.getElementById('edit-movie-year').value),
rating: parseFloat(document.getElementById('edit-movie-rating').value)
};
if (window.editMovieNative) {
const trackResult = window.editMovieNative.trackChanges(
JSON.stringify(originalMovieData),
JSON.stringify(modifiedMovie)
);
const result = JSON.parse(trackResult);
if (result.hasChanges) {
console.log('变更字段:', result.changedFields);
const validateResult = window.editMovieNative.validateChanges(
JSON.stringify(result.changes)
);
const validation = JSON.parse(validateResult);
if (!validation.valid) {
showError(validation.errors.join('\n'));
return false;
}
}
}
return true;
} catch (error) {
console.error('变更跟踪失败:', error);
return false;
}
}
这个函数展示了如何调用OpenHarmony原生的变更跟踪功能。在保存修改前进行变更跟踪和验证。
📝 总结
编辑影片模块展示了Cordova与OpenHarmony混合开发中的数据加载、修改跟踪和验证功能。通过Web层提供完整的编辑表单界面,同时利用OpenHarmony原生能力进行变更跟踪和验证。
在实现这个模块时,需要注意数据的加载和填充、变更的跟踪、以及用户体验的流畅性。通过合理的架构设计,可以构建出高效、易用的影片编辑功能。
更多推荐
所有评论(0)