nextjs的图片和文字优化

1.文字优化:

(1)具体代码:

ts 复制代码
///app/ui/fonts.ts
import { Inter } from 'next/font/google'; 
export const inter = Inter({
subsets: ['latin'] 
}
);


///app/layout.tsx
import '@/app/ui/global.css';
import { inter } from '@/app/ui/fonts'; 
export default function RootLayout({ children,}: { children: React.ReactNode;}) { 
return ( 
<html lang="en">
<body className={`${inter.className} antialiased`}>{children}</body> </html>
);
}

(2)相关疑问:

问:为什么import { Inter } from 'next/font/google'中Inter要加大括号

答:这里涉及了命名导入,在命名导入时是要精确的导入内容的所以必须名字一模一样,并且必须加大括号 import { X } from 'xxx'

额外补充:默认导出导入关系和命名导出导入关系

1.默认导出导入关系:默认导出那这个文件当中只能导出一个 多了就会报错、就乱了、就无法精准接收


为什么只能一个?

因为:默认导出 = 这个文件的 "主角"一个文件只能有 一个主角。 如果是 export default const A = ... export default const B = ... export default const C = ... 这里就会覆盖,也就是最终模块的 default 只会保留最后一个值(c),前面的都会被覆盖,相当于 "白写了"------ 这就是为什么说 "只能有一个"(多了会乱,失去意义)

所以默认导入 = 跟名字无关,导入名字随便写。export default 导出你给它起什么名字,它就叫什么名字。


那如果一个文件里要导出很多东西怎么办?

用 命名导出(大括号那种) export const A = ... export const B = ... export const C = ... 别人导入时: import { A, B, C } from 'xxx'


2.命名导出导入关系:

命名导出就是为「一个文件导出多个内容」设计的,想导出多少就导出多少,完全不受限。

对方是 export const XXX你导入时 必须名字一模一样,错一个字母都不行 必须大括号 import { X } from 'xxx'

问:默认和命名导出本质上这两个是不能出现在一个文件里的吧?

答:在 JavaScript 的模块系统里,一个文件可以同时拥有一个默认导出(Default Export)和多个命名导出(Named Export)。

  • 默认导出 (export default) :像是一个国家的"国王",一个文件只能有一个。导入时不需要大括号:import CardWrapper from '...'
  • 命名导出 (export function Card) :像是一个国家的"大臣",一个文件可以有无数个。导入时必须带大括号:import { Card } from '...'

例如在card.tsx中

ts 复制代码
export default async function CardWrapper() {
  const {
    numberOfInvoices,
    numberOfCustomers,
    totalPaidInvoices,
    totalPendingInvoices,
  } = await fetchCardData();
  return (
    <>
      <Card title="Collected" value={totalPaidInvoices} type="collected" />
      <Card title="Pending" value={totalPendingInvoices} type="pending" />
      <Card title="Total Invoices" value={numberOfInvoices} type="invoices" />
      <Card
        title="Total Customers"
        value={numberOfCustomers}
        type="customers"
      />
    </>
  );
}

export function Card({
  title,
  value,
  type,
}: {
  title: string;
  value: number | string;
  type: 'invoices' | 'customers' | 'pending' | 'collected';
}) {
  const Icon = iconMap[type];

  return (
    <div className="rounded-xl bg-gray-50 p-2 shadow-sm">
      <div className="flex p-4">
        {Icon ? <Icon className="h-5 w-5 text-gray-700" /> : null}
        <h3 className="ml-2 text-sm font-medium">{title}</h3>
      </div>
      <p
        className={`${lusitana.className}
          truncate rounded-xl bg-white px-4 py-8 text-center text-2xl`}
      >
        {value}
      </p>
    </div>
  );
}

就同时存在了这两种导出方式,同时card是cardWrapper数据的载体需要用到,如果你把 Card 挪到另一个文件,你也得在 cards.tsx 顶层写 import { Card } from './SingleCard'。既然目前这个 Card 只在这一处大规模使用,放在一起其实更清爽。

问:针对上一个问题,什么时候该拆分(这里的拆分其实就是组件应该写在app下还是写在具体的目录例如 invoice dashboard下,其实也就看能不能复用)?

答:要建立这种 拆分标准 。只有当以下情况发生时,你才应该把 Card 拿出去:

  1. 复用需求 :如果你的 Customers 页面或 Invoices 页面也想用一模一样的卡片样式,那就拆。
  2. 复杂度爆表 :如果 Card 的 CSS 代码写了 200 行,逻辑又变得很复杂,为了可读性,那就拆。

问:export const inter = Inter({ subsets: ['latin'] });是什么意思,又有什么用?

答:这里就是默认导出的写法,其中 Inter({ subsets: 'latin' })就是利用上面导入的Inter函数实现''我要使用 Inter 字体,只加载英文字符集,帮我生成一个配置好的字体对象''这个功能,最后把生成好的字体对象存到变量 inter 里并且把这个配置好的字体,暴露出去,让别的文件能用到。

问:

ts 复制代码
<body className={`${inter.className} antialiased`}>{children}</body>

这段代码是什么意思啊?

答:在写法层面分析:类如${inter.className} antialiased结果是font-inter antialiased,这是一个具体的类名并且有逻辑含义所以用{},但是为了严谨font-inter不适合直接写。因为想要能自动适配字体加载、全局样式等逻辑,哪怕后续字体名变了,代码不用改;所以要用变量来转化,所以用${}来表示逻辑关系。

在逻辑层面分析:这里inter.className中的inter就是上面导入的默认导入,这里是为了提取这个inter的属性classname

2.图片优化:

1.主要作用者 ---Image

Image不是普通 img,它是自动帮你做图片优化的组件。 它自带这些强大功能:

这里注意需要写的属性:

其他的不是必要写的,只要写出Image标签他的图片就会自动优化

2.代码分析

ts 复制代码
// /app/page.tsx
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';


import Image from 'next/image';
 
export default function Page() {
  return (
    // ...
    <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
      {/* Add Hero Images Here */}
      
      <Image
        src="/hero-desktop.png"
        width={1000}
        height={760}
        className="hidden md:block"
        alt="Screenshots of the dashboard project showing desktop version"
      />
      
    </div>
    //...
  );
}.

问:在你这段代码里,它是怎么优化图片的?

答案:import Image from 'next/image'是默认导入next/image 是 Next.js 自带的图片优化工具 它里面是 export default Image所以你导入时 不用大括号,直接写名字就行

再来看看主要逻辑部分:

① src="/hero-desktop.png" 图片放在 /public 文件夹 / 开头就代表从 public 里找

② width={1000} height={760} 告诉 Next 图片原始宽高 它会自动保持比例,不会变形 关键:防止页面布局跳动(CLS)

③ className="hidden md:block" 这是 Tailwind 响应式: hidden → 手机上隐藏 md:block → 平板 / 电脑上显示

补充建议:响应式图片的"两套方案"

你在代码中用了 hidden md:block 来切换桌面端图片。这是最简单、最稳妥的做法。

但如果项目非常复杂,工程师有时会使用 sizes 属性或者 fill 模式:

  • fill 模式 :当你不知道图片的具体宽高(比如图片由用户上传)时,给父元素设置 position: relative,给 Image 设置 fill 属性,图片会自动撑满容器。

3.总结:

相关推荐
gogoing4 小时前
React Hooks 完整指南
react.js
假如让我当三天老蒯5 小时前
State和Props区别和左右(自学用)
前端·react.js
夜雪闻竹6 小时前
React Query + REST API 最佳实践
前端·react.js·前端框架
戈德斯文8 小时前
我做了一面互联网摸鱼墙:从无限 Canvas 到本地生产环境
react.js·canvas·next.js
vim怎么退出1 天前
Dive into React——Hooks 原理
react.js·源码阅读
光影少年1 天前
react的useMemo 如何优化?
前端·react.js·掘金·金石计划
YFF菲菲兔1 天前
React 核心流程总述
react.js
光影少年1 天前
react状态管理
前端·react.js·前端框架
珎珎啊1 天前
React 和 Vue 3的区别
前端·vue.js·react.js