비즈니스 요구사항 및 데이터 구조
시사 정보 아카이빙 기능은 교육용 애플리케이션에서 실시간 데이터와 학습 자료를 연결하는 핵심 모듈입니다. 본 기술 문서에서는 OpenHarmony 및 HarmonyOS 환경에서 ArkUI 프레임워크를 사용하여 날짜별 시사 정보 목록, 카테고리 필터링, 키워드 검색, 즐겨찾기 기능 그리고 상세 정보 모달 오버레이를 구현하는 기술적 접근 방식을 다루겠습니다.
해당 컴포넌트는 다음 기능을 제공하도록 설계되었습니다.
- 当日(당일) 시사 콘텐츠 렌더링 및 날짜 포맷팅
- 도메인별 필터링 (정치, 경제, 문화, 철학)
- 다중 필드 키워드 검색
- 사용자 정의 즐겨찾기 상태 관리
- 카드형 UI 클릭 시 모달 기반 상세 뷰 제공
데이터 모델 정의
아카이빙될 시사 자료의 구조를 타입 안전하게 정의합니다. 메타데이터, 본문, 미디어 자산 및 상태 플래그를 포함합니다.
export interface NewsArchiveEntry {
entryId: number;
headline: string;
summary: string;
bodyText: string;
mediaAsset: string;
topicDomain: string;
targetLevel: string;
publishDate: string;
keywords: string[];
isBookmarked: boolean;
viewCount: number;
}
컴포넌트 상태 관리
ArkUI의 반응형 시스템을 활용하여 목록 데이터, 필터 조건, 검색어, 모달 가시성 등을 @State 데코레이터로 선언합니다.
@State archiveEntries: NewsArchiveEntry[] = mockNewsData;
@State activeDomain: string = '전체';
@State formattedDate: string = '';
@State activeEntry: NewsArchiveEntry | undefined = undefined;
@State isModalVisible: boolean = false;
@State isModalAnimating: boolean = false;
@State bookmarkedIds: number[] = [];
@State searchQuery: string = '';
@State featuredEntry: NewsArchiveEntry | undefined = undefined;
수명 주기 및 초기 데이터 바인딩
컴포넌트가 마운트될 때 aboutToAppear 훅을 사용하여 현재 날짜를 포맷팅하고, 해당 날짜에 맞는 추천 자료를 매칭합니다.
aboutToAppear(): void {
const currentDate = new Date();
const y = currentDate.getFullYear();
const m = String(currentDate.getMonth() + 1).padStart(2, '0');
const d = String(currentDate.getDate()).padStart(2, '0');
this.formattedDate = `${y}-${m}-${d}`;
this.featuredEntry = this.fetchFeaturedEntry();
}
다중 조건 필터링 알고리즘
카테고리 도메인과 텍스트 검색어를 동시에 처리하는 필터링 로직을 구현합니다. 검색어는 제목, 요약, 본문, 키워드를 모두 포함하는 통합 텍스트 스트림에서 매칭됩니다.
computeFilteredEntries(): NewsArchiveEntry[] {
return this.archiveEntries.filter((entry: NewsArchiveEntry) => {
const matchesDomain = this.activeDomain === '전체' || entry.topicDomain === this.activeDomain;
if (!matchesDomain) return false;
if (this.searchQuery.trim().length === 0) return true;
const lowerQuery = this.searchQuery.toLowerCase();
const searchableText = [
entry.headline,
entry.summary,
entry.bodyText,
...entry.keywords
].join(' ').toLowerCase();
return searchableText.includes(lowerQuery);
});
}
당일 콘텐츠 매칭
현재 날짜와 정확히 일치하는 자료를 탐색합니다. 만약 당일 자료가 존재하지 않는 경우, 폴백(Fallback)으로 목록의 첫 번째 자료를 반환하여 UI가 비어있는 것을 방지합니다.
fetchFeaturedEntry(): NewsArchiveEntry | undefined {
return this.archiveEntries.find((entry: NewsArchiveEntry) => entry.publishDate === this.formattedDate)
?? (this.archiveEntries.length > 0 ? this.archiveEntries[0] : undefined);
}
상태 업데이트 및 모달 오버레이 제어
즐겨찾기 기능은 배열의 불변성을 유지하면서 ArkUI의 상태 변경 감지를 정확히 트리거해야 합니다. 기존 ID를 제외하거나 새로운 ID를 추가하는 방식으로 상태를 재할당합니다.
handleBookmarkToggle(entryId: number): void {
const exists = this.bookmarkedIds.includes(entryId);
this.bookmarkedIds = exists
? this.bookmarkedIds.filter((id: number) => id !== entryId)
: [...this.bookmarkedIds, entryId];
}
상세 정보 모달은 DOM 마운트 상태와 CSS 애니메이션 상태를 분리하여 제어합니다. 모달을 닫을 때는 애니메이션이 완료된 후 실제 컴포넌트를 언마운트하여 리소스를 해제합니다.
presentDetailView(entry: NewsArchiveEntry): void {
this.activeEntry = entry;
this.isModalVisible = true;
setTimeout(() => {
this.isModalAnimating = true;
}, 16);
}
dismissDetailView(): void {
animateTo({ duration: 250, curve: Curve.EaseOut }, () => {
this.isModalAnimating = false;
});
setTimeout(() => {
this.isModalVisible = false;
this.activeEntry = undefined;
}, 250);
}