The cover for the component of holder.js

目录

1. 引言

笔者在自学和实践全栈开发,在学到 react-bootstrap card 时看到了官方示例使用到了图片占位符组件 holder.js, 发现非常的巧妙和有趣,能够使得我们的前端开发更友好,于是跟着学做了一遍。在使用的过程中遇到了一些小坑,在解决了这些问题后觉得有必要记录下来, 以备下次快速查询使用,起到笔记备忘的作用,因为下次使用时一定会忘记而又得从头研究一遍。操作实践内容都是从生产级层面来考虑,不是玩具性代码。

此 Demo 属于 React 体系,技术栈为:

React.js + Next.js + App Router + TypeScript + Tailwind CSS + React-Bootstrap + PNPM

2. 准备条件

  • 系统:笔者使用的是 macOS 系统,其它系统操作类似。
  • 科学上网环境。如无可参考笔者的 科学上网之 Gost 方案 v2
  • 如果未安装则安装 Homebrew

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    
  • 如果未安装则安装 Visual Studio Code:

    brew install --cask visual-studio-code
    

    配置 VS Code 以便之后从终端启动:

    • 打开 VS Code。
    • 打开命令面板 (Cmd+Shift+P) 并输入“shell command”以查找 Shell Command: Install ‘code’ command in PATH 命令。
    • 重新启动终端以使新的 $PATH 值生效。您可以在任何文件夹中键入 code . 来开始编辑该文件夹中的文件。
  • 如果未安装则安装 Node.js:

    brew install node
    
  • 如果未安装则安装 PNPM:

    npm install -g pnpm
    
  • 如果未安装则安装 TypeScript:

    npm install -g typescript
    

3. 操作步骤

  • 打开 Terminal.app 终端或 iTerm2 等终端,并导航到项目想存放的目录。
  • 创建项目:

    可用自定义项目名替换下面的 react-bs-demo。

    pn create react-bs-demo
    
  • 导航到项目里:

    cd react-bs-demo
    
  • 安装依赖框架:

    pn add react-bootstrap bootstrap sass holderjs
    
  • 用 Visual Studio Code 打开:

    code .
    
  • 打开 layout.tsx 文件,删除 import "./globals.css";,然后添加 import "bootstrap/dist/css/bootstrap.min.css";

    // layout.tsx
    
    import type { Metadata } from "next";
    import { Inter } from "next/font/google";
    
    import "bootstrap/dist/css/bootstrap.min.css";
    
    const inter = Inter({ subsets: ["latin"] });
    
    export const metadata: Metadata = {
      title: "My Placeholder Demo of Image",
      description: "Generated by create next app",
    };
    
    export default function RootLayout({
      children,
    }: Readonly<{
      children: React.ReactNode;
    }>) {
      return (
        <html lang="zh-CN">
          <body className={inter.className}>{children}</body>
        </html>
      );
    }
    
  • 打开 page.tsx 文件,并替换为以下代码:

    // page.tsx
    
    "use client";
    
    import { useEffect } from "react";
    import { Button, ButtonGroup, Card, Dropdown } from "react-bootstrap";
    import { run as runHolder } from "holderjs/holder";
    
    export default function Home() {
    
      useEffect(() => {
        runHolder();
      });
    
      const cardWidth = { width: "18rem" };
    
      return (
        <main className="p-5">
    
          <Card style={cardWidth}>
            <Card.Img variant="top" data-src="holder.js/100px180?text=Placeholder of Image&theme=social" />
            <Card.Body>
              <Card.Title>Card Title</Card.Title>
              <Card.Text>
                Some quick example text to build on the card title and make up the
                bulk of the card's content.
              </Card.Text>
              <Button variant="primary">Go somewhere</Button>
            </Card.Body>
          </Card>
    
        </main>
      );
    }
    

    Card.Imgdata-src 属性值就是图片占位符工具 holderjs 的配置部分,更多功能配置可见 深入了解 部分。 如果有正常正确的图片链接,便可以添加一个 src 属性,把值放到里面,这样便简洁清晰互不影响,亦不会忘, 当没有图片或图片地址错误时便显示 data-src 里的 holderjs 生成的占位图片,当 src 存在且指定的图片地址没问题时便使用真正的图片。即:

    <Card.Img variant="top" src="https://getbootstrap.com/docs/5.3/assets/brand/bootstrap-logo-shadow.png" 
      data-src="holder.js/100px180?text=Placeholder of Image&theme=social" />
    
  • 在终端中运行 pn dev --turbo,然后在浏览器中打开 http://localhost:3000,即可得到封面图所示界面。

  • 但是在代码头的导入语句处会出现红色波浪线, 鼠标移上去会出现类似警告提示(在底部的 PROBLEMS 面板中也会出现, 虽然不影响使用):

    Could not find a declaration file for module 'holderjs/holder'. '/Users/myqs/Downloads/bs-react-demo/node_modules/.pnpm/holderjs@2.9.9/node_modules/holderjs/holder.js' implicitly has an 'any' type.
    Try `npm i --save-dev @types/holderjs` if it exists or add a new declaration (.d.ts) file containing `declare module 'holderjs/holder';`
    

    按照提示即 npm i --save-dev @types/holderjs 尝试解决, 由于我使用的是 pnpm, 所以是 pn i --save-dev @types/holderjs。如果无效则继续后续步骤。

    • 在项目根目录下创建文件夹 types, 并在文件夹中创建 holderjs.d.ts 文件。
    • holderjs.d.ts 文件中写入如下代码:

      declare module 'holderjs/holder' {
        export function run(options?: any): void;
        export default run;
      }
      
    • 打开 tsconfig.json 文件, 在 compilerOptions 选项下找到 typeRoots (若没有则新增) 并添加 "./types", "./node_modules/@types" 这两项。整个文件似下:

      {
        "compilerOptions": {
          "lib": ["dom", "dom.iterable", "esnext"],
          "allowJs": true,
          "skipLibCheck": true,
          "strict": true,
          "noEmit": true,
          "esModuleInterop": true,
          "module": "esnext",
          "moduleResolution": "bundler",
          "resolveJsonModule": true,
          "isolatedModules": true,
          "jsx": "preserve",
          "incremental": true,
          "plugins": [
            {
              "name": "next"
            }
          ],
          "paths": {
            "@/*": ["./src/*"]
          },
          "typeRoots": ["./types", "./node_modules/@types"]
        },
        "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
        "exclude": ["node_modules"]
      }
      

4. 深入了解

通过访问托管到 GitHub 的官方 holder.js 项目来获得更多功能使用说明。

5. 参考资源