1. 项目背景与需求分析
在OpenHarmony生态中开发一个商城类应用时,用户评价功能是不可或缺的核心模块。这个功能看似简单,但实际开发中涉及到UI交互设计、数据存储、网络请求、状态管理等多个技术点的协同工作。基于React Native for OpenHarmony(简称rn_for_openharmony)框架实现评价功能,既要考虑跨平台特性,又要兼顾OpenHarmony系统的特有API调用。
评价模块的典型使用场景包括:
- 用户购买商品后提交使用反馈
- 浏览其他用户的真实评价作为购物参考
- 商家通过评价改进商品和服务质量
2. 技术架构设计
2.1 整体方案选型
采用分层架构设计:
code复制UI层 → 业务逻辑层 → 数据访问层
↘ ↘ ↙
Native能力桥接层
2.2 关键技术栈
- 前端框架:React Native for OpenHarmony 0.71 LTS
- 状态管理:Zustand(轻量级解决方案)
- 网络请求:axios + 自定义拦截器
- 本地存储:@react-native-async-storage/async-storage
- 富文本编辑器:react-native-richeditor
- 图片处理:react-native-image-picker
3. 核心功能实现
3.1 评价表单UI构建
创建可复用的评价组件:
jsx复制const RatingInput = ({ initialValue = 0, onChange }) => {
const [rating, setRating] = useState(initialValue);
const handlePress = (newRating) => {
setRating(newRating);
onChange(newRating);
};
return (
<View style={styles.ratingContainer}>
{[1, 2, 3, 4, 5].map((star) => (
<TouchableOpacity key={star} onPress={() => handlePress(star)}>
<Image
source={star <= rating ? filledStar : emptyStar}
style={styles.starIcon}
/>
</TouchableOpacity>
))}
</View>
);
};
3.2 富文本编辑实现
集成富文本编辑器处理多格式评价内容:
jsx复制<RichEditor
ref={editorRef}
initialContentHTML={initialContent}
onChange={handleContentChange}
placeholder="写下您的真实体验..."
androidHardwareAccelerationDisabled={true}
style={styles.editor}
/>
3.3 图片上传处理
实现多图上传功能的关键代码:
javascript复制const handleImageUpload = async () => {
try {
const result = await ImagePicker.launchImageLibrary({
mediaType: 'photo',
quality: 0.8,
selectionLimit: 5,
});
if (!result.didCancel) {
const compressedImages = await Promise.all(
result.assets.map(async (asset) => {
const compressedFile = await compressImage(asset.uri);
return {
uri: compressedFile.uri,
name: `eval_${Date.now()}.jpg`,
type: 'image/jpeg',
};
})
);
setAttachments([...attachments, ...compressedImages]);
}
} catch (error) {
console.error('Image picker error:', error);
}
};
4. 数据持久化与同步
4.1 本地草稿保存
利用AsyncStorage实现自动保存草稿:
javascript复制const saveDraft = debounce(async (content) => {
try {
await AsyncStorage.setItem(
`eval_draft_${productId}`,
JSON.stringify({
content,
rating,
attachments: attachments.map(item => item.uri),
})
);
} catch (e) {
console.warn('Failed to save draft', e);
}
}, 2000);
4.2 网络请求封装
评价提交API请求示例:
javascript复制const submitEvaluation = async () => {
const formData = new FormData();
formData.append('product_id', productId);
formData.append('rating', rating);
formData.append('content', content);
attachments.forEach((file) => {
formData.append('images', file);
});
try {
const response = await api.post('/evaluations', formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
if (response.data.success) {
await AsyncStorage.removeItem(`eval_draft_${productId}`);
navigation.goBack();
}
} catch (error) {
console.error('Submission failed:', error);
throw error;
}
};
5. 性能优化实践
5.1 图片压缩算法
采用分层压缩策略:
- 分辨率限制:长边不超过2000px
- 质量压缩:JPEG质量设置为75%
- 渐进式加载:大图显示缩略图
javascript复制const compressImage = async (uri) => {
const result = await ImageResizer.createResizedImage(
uri,
2000, // maxWidth
2000, // maxHeight
'JPEG',
75, // quality
0, // rotation
null, // outputPath
false, // keepMeta
{ // options
mode: 'contain',
onlyScaleDown: true,
}
);
return result;
};
5.2 渲染性能优化
使用React.memo优化组件重渲染:
jsx复制const MemoizedRatingItem = React.memo(({ item }) => (
<View style={styles.evaluationItem}>
<Text style={styles.userName}>{item.user.name}</Text>
<RatingDisplay value={item.rating} />
<Text style={styles.content}>{item.content}</Text>
{item.images.length > 0 && (
<ImageGrid images={item.images} />
)}
</View>
));
6. 异常处理与用户体验
6.1 网络异常处理
实现自动重试机制:
javascript复制const api = axios.create({
timeout: 10000,
});
api.interceptors.response.use(null, async (error) => {
const config = error.config;
if (!config || !config.retry) {
return Promise.reject(error);
}
config.__retryCount = config.__retryCount || 0;
if (config.__retryCount >= config.retry) {
return Promise.reject(error);
}
config.__retryCount += 1;
const delay = new Promise((resolve) => {
setTimeout(() => resolve(), config.retryDelay || 1000);
});
await delay;
return api(config);
});
6.2 用户引导设计
评价提交状态机管理:
javascript复制const [submitState, setSubmitState] = useState('idle'); // idle | submitting | success | error
const handleSubmit = async () => {
try {
setSubmitState('submitting');
await submitEvaluation();
setSubmitState('success');
setTimeout(() => navigation.goBack(), 1500);
} catch (e) {
setSubmitState('error');
}
};
7. 测试关键点
7.1 单元测试重点
评价组件测试用例示例:
javascript复制describe('RatingInput', () => {
it('should display correct star rating', () => {
const mockFn = jest.fn();
const { getAllByTestId } = render(
<RatingInput initialValue={3} onChange={mockFn} />
);
const stars = getAllByTestId('rating-star');
expect(stars[0].props.source).toBe(filledStar);
expect(stars[4].props.source).toBe(emptyStar);
});
it('should call onChange when star pressed', () => {
const mockFn = jest.fn();
const { getAllByTestId } = render(
<RatingInput onChange={mockFn} />
);
fireEvent.press(getAllByTestId('rating-star')[2]);
expect(mockFn).toHaveBeenCalledWith(3);
});
});
7.2 端到端测试场景
关键用户旅程测试:
- 进入商品详情页
- 点击"写评价"按钮
- 选择星级并输入文本
- 添加多张图片
- 提交评价
- 验证评价显示在列表中
8. 项目部署注意事项
8.1 构建配置优化
修改metro.config.js提升构建性能:
javascript复制module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
}),
},
maxWorkers: 4,
};
8.2 资源文件处理
评价图片存储方案设计:
- 开发环境:使用本地mock服务器
- 生产环境:对接对象存储服务
- 缓存策略:CDN加速 + 客户端缓存
9. 扩展功能思路
9.1 评价互动功能
实现评价回复功能的数据结构:
javascript复制interface Evaluation {
id: string;
user: UserInfo;
rating: number;
content: string;
images: string[];
replies: Reply[];
createdAt: string;
}
interface Reply {
id: string;
user: UserInfo;
content: string;
isSeller: boolean;
createdAt: string;
}
9.2 智能评价分析
基于NLP的评价情感分析集成:
javascript复制const analyzeSentiment = async (text) => {
const result = await NaturalLanguage.sentimentAnalysis(text, {
language: 'zh',
});
return {
score: result.score,
tags: result.tags,
};
};
在项目开发过程中,我发现OpenHarmony的文件系统访问权限需要特别处理,特别是在处理图片附件时。实际测试中发现,直接访问相册路径在某些设备上会受限,需要通过特定的URI转换器处理。这提醒我们在跨平台开发中,即使使用React Native这样的框架,也需要充分测试各平台的特性差异。