React案例:鼠标移入和移出更改背景颜色

在本文中,我们将使用 React 创建一个简单的卡片组件,该组件可以根据用户的交互更改背景颜色和文字颜色。我们将使用 React 内联样式来管理卡片的样式,并通过 React 的 useState 钩子来管理状态。

创建 Card 组件

我们从创建一个名为 Card 的函数组件开始。该组件将渲染一个包含标题、段落和按钮的卡片。用户可以将鼠标悬停在按钮上,以更改卡片的样式。从 Card 组件顶部的 React 导入 useState。 导入后,我们将使用数组解构来创建状态变量和更新状态的函数。

import React, { useState } from "react";

const Card = () => {
    // 使用 useState 定义状态变量和更新函数
    const [style, setStyle] = useState({
        background: "#fdfdfd",
        color: "#424246"
    });

    // 定义一个函数,根据用户的交互更新卡片的样式
        const setCardStyle = (background, color) => {
        setStyle({ background, color });
    };

    // 定义卡片和按钮的样式
    const cardStyle = {
        maxWidth: "600px",
        padding: "40px",
        backgroundColor: style.background,
    };

    const headerStyle = {
        fontSize: "36px",
        marginBottom: "10px",
        color: style.color
    };

    const paragraphStyle = {
        fontSize: "16px",
        marginBottom: "20px",
        color: style.color
    };

    const buttonStyle = {
        fontWeight: "500",
        fontSize: "12px",
        padding: "10px 30px",
        marginRight: "20px",
        marginBottom: "20px",
        borderRadius: "50px",
        cursor: "pointer"
    };

    const blackButtonStyle = {
        ...buttonStyle,
        color: "#fdfdfd",
        backgroundColor: "#424246"
    };

    const blueButtonStyle = {
        ...buttonStyle,
        color: "#fdfdfd",
        backgroundColor: "#1d499b"
    };

    const yellowButtonStyle = {
        ...buttonStyle,
        color: "#424246",
        backgroundColor: "#f9d648"
    };

    return (
        <div style={cardStyle}>
            <h1 style={headerStyle}>颜色卡片</h1>
            <p style={paragraphStyle}>
                通过鼠标移入按钮来更改卡片的背景颜色,移出后恢复
            </p>
            <div>
                <div
                    onMouseEnter={() => setCardStyle("#424246", "#fdfdfd")}
                    onMouseOut={() => setCardStyle("#fdfdfd", "#424246")}
                    style={blackButtonStyle}
                >
                    Black
                </div>
                <div
                    onMouseEnter={() => setCardStyle("#1d499b", "#fdfdfd")}
                    onMouseOut={() => setCardStyle("#fdfdfd", "#424246")}
                    style={blueButtonStyle}
                >
                    Blue
                </div>
                <div
                    onMouseEnter={() => setCardStyle("#f9d648", "#424246")}
                    onMouseOut={() => setCardStyle("#fdfdfd", "#424246")}
                    style={yellowButtonStyle}
                >
                    Yellow
                </div>
            </div>
        </div>
    );
};

export default Card;

在上述代码中,我们首先导入了 React 和 useState 钩子。然后,我们定义了一个名为 Card 的函数组件,其中包含了一个 useState 钩子来管理状态。useState 钩子返回一个状态变量和一个更新该变量的函数。我们使用这个函数来更新卡片的样式。
在组件内部,我们定义了一个 setCardStyle 函数,它接受两个参数:background 和 color。这个函数用来更新卡片的样式。然后,我们定义了卡片和按钮的样式对象,以及三种不同颜色的按钮样式。
最后,我们返回一个包含标题、段落和按钮的 div 元素。当用户将鼠标悬停在按钮上时,会触发相应的 onMouseEnter 和 onMouseOut 事件处理函数,从而更新卡片的样式。

Emotion库的使用

Emotion是一种CSS in JS的 React 应用中写样式的一个主流的方案,一些基本的使用方法可以访问官网地址:
emotion.sh/docs/introd…
Emotion的的优点如下:

  1. 不用关心繁琐的 Class 命名规则
  2. 不用担心样式被覆盖
  3. 便利的样式复用(样式都是 js 对象或字符串)
  4. 减少冗余的 CSS 代码,极致的样式按需加载

通过Emotion实现Card的组件:

/** @jsxImportSource @emotion/react */
import React, { useState } from "react";
import { jsx, css } from '@emotion/react'

const Card = () => {
    // 使用 useState 定义状态变量和更新函数
    const [style, setStyle] = useState({
        background: "#fdfdfd",
        color: "#424246"
    });


    // 定义一个函数,根据用户的交互更新卡片的样式
    const setCardStyle = (background, color) => {
        setStyle({ background, color });
    };

    const card = css`
        max-width: 600px;
        padding: 40px 40px 20px 40px;
        background-color: ${style.background};
        h1 {
          font-weight: 400;
          font-size: 36px;
          margin-bottom: 10px;
          color: ${style.color};
        }
        p {
          font-weight: 300;
          font-size: 16px;
          margin-bottom: 20px;
          color: ${style.color};
        }
  `;

    const cardButtons = css`
        display: flex;
        flex-wrap: wrap;
        div {
          font-weight: 500;
          font-size: 12px;
          padding: 10px 30px;
          margin-right: 20px;
          margin-bottom: 20px;
          border: none;
          border-radius: 50px;
          cursor: pointer;
        }
  `;

    const blackButton = css`
        color: #fdfdfd;
        background-color: #424246;
  `;

    const blueButton = css`
        color: #fdfdfd;
        background-color: #1d499b;
  `;

    const yellowButton = css`
        color: #424246;
        background-color: #f9d648;
  `;

    return (
        <div css={card}>
            <h1>颜色卡片</h1>
            <p>通过鼠标移入按钮来更改卡片的背景颜色,移出后恢复</p>
            <div css={cardButtons}>
                <div
                        onMouseEnter={() => setCardStyle("#424246", "#fdfdfd")}
                        onMouseOut={() => setCardStyle("#fdfdfd", "#424246")}
                        css={blackButton}
                >
                        Black
                </div>
                <div
                        onMouseEnter={() => setCardStyle("#1d499b", "#fdfdfd")}
                        onMouseOut={() => setCardStyle("#fdfdfd", "#424246")}
                        css={blueButton}
                >
                        Blue
                </div>
                <div
                        onMouseEnter={() => setCardStyle("#f9d648", "#424246")}
                        onMouseOut={() => setCardStyle("#fdfdfd", "#424246")}
                        css={yellowButton}
                >
                        Yellow
                </div>
            </div>
        </div>
    );
}

export default Card;

需要注意的是,将 jsx 注释设置在使用道具的源文件的顶部。 此选项最适合测试 prop 功能或在 babel 配置不可配置的项目(create-react-app、codesandbox 等)中。

/** @jsxImportSource @emotion/react */
import { jsx } from '@emotion/react'

/** @jsxImportSource @emotion/react */ 不生效的时候可以改为 /** @jsx jsx */ 来尝试。

自定义改变全局的主题

当我们使用 Emotion 库创建 React 组件时,通常希望能够轻松地管理全局的主题,以便在整个应用程序中共享样式和颜色。

创建自定义主题的组件:ThemeProvider

/** @jsxImportSource @emotion/react */
import { createContext, useContext, useState, useEffect } from 'react';
import { ThemeProvider as EmotionThemeProvider } from '@emotion/react';
import { lightTheme, darkTheme } from '../themes'; // 假设你有两个主题文件

const ThemeContext = createContext();

export const customUseTheme = () => {
    const context = useContext(ThemeContext);
    if (!context) {
        throw new Error('useTheme must be used within a ThemeProvider');
    }
    return context;
};

const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState('light'); // 默认主题为 light

    useEffect(() => {
        // 通过 localStorage 或其他途径保存当前主题设置
        const savedTheme = localStorage.getItem('theme');
        if (savedTheme) {
            setTheme(savedTheme);
        }
    }, []);

    useEffect(() => {
        // 每次主题改变时更新 localStorage 中的值
        localStorage.setItem('theme', theme);
    }, [theme]);

    const toggleTheme = () => {
        setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
    };

    const themeValues = {
        theme,
        toggleTheme,
    };

    return (
        <ThemeContext.Provider value={themeValues}>
            <EmotionThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}>
                {children}
            </EmotionThemeProvider>
        </ThemeContext.Provider>
    );
};

export default ThemeProvider;

根组件中引入

import React from 'react';
import ThemeProvider from './components/ThemeProvider';
import Card from './components/card';

function App() {
    return (
        <ThemeProvider>
            <Card />
        </ThemeProvider>
    )
}

export default App

card组件中的使用:

/** @jsxImportSource @emotion/react */
import { jsx, css, useTheme } from '@emotion/react';
import { customUseTheme } from './ThemeProvider';

function Card() {
    const theme = useTheme();

    const { toggleTheme } = customUseTheme();

    const card = css`
        max-width: 600px;
        padding: 40px 40px 20px 40px;
        background-color: ${theme.colors.background};
        h1 {
            font-weight: 400;
            font-size: 36px;
            margin-bottom: 10px;
            color: ${theme.colors.primary};
        }
        p {
            font-weight: 300;
            font-size: 16px;
            margin-bottom: 20px;
            color: ${theme.colors.primary};
        }
    `;

  return (
    <div css={card}>
        <h1>颜色卡片</h1>
        <p>通过鼠标移入按钮来更改卡片的背景颜色,移出后恢复</p>

        <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
}

export default Card

原文链接:https://juejin.cn/post/7347905312470614055 作者:梦尘星月

(0)
上一篇 2024年3月19日 下午4:22
下一篇 2024年3月19日 下午4:32

相关推荐

发表评论

登录后才能评论