第七周

date
May 24, 2022
tags
Website
summary
type
Post
status
Published
slug
week-7

styled-components 记录

最近看 CSS for JS 课程,看到作者分享使用 styled-components 的一些技巧,感觉很有用,所以记录总结一下。
Demystifying styled-components The styled-components Happy Path
基础的处理逻辑
当我们使用 styled-components 生成一个组件的时候会发生下面代码这几件事:
const styled = (Tag) => (styles) => {
  return function NewComponent(props) {
		// 生成唯一 class 名
    const uniqueClassName = comeUpWithUniqueName(styles);
    // 加工 style 字符串
		const processedStyles = runStylesThroughStylis(styles);
    // style 字符注入 css 文件
    createAndInjectCSSClass(uniqueClassName, styles);
		// 新的 className 和组件本身的 className 组合
		const combinedClasses =
      [uniqueClassName, props.className].join(' ');

		// 绑定 className
    return <Tag className={combinedClasses} {...props} />
  }
}
模板字符使用 props 后会生成两个份不一样的 className 和 CSS
因为 props 对象里的值是暂时无法确定的,必须等到运行后才能确定
/* before */
const ContentImage = styled.img`
  display: block;
  margin-bottom: 8px;
  width: 100%;
  max-width: ${p => p.maxWidth};
`;

render(
  <>
    <ContentImage
      alt="A running shoe with pink laces and a rainbow decal"
      src="/images/shoe.png"
      maxWidth="200px"
    />
    <ContentImage
      alt="A close-up shot of the same running shoe"
      src="/images/shoe-closeup.png"
    />
  </>
)

/* after */
<style>
  .JDSLg {
    display: block;
    margin-bottom: 8px;
    width: 100%;
    max-width: 200px;
  }
  .eXyedY {
    display: block;
    margin-bottom: 8px;
    width: 100%;
  }
</style>
<img
  alt="A running shoe with pink laces and a rainbow decal"
  src="/images/shoe.png"
  class="sc-bdnxRM JDSLg"
/>
<img
  alt="A close-up shot of the same running shoe"
  src="/images/shoe-closeup.png"
  class="sc-bdnxRM eXyedY"
/>
使用 CSS 变量会生成更少的代码,减少摩擦
例如下面的 var(—max-width),配合 style 对象参数,它们会共享一个 className 和 CSS 代码。
/* before */
const ContentImage = styled.img`
  display: block;
  margin-bottom: 8px;
  width: 100%;
  max-width: var(--max-width);
`;

render(
  <>
    <ContentImage
      alt="A running shoe with pink laces and a rainbow decal"
      src="/images/shoe.png"
      style={{
        '--max-width': '200px',
      }}
    />
    <ContentImage
      alt="A close-up shot of the same running shoe"
      src="/images/shoe-closeup.png"
    />
  </>
)

/* after */
<style>
  .JDSLg {
    display: block;
    margin-bottom: 8px;
    width: 100%;
    max-width: var(--max-width);
  }
</style>
<img
  alt="A running shoe with pink laces and a rainbow decal"
  src="/images/shoe.png"
  class="sc-bdnxRM JDSLg"
  style="--max-width: 200px"
/>
<img
  alt="A close-up shot of the same running shoe"
  src="/images/shoe-closeup.png"
  class="sc-bdnxRM JDSLg"
/>
 
组件单一样式控制
有两种适用的场景,一个场景是两个组件都是通用组件,会频繁适用,与业务逻辑不强关联
// Aside.js
const Aside = ({ children }) => { /* Omitted for brevity */ }
// Export this wrapper
export const Wrapper = styled.aside`
  /* styles */
`;
export default Aside;

// TextLink.js
import { Wrapper as AsideWrapper } from '../Aside'

const TextLink = styled.a`
  color: var(--color-primary);
  font-weight: var(--font-weight-medium);
  ${AsideWrapper} & {
    color: var(--color-text);
    font-weight: var(--font-weight-bold);
  }
`;

// render after
.TextLink-abc123 {
  color: var(--color-primary);
  font-weight: var(--font-weight-medium);
}
.Aside-Wrapper-def789 .TextLink-abc123 {
  color: var(--color-text);
  font-weight: var(--font-weight-bold);
}
还有一种是在某种业务情况下使用,与当前的业务有较强的关联
import TextLink from '../TextLink';
import { Wrapper as AsideWrapper } from '../Aside'

const HalloweenTextLink = styled(TextLink)`
	--color-primary: orange;
  font-family: 'Spooky Font', cursive;
`;

// render css
.TextLink-abc123 {
  color: var(--color-primary);
  font-weight: var(--font-weight-medium);
}

.HalloweenTextLink-edf321 {
	--color-primary: orange;
}

<div
	class="TextLink-abc123 HalloweenTextLink-edf321"
>
	hello!
</div>
as 语义化
Extending Styles
不要让包裹的标签全是 div,可以根据语义使用 as 指定包裹的标签
// `level` is a number from 1 to 6, mapping to h1-h6
function Heading({ level, children }) {
  const tag = `h${level}`;
  return (
    <Wrapper as={tag}>
      {children}
    </Wrapper>
  );
}
// The `h2` down here doesn't really matter,
// since it'll always get overwritten!
const Wrapper = styled.h2`
  /* Stuff */
`;

function LinkButton({ href, children, ...delegated }) {
  const tag = typeof href === 'string'
    ? 'a'
    : 'button';
  return (
    <Wrapper as={tag} href={href} {...delegated}>
      {children}
    </Wrapper>
  );
}
notion image
styled-component/macro
Better debugging
使用 styled-component/macro 导入可以让你创建的组件有更全的 className,方便开发的时候检索文件、定位代码
notion image
 

我叒换手机了!

由于手机又丢了,所有有了这篇 我的一加8T装了啥? 的 Blog

购买 Theine.app

这是一个让 Mac 不休眠的状态栏小工具。刚好遇到有限时优惠只要 $0.99,设计很精美的 App

购买安卓App 带壳截图Pro

notion image

终于等到了 Github Codespaces 试用资格

notion image
notion image
收到邮件后就迫不及待的试用了一下。所有 VS Code 的设置都自动同步过来,不需要任何的配置就有一个最熟悉的编辑器,和之前使用较多的 Gitpod 相比开发体验还是有提升。期待云 IDE、开发环境发展得更加成熟。

用 Raycast 替代 Manico 的部分功能

notion image
notion image
用 Manico 来帮助我使用快捷键快速的打开常用软件,就这个功能来说在 Raycast 中给 App 配置 Hotkey 也可以完成相同的事情。但 Manico 的作者都维护了它近 10 年了

了解 tRPC

最近在读 代码时看到有使用 tPRC 这个库,大概过了一下官方的介绍。和 GraphQL 的要解决的问题有一些相似。
Simple, strong types.
notion image
 

© Craig Hart 2021 - 2024