Skip to content

Commit

Permalink
feat: search history component
Browse files Browse the repository at this point in the history
  • Loading branch information
Away0x committed Aug 18, 2020
1 parent 1ef3a57 commit a45d537
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 23 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# react-cloud-music
# React-Cloud-Music 仿网易云音乐 WebApp

> 参考 https://github.com/sanyuan0704/react-cloud-music,升级为 TypeScript 版本
> 参考 `https://github.com/sanyuan0704/react-cloud-music`,升级为 TypeScript 版本
- 技术栈: typescript、react、react hooks、unstated-next、immer、styled-components ...
- [预览地址](http://cloudmusic.frontendgo.com)
- [组件文档地址](http://cloudmusic.frontendgo.com/storybook)

Expand Down
32 changes: 30 additions & 2 deletions src/containers/SearchContainer.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { useCallback } from 'react';
import { useCallback, useEffect } from 'react';
import { createContainer } from 'unstated-next';
import { useImmer } from 'use-immer';

import SearchHistoryStorage from 'services/storage/search-history';
import { getHotKeyWordsService, getSuggestListService, getResultSongsListService } from 'services';

export interface SearchState {
hotList: Data.HotKeyWordItem[];
suggestList: Data.SuggestData | null;
songsList: Data.SongListItem[];
historyList: string[];
loading: boolean;
}

Expand All @@ -16,6 +18,8 @@ interface SearchComputedState {}
interface SearchActions {
getHotKeyWords: () => Promise<void>;
getSuggestList: (query: string) => void;
deleteHistory: (query: string) => void;
cleanHistory: () => void;
}

type UseSearch = SearchState & SearchComputedState & SearchActions;
Expand All @@ -25,6 +29,7 @@ function useSearch(): UseSearch {
hotList: [],
suggestList: null,
songsList: [],
historyList: [],
loading: false,
});

Expand All @@ -47,6 +52,7 @@ function useSearch(): UseSearch {

getSuggestListService(query)
.then((data) => {
SearchHistoryStorage.set(query);
updateSearchState((state) => {
state.suggestList = data;
});
Expand All @@ -72,7 +78,29 @@ function useSearch(): UseSearch {
[updateSearchState],
);

return { ...searchState, getHotKeyWords, getSuggestList };
const deleteHistory = useCallback(
(query: string) => {
updateSearchState((state) => {
state.historyList = SearchHistoryStorage.remove(query);
});
},
[updateSearchState],
);

const cleanHistory = useCallback(() => {
SearchHistoryStorage.clean();
updateSearchState((state) => {
state.historyList = [];
});
}, [updateSearchState]);

useEffect(() => {
updateSearchState((state) => {
state.historyList = SearchHistoryStorage.get();
});
}, [searchState.songsList, searchState.suggestList, updateSearchState]);

return { ...searchState, getHotKeyWords, getSuggestList, deleteHistory, cleanHistory };
}

const SearchContainer = createContainer(useSearch);
Expand Down
74 changes: 59 additions & 15 deletions src/pages/Search/HotKeyList.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,77 @@
import React from 'react';
import React, { useCallback } from 'react';

import Scroll from 'components/Scroll';

import { ShortcutWrapper, HotKey } from './style';
import {
ShortcutWrapper,
HotKey,
HistoryWrapper,
HistoryText,
HistoryClear,
HistoryItem,
HistoryItemText,
HistoryItemIcon,
} from './style';

interface HotKeyListProps {
show?: boolean;
list?: Data.HotKeyWordItem[];
historyList?: string[];
onDeleteHistory?: (q: string) => void;
onCleanHistory?: () => void;
onItemClick?: (q: string) => void;
}

function HotKeyList({ show = true, list, onItemClick }: HotKeyListProps) {
function HotKeyList({ historyList, show = true, list, onItemClick, onDeleteHistory, onCleanHistory }: HotKeyListProps) {
const SearchHistoryList = useCallback(() => {
if (!historyList || !historyList.length) return null;

return (
<HistoryWrapper>
<h1>
<HistoryText>搜索历史</HistoryText>
<HistoryClear onClick={() => onCleanHistory && onCleanHistory()}>
<i className="iconfont">&#xe63d;</i>
</HistoryClear>
</h1>
{historyList.map((item) => {
return (
<HistoryItem key={item} onClick={() => onItemClick && onItemClick(item)}>
<HistoryItemText>{item}</HistoryItemText>
<HistoryItemIcon
onClick={(ev) => {
ev.stopPropagation();
onDeleteHistory && onDeleteHistory(item);
}}>
<i className="iconfont">&#xe600;</i>
</HistoryItemIcon>
</HistoryItem>
);
})}
</HistoryWrapper>
);
}, [historyList, onCleanHistory, onDeleteHistory, onItemClick]);

if (!list) return null;

return (
<ShortcutWrapper show={show}>
<Scroll>
<HotKey>
<h1>热门搜索</h1>
<ul>
{list.map((item) => {
return (
<li key={item.first} onClick={() => onItemClick && onItemClick(item.first)}>
<span>{item.first}</span>
</li>
);
})}
</ul>
</HotKey>
<div>
<HotKey>
<h1>热门搜索</h1>
<ul>
{list.map((item) => {
return (
<li key={item.first} onClick={() => onItemClick && onItemClick(item.first)}>
<span>{item.first}</span>
</li>
);
})}
</ul>
</HotKey>
<SearchHistoryList />
</div>
</Scroll>
</ShortcutWrapper>
);
Expand Down
21 changes: 19 additions & 2 deletions src/pages/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ import { useMount } from 'ahooks';

function Search() {
const history = useHistory();
const { loading, hotList, suggestList, songsList, getHotKeyWords, getSuggestList } = SearchContainer.useContainer();
const {
loading,
hotList,
suggestList,
songsList,
historyList,
getHotKeyWords,
getSuggestList,
deleteHistory,
cleanHistory,
} = SearchContainer.useContainer();

const subPageRef = useRef<SubPageHandlers>(null);
const [query, setQuery] = useState('');
Expand Down Expand Up @@ -54,7 +64,14 @@ function Search() {
header={<SearchBox newQuery={query} onSearch={onSearch} onBackButtonClick={closePage} />}>
<StyledSearch>
{/* 热门搜索 */}
<HotKeyList show={!query} list={hotList} onItemClick={handleHotKeyItemClick} />
<HotKeyList
show={!query}
list={hotList}
historyList={historyList}
onItemClick={handleHotKeyItemClick}
onDeleteHistory={deleteHistory}
onCleanHistory={cleanHistory}
/>
{/* 搜索结果 */}
<ResultList show={!!query} suggestList={suggestList} songsList={songsList} onItemClick={enterDetail} />
{loading && <Loading full />}
Expand Down
60 changes: 59 additions & 1 deletion src/pages/Search/style.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import styled from 'styled-components';

import { extendClick } from 'styles/mixins';

const StyledSearch = styled.div`
width: 100%;
height: 100%;
Expand Down Expand Up @@ -39,6 +41,62 @@ const HotKey = styled.div`
}
`;

const HistoryWrapper = styled.div`
position: relative;
margin: 0 20px;
h1 {
display: flex;
align-items: center;
height: 40px;
font-size: ${({ theme }) => theme.fontSizeM};
color: ${({ theme }) => theme.fontColorDescV2};
}
`;

const HistoryText = styled.span`
flex: 1;
`;

const HistoryClear = styled.span`
${extendClick()}
.iconfont {
font-size: ${({ theme }) => theme.fontSizeM};
color: ${({ theme }) => theme.fontColorDesc};
}
`;

const HistoryItem = styled.li`
display: flex;
align-items: center;
height: 40px;
overflow: hidden;
color: ${({ theme }) => theme.fontColorDescV2};
border-bottom: 1px solid ${({ theme }) => theme.borderColor};
`;

const HistoryItemText = styled.span`
flex: 1;
font-size: ${({ theme }) => theme.fontSizeS};
color: ${({ theme }) => theme.fontColorDesc};
`;

const HistoryItemIcon = styled.span`
${extendClick()}
.iconfont {
color: ${({ theme }) => theme.fontColorDesc};
}
`;

export default StyledSearch;

export { ShortcutWrapper, HotKey };
export {
ShortcutWrapper,
HotKey,
HistoryWrapper,
HistoryText,
HistoryClear,
HistoryItem,
HistoryItemText,
HistoryItemIcon,
};
65 changes: 65 additions & 0 deletions src/services/storage/search-history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* COMPONENT DOCUMENT
* author: wutong
* date: 2020/08/18
* desc: 搜索历史存储
*/

import Storage from 'aw-easy-storage';

import { LOCALSTROAGE_PREFIX } from 'config';

export default class SearchHistoryStorage {
private static readonly key = `${LOCALSTROAGE_PREFIX}searchhistory`;
private static storage = new Storage({
hasMeta: false,
});
private static MAX_LENGTH = 20;
private static tempStore: string[] | null = null;

public static get(): string[] {
if (this.tempStore) return this.tempStore;

const str = this.storage.getString(this.key) || '';
const data = str.split(',').filter((s) => !!s);

this.tempStore = data;
return data;
}

public static set(keyword: string): string[] {
keyword = keyword.trim();
let list = this.get();
if (!keyword) return list;

const index = list.indexOf(keyword);
if (index !== -1) {
list.splice(index, 1);
}
list.unshift(keyword);

if (list.length > this.MAX_LENGTH) list = list.slice(0, this.MAX_LENGTH);

this.tempStore = [...list];
this.storage.setString(this.key, list.join(','));

return this.tempStore;
}

public static remove(keyword: string): string[] {
const list = this.get();
const index = list.indexOf(keyword);
if (index !== -1) {
list.splice(index, 1);
}

this.tempStore = [...list];
this.storage.setString(this.key, list.join(','));

return this.tempStore;
}

public static clean() {
this.storage.remove(this.key);
this.tempStore = null;
}
}
2 changes: 1 addition & 1 deletion src/services/storage/token.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* COMPONENT DOCUMENT
* author: wutong
* date: 2020/05/18
* date: 2020/08/18
* desc: token 存储
*/
import { TOKEN_KEY } from 'config';
Expand Down

0 comments on commit a45d537

Please sign in to comment.