跳转至

Building Search Input

SearchInput.tsx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import { Input, InputGroup, InputLeftElement } from "@chakra-ui/react";
import { BsSearch } from "react-icons/bs";

const SearchInput = () => {
    return (
        <InputGroup>
            <InputLeftElement children={<BsSearch />} />
            <Input
                borderRadius={20}
                placeholder="Search games..."
                variant="filled"
            />
        </InputGroup>
    );
};

export default SearchInput;

添加到 NavBar.tsx,其中 <HStack> 删除了 justifyContent="space-between",因为现在添加了搜索组件,会占据剩余空间,所以样式没区别:

NavBar.tsx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import { HStack, Image } from "@chakra-ui/react";
import logo from "../assets/logo.webp";
import ColorModeSwitch from "./ColorModeSwitch";
import SearchInput from "./SearchInput";
const NavBar = () => {
    return (
        <HStack padding="10px">
            <Image src={logo} boxSize="60px" />
            <SearchInput />
            <ColorModeSwitch />
        </HStack>
    );
};

export default NavBar;

其中主题切换组件的文字换行了,需要修复一下样式,使用原生的 CSS 即可实现:

ColorModeSwitch.tsx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import { HStack, Switch, Text, useColorMode } from "@chakra-ui/react";

const ColorModeSwitch = () => {
    const { toggleColorMode, colorMode } = useColorMode();

    return (
        <HStack>
            <Switch
                colorScheme="green"
                isChecked={colorMode === "dark"}
                onChange={toggleColorMode}
            />
            {/* fix the text wrap after adding the search input */}
            <Text whiteSpace="nowrap">Dark Mode</Text>
        </HStack>
    );
};

export default ColorModeSwitch;

Searching Games#

SearchInput 将组件用 form 标签包裹,监听 onSubmit 事件并使用 useRef 获取输入的值,并使用 onSearch 函数

SearchInput.tsx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// 从 @chakra-ui/react 库中导入 Input, InputGroup 和 InputLeftElement 组件
import { Input, InputGroup, InputLeftElement } from "@chakra-ui/react";

// 从 react 库中导入 useRef hook
import { useRef } from "react"; 

// 从 react-icons 库中导入搜索图标 BsSearch
import { BsSearch } from "react-icons/bs";

// 定义 Props 接口,接受一个 onSearch 函数作为参数
interface Props {
    onSearch: (searchText: string) => void;  // onSearch 是一个接收字符串并无返回值的函数
}

// 定义 SearchInput 组件,接受 onSearch 作为属性
const SearchInput = ({ onSearch }: Props) => {
    // 使用 useRef 创建一个 ref,用来引用 HTML 输入元素
    const ref = useRef<HTMLInputElement>(null);

    // 返回组件的 JSX 结构
    return (
        // 表单元素,onSubmit 事件处理函数拦截表单提交并调用 onSearch 函数
        <form
            onSubmit={(event) => {
                event.preventDefault();  // 阻止表单默认提交行为
                if (ref.current) onSearch(ref.current.value);  // 如果 ref 存在,调用 onSearch 并传入输入框的值
            }}
        >
            {/* 使用 InputGroup 将输入框和搜索图标包装在一起 */}
            <InputGroup>
                {/* 在输入框左边添加搜索图标 */}
                <InputLeftElement children={<BsSearch />} />
                {/* 定义搜索输入框 */}
                <Input
                    ref={ref}  // 绑定 ref,使其可以获取输入框的值
                    borderRadius={20}  // 设置输入框的圆角
                    placeholder="Search games..."  // 输入框提示文字
                    variant="filled"  // 使用填充样式的输入框
                />
            </InputGroup>
        </form>
    );
};

export default SearchInput;

因为需要接收输入框的值作为参数去请求接口返回数据,因此需要向上传递到 App.tsx

NavBar.tsx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import { HStack, Image } from "@chakra-ui/react";
import logo from "../assets/logo.webp";
import ColorModeSwitch from "./ColorModeSwitch";
import SearchInput from "./SearchInput";

interface Props {
    onSearch: (searchText: string) => void;
}

const NavBar = ({ onSearch }: Props) => {
    return (
        <HStack padding="10px">
            <Image src={logo} boxSize="60px" />
            <SearchInput onSearch={onSearch} />
            <ColorModeSwitch />
        </HStack>
    );
};

export default NavBar;
App.tsx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import { Grid, GridItem, HStack, Show } from "@chakra-ui/react";
import NavBar from "./components/NavBar";
import GameGrid from "./components/GameGrid";
import GenreList from "./components/GenreList";
import { useState } from "react";
import { Genre } from "./hooks/useGenres";
import PlatfromSelector from "./components/PlatfromSelector";
import { Platform } from "./hooks/useGames";
import SortSelector from "./components/SortSelector";
export interface GameQuery {
    genre: Genre | null;
    platform: Platform | null;
    sortOrder: string;
    searchText: string;
}

function App() {
    const [gameQuery, setGameQuery] = useState<GameQuery>({} as GameQuery);

    return (
        <Grid
            templateAreas={{
                base: `"nav" "main"`,
                lg: `"nav nav" "aside main"`,
            }}
            templateColumns={{
                base: "1fr",
                lg: "250px 1fr",
            }}
        >
            <GridItem area="nav">
                <NavBar
                    onSearch={(searchText) =>
                        setGameQuery({ ...gameQuery, searchText })
                    }
                />
            </GridItem>
            <Show above="lg">
                <GridItem area="aside" paddingX={5}>
                    <GenreList
                        onSelectGenre={(genre) =>
                            setGameQuery({ ...gameQuery, genre })
                        }
                        selectedGenre={gameQuery.genre}
                    />
                </GridItem>
            </Show>
            <GridItem area="main">
                <HStack spacing={5} paddingLeft={2} marginBottom={5}>
                    <PlatfromSelector
                        onSelectPlatform={(platform) =>
                            setGameQuery({ ...gameQuery, platform })
                        }
                        selectedPlatform={gameQuery.platform}
                    />
                    <SortSelector
                        onSelectSortOrder={(sortOrder) =>
                            setGameQuery({ ...gameQuery, sortOrder })
                        }
                        sortOrder={gameQuery.sortOrder}
                    />
                </HStack>
                <GameGrid gameQuery={gameQuery} />
            </GridItem>
        </Grid>
    );
}

export default App;

2024-09-08 21:02 2024-09-11 23:39

评论