React18项目,头部布局,styled-components的使用,主题文件配置ThemeProvider,css in js 样式混入,

252 阅读2分钟

页面布局

image.png

样式(css in js)-> styled-components的使用

安装依赖 npm i styled-components

在style.js里写样式

import styled from "styled-components";
export const HeaderWrapper = styled.div`
  display: flex;
  .left {
    color: orange;
  }

  .center {
    color: purple;
  }

  .right {
    color: blue;
  }
`;

应用到组件上

import React, { memo } from "react";
import { HeaderWrapper } from "./style";
const AppHeader = memo(() => {
  return (
    <HeaderWrapper>
      <div className="left">left</div>
      <div className="center">center</div>
      <div className="right">right</div>
    </HeaderWrapper>
  );
});
export default AppHeader;

效果:

image.png

头部比较复杂,继续拆分:

image.png

import styled from "styled-components";
export const LeftWrapper = styled.div``;
import React, { memo } from "react";
import { LeftWrapper } from "./style";
const HeaderLeft = memo(() => {
  return <LeftWrapper>HeaderLeft</LeftWrapper>;
});
export default HeaderLeft;

上面是子组件

import React, { memo } from "react";
import { HeaderWrapper } from "./style";
import HeaderLeft from "./c-cpns/header-left";
import HeaderCenter from "./c-cpns/header-center";
import HeaderRight from "./c-cpns/header-right";

const AppHeader = memo(() => {
  return (
    <HeaderWrapper>
      <HeaderLeft />
      <HeaderCenter />
      <HeaderRight />
    </HeaderWrapper>
  );
});
export default AppHeader;
import styled from "styled-components";
export const HeaderWrapper = styled.div`
  display: flex;
  align-items: center;
  height: 80px;
  border-bottom: 1px solid #eee;
`;

image.png

  • sc-类似Vue中的scoped

头部布局

左右flex:1;

export const LeftWrapper = styled.div`
  flex: 1;
`;

右边:

import styled from "styled-components";
export const RightWrapper = styled.div`
  flex: 1;
  display: flex;
  justify-content: flex-end;
`;

可以保证中间部分,居中

image.png

左边logo

import React, { memo } from "react";
import { LeftWrapper } from "./style";
import logo from "@/assets/img/logo.png";
const HeaderLeft = memo(() => {
  return (
    <LeftWrapper>
      <img className="logo" alt="logo" src={logo} />
    </LeftWrapper>
  );
});
export default HeaderLeft;

注意:这样子引入图片没有效果 <img className="logo" alt="" src="../../../../assets/img/logo.png" />

  • Webpack默认会将图片以base64的形式内联到打包后的文件中

image.png

  • svg图片处理 将svg封装成一个jsx组件

style -> obj

function styleStrToObject(styleStr) {
  const obj = {};

  const s = styleStr
    .toLowerCase()
    .replace(/-(.)/g, function (m, g) {
      return g.toUpperCase();
    })
    .replace(/;\s?$/g, "")
    .split(/:|;/g);

  for (var i = 0; i < s.length; i += 2) {
    obj[s[i].replace(/\s/g, "")] = s[i + 1].replace(/^\s+|\s+$/g, "");
  }
  return obj;
}
export default styleStrToObject;
import React, { memo } from "react";
import styleStrToObject from "./utils";

const IconLogo = memo(() => {
  return (
    <svg width="102" height="32" style={styleStrToObject("display:block")}>
      <path></path>
    </svg>
  );
});
export default IconLogo;

logo颜色和主题文件配置

方案1:css变量

image.png

image.png

方案2:ThemeProvider

  • import { ThemeProvider } from "styled-components";

image.png

const theme = {
  color: {
    primary: "#ff385c",
    second: "#00848A",
  },
};
export default theme;
import React, { Suspense } from "react";
import ReactDOM from "react-dom/client";
import { HashRouter } from "react-router-dom";
import { Provider } from "react-redux";
import { ThemeProvider } from "styled-components";

import App from "@/App";
import "normalize.css";
import "./assets/css/index.less";
import store from "./store";
import theme from "./assets/theme";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  // <React.StrictMode>
  <Suspense fallback="loading">
    <Provider store={store}>
      <ThemeProvider theme={theme}>
        <HashRouter>
          <App />
        </HashRouter>
      </ThemeProvider>
    </Provider>
  </Suspense>
  // </React.StrictMode>
);

在样式组件RightWrapper (style.js)文件中使用:

  • color: ${(props) => props.theme.color.second};
import styled from "styled-components";
export const RightWrapper = styled.div`
  flex: 1;
  display: flex;
  justify-content: flex-end;
  padding-right: 40px;
  /* color: var(--primary-color); */

  color: ${(props) => props.theme.color.second};
`;

image.png

头部右侧

import React, { memo } from "react";
import { RightWrapper } from "./style";
import IconGlobal from "@/assets/svg/icon-global";
import IconMenu from "@/assets/svg/icon-menu";
import IconAvatar from "@/assets/img/avatar.png";

const HeaderRight = memo(() => {
  return (
    <RightWrapper>
      <div className="btns">
        <span>登录</span>
        <span>注册</span>
        <span>
          <IconGlobal />
        </span>
      </div>

      <div className="profile">
        <span>
          <IconMenu />
        </span>
        <span>
          <img src={IconAvatar} alt="头像" />
        </span>
      </div>
    </RightWrapper>
  );
});
export default HeaderRight;
import styled from "styled-components";

export const RightWrapper = styled.div`
  flex: 1;
  display: flex;
  justify-content: flex-end;
  padding-right: 40px;
  align-items: center;
  font-size: 14px;
  font-weight: 600;
  color: ${(props) => props.theme.text.primary};

  .btns {
    display: flex;
    align-items: center;
    span {
      cursor: pointer;
      padding: 12px 15px;
      border-radius: 22px;
      height: 18px;
      line-height: 18px;
      &:hover {
        background-color: #f5f5f5;
      }
    }
  }

  .profile {
    display: flex;
    align-items: center;
    margin-left: 5px;
    border-radius: 22px;
    border: 1px solid #ccc;
    transition: box-shadow 0.2s ease;
    width: 80px;
    height: 42px;
    box-sizing: border-box;
    padding: 0px 10px 0 15px;
    img {
      width: 28px;
      height: 28px;
      border-radius: 50%;
      margin-left: 10px;
    }
    transition: box-shadow 0.2s ease;
    &:hover {
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.18);
    }
  }

  .profile > span {
    cursor: pointer;
  }
`;

效果:

image.png

css in js 样式混入

    transition: box-shadow 0.2s ease;
    &:hover {
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.18);
    }

抽取出去。

image.png

const theme = {
  color: {
    primary: "#ff385c",
    second: "#00848A",
  },
  text: {
    primary: "#484848",
    second: "#222",
  },
  mixin: {
    boxShadow: `
      transition: box-shadow 0.2s ease;
      &:hover {
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.18);
      }
    `,
  },
};
export default theme;

样式组件中使用:

image.png

头部中间部分

请看下篇文章~~~