Normal view

There are new articles available, click to refresh the page.
Before yesterdayStories by 李瑞东 on Medium

面向产品设计的 Web 前端分享会(分享会记录)

最近听说部门里面的产品或本地化运营对 Web 前端相关的内容比较感兴趣,正好我有相关的实践经验,所以在公司做了一个 Web 前端相关的分享会。分享内容包含:

  1. 使用 Devtools:介绍 Chrome 浏览器内的模拟、编辑和审查工具;
  2. 网页和部署:介绍 HTML, CSS, JavaScript, React,以及网站的部署和托管;
  3. 网页性能指标:介绍网页性能常用指标和测量工具;
  4. 资源分享:分享浏览器插件、网站和课程推荐。

与以往不同的是,这次分享会中加入了互动环节。我做了一个代码 Playground,尝试帮助观众了解 React,以及 React Props 的概念,并留了两个小任务,给观众尝试去实践对 React 项目进行编码。

完整的分享内容内容请继续浏览本文。

使用 Devtools

这个章节主要介绍 Chrome Devtools 一些可能不为人知的功能,来帮助我们提高日常工作中的效率和解决一些问题。先介绍 Devtool 里面「模拟」相关的功能。

模拟设备和屏幕尺寸

在 Devtool 里打开设备工具栏,在这里除了能够自由调整网页宽高,还能够模拟各种主流设备的屏幕。

甚至还能读取到网页里面的断点样式,提供快捷切换各种断点的方式。

需要注意的是,这里模拟的设备是会带上 UA 的,所以如果想在电脑里调试一些做了移动端特化处理的网站(比如访问主域名时,判断到是手机设备,则会跳到移动端的专门网站),是需要用到这个功能的。

模拟伪类

Devtools 还可以帮助我们排查各种交互状态下的样式问题,最常用的是,比如说我们想仔细排查某个元素的悬停和按下状态的样式,则可以在选中元素之后,勾选对应的伪类选项。

模拟媒体

在渲染面板(需要手动开启,浏览器默认是没有打开这个面板的)能够模拟部分系统设置,比如亮暗模式、打印模式、高对比度和减少动态效果等。

与之对应地,可以扩展一个概念叫做 CSS 的媒体查询,CSS 还可以探测到很多用户设备的属性或者设置,比如设备指针精度、视窗比例、当前是否全屏模式、设备方向等…

能探测的内容很多,但实际能用起来的可能只有寥寥数个,最全面的信息可以取 MDN 上查看。

编辑网页文字样式

Devtools 还提供了一个新的字体编辑器,能够让我们实时更改网页中的字体家族、字体大小、字重等属性。

编辑网页内容

我们在 Devtools 控制台里面执行代码document.designMode = 'on' 后,就可以实时在本地修改网页文字内容了,就跟平常打字一样。很适合用在测试文案长度的场景。最后也会分享一个浏览器插件,能够对网页做更多的编辑。

审查 React 组件

最后介绍一个审查 React 组件的方法,有时候我们想看某个元素是不是用的组件库,或者这个组件包含了什么属性之类的,可以下载 React Developer Tools,然后点选网页中的任意元素,进行审查。

网页和部署

接下来我介绍一下网页构成和网站部署相关的内容。

通常来说,HTML, CSS, JavaScript 是构成网站的三个要素。其中:

  • HTML 用来用于定义网页的结构和内容,可以用来创建网站的各个部分,比如标题、段落、图片、链接等。
  • CSS 用来定义网页的样式和布局,这个可能会是咱们设计师比较熟悉的部分,我们能够利用 CSS 来定义 HTML 元素的各种样式,控制它们的布局和位置。
  • JavaScript 用来实现各种功能逻辑和操作交互。比如响应点击事件、动态修改网页内容,根据条件执行动画效果或展示特定内容等。

CSS 预处理器

上述的三种语言,都有各自对应的语法规则。而 CSS 预处理器,则改进了原有的 CSS 语法,使我们能使用更复杂的逻辑语法,比如使用变量、代码嵌套和继承等。

简单来说,CSS 预处理器能让我们写样式代码的过程更顺畅,使代码有更良好的可读性和扩展性,帮助我们更好地维护代码。

举个简单的例子,比如原本的 CSS 语法中要求我们给每一个元素写样式时,必须以花括号开始和结尾,而且每一条样式规则直接都要以分号隔开,而 Stylus 则能够让我们跳出这个限制。直接用换行和缩进来代替。

CSS 框架

另一个值得一提的概念是 CSS 框架。CSS 框架则提供了一套预设样式,比如颜色板、字体梯度,布局和断点设定等;以及一些常用组件,如导航栏、对话框和页脚等。

简单来说,就是提供了一批开箱即用的样式,便于开发者快速启动项目,同时也会保留高度自定义的空间,用于支持各种各样的需求。通常 CSS 框架都会包含使用某个 CSS 预处理器,甚至内置了一些图标库,主打一个 “开箱即用”。

这里稍微介绍一下一个 CSS 框架:Tailwind CSS。是一个高度定制化的 CSS 框架,通过大量的预定义类名,使开发人员快速构建和设计网页界面。

与其他 CSS 框架相比,有一个显著的特点是 Tailwind CSS 本身不会包装一个组件出来,比如按钮、输入框的样式,没有预设好的。取而代之的是,Tailwind CSS 将各种原子级的 CSS 类名包装起来,比如:

  • 设置左右两边的 Padding,用 px-[...] 类名来实现;
  • 设置一个元素为块级元素, 用block 类名来实现…

如果想要在 TailwindCSS 中,使用打包好的组件,达到开箱即用的效果,可以通过各种官方/非官方的模版或组件生态来进行。比如:

React

接下来介绍另一个概念:React。这是一个用于构建 Web 和原生交互界面的库(是的,它能够用来做 App,不仅仅是网页)。而且引入了 JSX 语法,将 HTML 和 JS 结合起来,以一种更直观和易于理解的方式描述界面的结构和内容。

React 有一点和我们的设计稿很像,就是它的组件思维。在构建用户界面时,React 主张先把内容分解成一个个可以复用的组件(把具体的交互、功能逻辑写在组件里面)。然后在页面中将各个组件连接起来,使数据流经它们。

下图引用了官网中的一个例子,其中:

  1. 完整的应用,可以理解为由多个组件拼接成的完成网页;
  2. 搜索组件,用来获取用户输入;
  3. 数据列表,会根据用户搜索来过滤和展示内容;
  4. 每个列表的表头;
  5. 表格内每条数据。

现在我们用一个具体例子来简单介绍下 React 的组件。

在上图中,展示了一个页面页面 App.jsx 包含了 Profile、Gallery 和 FAQ 组件,以及 Profile.jsx 组件的代码。右侧是输出页面,展示了三个组件拼接而成的页面效果示意图,其中 Profile 组件模块里展示的内容,是和 Profile.jsx 文件内代码一一对应的。

上述的组件只是将一个模块包装起来,使其能够被其他地方复用。但组件内容是固定的。接下来会为大家展示如何向组件传递 Props,实现上文提到的一句话 “使数据流经他们” 。

在上图中,我们先将一些 Props 传递给组件 Profile(比如这里传递了图片的地址、人物姓名和描述),然后在 Profile 组件内接收这些 Props,并在组件代码内使用这些数据。

现在,我们就做出了一个可以复用的组件了,可以根据不同的内容来展示相关的人物信息。

大家有没有觉得这种做法有点熟悉?是的,在 Figma 中,我们的组件里面也有类似的做法。Figma 组件同样同样传递字符串、布尔和组件等内容。

实际上 React 组件可以传递的参数不仅仅只是上面例子中的字符串和布尔值,还能传递数值、函数、对象、Node 类型甚至另一个组件等。

我做了一个简单的 Playground,提前封装好了一个 Profile 组件,会传递一些字符串、布尔值(是否展示网站标签)以及数值(圆角大小),帮助大家更好地理解。

🛝 Playground

我做了一个 🛝 Playground ,大家可以在里面看到这个组件的具体的情况,实际看一遍代码可能会帮助理解 React 的组建和 Props 概念。

同时我也写了两个小任务给到大家去尝试,大家可以在上面的编辑器中自由尝试。

发布网站

到了这里,相信大家对构建一个网站已经有了初步的认识,接下来我为大家介绍下如何将构建好的网站发布的互联网当中,能够真正地被世界各地的人们浏览。

方法一:部署到服务器

这是比较传统的方法,先将项目相关的文件放进服务器里面(比如阿里云 ECS,或轻量服务器等)。然后在服务器内安装 NGINX,索引到项目文件夹,定义好首页、端口、404 等场景,最后将域名解析到服务器 IP。之后我们的网站就能在互联网上被人们访问了。

方法二:托管到服务商

这种是相对省心的方法,将我们项目所在的 GitHub 仓库,链接到服务商的托管服务当中。等于是由服务商来帮我们部署、发布项目,不用自己来配置服务器的各种内容了。下图列举了几种常见的网站托管服务商,分别是:Vercel,Github Pages 和 Netlify。

以 Vercel 来举例,除了能够托管网站之外,对每一次发布进行管理,甚至能够是对不同代码分支进行独立发布,还能收集网站访问数据等。

网页性能

接下来为大家介绍网页性能相关的内容。通常一个网站性能好不好,我们能够在体验时主观地感受到,比如打开时很慢、滚动时卡顿,或者点击按钮后很久才响应等等。但如果要准确地判断到网页的性能到底如何,是需要依赖具体指标的。

下面介绍三个常用的指标,分别是:FCP(首次内容绘制)、LCP(最大内容绘制)以及 CLS(积累布局偏移)。

FCP(首次内容绘制)

FCP 是一个关键指标,用来测量页面从开始加载到第一个页面内容在屏幕上完成渲染的时间。越快的 FCP 时间能够让用户感知到网页有在正常运行,而不是停滞、无响应。

这里提到的 “内容” ,指的是文本、图像(包括背景图像)、<svg>元素或非白色的<canvas>元素。如下图所示,FCP 出现在第二帧。

LCP(最大内容绘制)

LCP 指的从页面开始加载到可视区域内可见的「最大图像」或「文本块」完成渲染的时间。

这里提到的「最大图像」或「文本块」,具体来说是包含<img>元素、内嵌在<svg>元素内的<image>元素、块级文本等。

而测量方式,则是在页面加载过程中,记录视窗内的元素的渲染大小,取尺寸最大的元素,回溯这个元素被完整渲染的时间。注意,如果元素的有一部分在视窗外,在视窗外的部分不会参与到尺寸比较当中。

如下图所示,LCP 发生在第二帧,因为这个时候渲染尺寸最大的文本块被渲染出来了。后续帧当中,可能渲染出了一些图片,但尺寸都比文本块小,所以文本块依然是这个视窗内的最大元素。

CLS(积累布局偏移)

CLS 是指可视区域内发生的最大布局偏移分数。简单来说就是测量页面在加载时,元素的位置出现意外的偏移情况,如果元素尺寸大,而且位置偏移比较远,那么 CLS 分数就会显著增高。

这个指标会跟实际的用户操作或者体验有直接相关,所以应该也会是咱们设计师需要重点关注的内容,因为有时候布局偏移,是会比较影响用户获取信息、或者进行操作,甚至引发一些不可挽回的损失。

然后我来介绍一下测量网页性能的工具吧。我自己用过这两个,发现其实没啥差别,大家看喜好使用即可:

两个工具都能模拟桌面设备或者移动设备,记录多项关键指标的数据,并给出改进建议。

观察页面性能情况,不仅仅是前端技术人员要做的事情,了解到设计师也是可以参与到其中的。

比如 Guillaume Granger,他会比较想控制页面中 JavaScript 的数量,所以它提到,他会将所有用了 JavaScript 相关信息记录在表格当中。之后每次在网页中使用 JavaScript 时,都会跟之前的记录进行比对,判断重要性,决定是否在这个位置上使用 JavaScript。

开发者 Thomas Kelly 则提出了当意识到页面性能出现瓶颈时,需要做的事情,比如:

  • 制定一个目标,团队一起往这个目标前进;
  • 高频收集页面性能数据;
  • 尝试用不同方式来解决同一个问题;
  • 与同伴分享对性能的一些新发现…

资源分享

最后来分享一下相关的资源吧,包含两个插件、三个学习网站以及一个 React 课程。

插件:VisBug

介绍一个谷歌官方出品的插件:VisBug,主要用来帮助用户在浏览网页时进行调试和设计,包括编辑和可视化页面的 CSS,尺寸和字体等元素。

插件:Motion DevTools

Motion DevTools 是一个检查网页动效的插件,可视化和分析用户交互设计中的滚动、动画效果,并支持实时编辑、预览或导出等功能。

网站推荐

接下来介绍三个在国内外拥有较高知名度和影响力的设计师和开发人员。他们的观点、经验分享往往能给我带来一些新的启发。尤其是他们对钻研新技术的热情,是非常强烈的。

课程推荐

最后强烈推荐一门 React 课程——The Joy of React,这个课程我在年初的文章也有提到过,是以互动式课程的形式,由浅入深地讲解 React。从基础的组件 props 和 JSX 知识,到 Hooks、API 设计等等,讲述非常清晰,强烈推荐。

分享会感想

分享完之后感觉效果可能还不错,大家都有各自的收获。而且分享会中也不时有人提出相关问题,我也一一进行解答了。

或者也有对我分享内容的一些补充,比如我在分享完 Devtools 环节的时候,有同事也分享了一个在 Application — Cookie 面板里快速切换网页语言的方法。

后面了解到大家对于 CSS 和 React 那块听的比较迷糊,因为原本没有实践过的话,会对这些没有什么概念。而且大家好像对 🛝Playground 没有什么兴趣,并没有人对里面的内容有什么提问和看法之类的,可能到这一步都比较迷糊?🤔

指标那块倒是有不少同事关心,问了几个问题,比如有哪些方法来去改进几个指标的数据,或者在设计过程中是否可以提前避免性能问题等等。

总体来说和之前的分享会相比,这次分享会的参与度比较不错。

用 Next.js 重构个人网站 (二):核心和通用模块

By: 李瑞东
19 March 2023 at 11:12
封面图:Maxime Bourgeois

一部分我会记录下在重构 LRD.IM 项目中,部分核心或比较通用功能的实现过程,以及一些我花了点巧思来设计的地方。

数据源和循环遍历

我的网站中常常会有字段是能在多个地方复用的,比如作品的标题、描述等信息。

作品集首页字段应用的示意。应用在首页、作品详情页、head 标签、复制链接时的拼接。

这些字段会在多个页面中使用,当文案调整时也需要同步改动,影响到所有相关的地方。所以为了达到「一改全改」的效果,改进网站迭代的效率,这里我会用到数据源和循环遍历来做(以前还真就手动一个个来改的)。

数据源
数据源像是一个专门存储数据的库,里面记载了某个模块会被用到的字段名称及其对应的值。这里面本身没有功能、交互和样式,就像一个仓库。作用就是给到具体的页面或者组件来调用。

循环遍历
有了数据源之后会需要将其逐个安放进统一的容器里面。容器的样式是一致的,布局和适配也通过 CSS 来统一处理好,只是里面的文本、配图、跳转链接等这些属于数据源的内容有差异,所以这里会用到map()来遍历数据,将数据逐一安放进容器里。

功能实现

构建数据源
举个例子,「作品」页面包含了好几个字段:

  1. 公司名称
  2. 公司 LOGO 图片链接
  3. 公司官网网址
  4. 公司相关作品
  5. 作品名称
  6. 作品描述
  7. 作品缩略图链接
  8. 作品跳转链接

这其中「公司」和「作品」是一对多的关系,一个公司可以对应有多个作品。所以这里据源的结构是:

const ProjectItemData = [
{
name: "公司名称",
img: "公司 LOGO 图片链接",
url: "公司官网网址",
projects: [
{
title: "作品名称",
desc: "作品描述",
img: "作品缩略图链接",
url: "作品跳转链接",
},
],
},
];
export default ProjectItemData;

应用在实际页面中

数据源在我的网站里有两种使用方式:直接引用数据源里的某一个字段,或者通过遍历循环来填充进容器里面。

直接引用字段
比如作品详情页里面的 <head> 标签,需要将作品标题,siteMetadata 里的一个字段拼接,我会直接将他们引用到页面当中。

// 导入数据:
import siteMetadata from "/data/siteMetadata";
import ProjectItemData from "/data/ProjectItemData";

// 使用数据:
const title = ProjectItemData[2].projects[0].title; // 指定获取某个字段
<title>{title} - {siteMetadata.title}</title> // 应用在页面中

// 输出:
// <title>SHOPLINE App 组件库构建 - 李瑞东 LRD.IM</title>

循环遍历,将内容逐一填进容器
LRD.IM 的首页会列出我之前任职公司时的实际项目,实际上这就可以将一组数据按顺序地填入设定好样式和交互的容器当中。

我使用 Array.prototype.map() 来实现这个循环遍历。

import ProjectItemData from "/data/ProjectItemData";  //导入数据源
<>
{ProjectItemData.map((company) => ( //查找数据源中的一级数据
<div>
<Image src={company.img} /> //公司 LOGO 图片
<Link href={company.url}> {company.name} </Link> //公司名称,点击跳转到公司官网网址
</div>
<div>
{company.projects.map((project) => ( //查找数据源中的二级数据
<Link href={project.url}> //作品跳转链接
<Image src={project.img} /> //作品缩略图
<h3>{project.title}</h3> //作品名称
<p>{project.desc}</p> // 作品描述
</Link>
))}
</div>
))}
</>

影响范围

数据源循环遍历这个做法频繁出现在重构后的个人网站里。除了上面提到的首页作品列表,还有比如网站的 Header 导航栏、作品详情页平铺图片的模块、以及 What’s New 页面的内容等等。

map 遍历用在Header 导航栏、作品详情页平铺图片的模块、以及 What’s New 页面的内容的示意图

如果后续某一个模块的内容需要增删改,我只要修改数据源里面的内容,操作完之后在具体页面中检查一遍就可以了。再也不用在编辑器里打开数十个 html 文件逐个修改了。也不用在一堆代码高亮后的标签内寻找内容了。

一个模块或组件对应一个数据源,然后数据也和页面分离,👍🏻。

不得不接受的局限性

这个看似完美的功能实际上也会有一个令我有点难受局限性。前文提到一句话:

有了数据源之后会需要将其逐个安放进统一的容器里面…

这种按部就班,放进「统一的容器」里的做法会丧失灵活性,比如在:一组容器里面我想要特意给某一个容器添加样式,或者某个字段的值是字符串,我想给里面的某个词语设定一个样式。这似乎不容易办到。

具体来说,在我前年写的一篇「Apple 官网里三个令我惊叹的中文排版细节」里,我学会了给标题或重要文本的最后一个词语和标点设置一个不换行的样式white-space: nowrap;来防止出现孤字,这是需要在 HTML 内对单独每一句话来设定的样式。

重构前避免出现孤字的做法

而通过数据源来填充文本内容,我似乎没法进行这样的操作了。所以重构后的网站,一些地方可能会出现无法避免的孤字。

后续我会继续关注这个问题,尝试找到低成本的解决办法。这并非毫无希望,起码最近有了解到 React Wrap Balancer 这个组件似乎能改善孤字的现象,后续我会继续跟进。有新进展也会在博客里更新。

React Wrap Balancer 的效果预览动图。
当前的解决方案:关键内容/复用较少的内容会写在 JSX 中,而不使用数据源,给到最大的灵活性。而像大标题或副标题,则是使用了 word-break: keep-all; 的方式减少孤字出现的可能性(参考此处)。其他更细的情况无处理。

深色模式

重构前的 LRD.IM,网页的深色和浅色模式是只会跟随用户系统设置的,而这次做到的效果是:

  1. 默认颜色主题跟随用户系统设置;
  2. 允许有一个按钮来切换深色或浅色模式;
  3. 手动更改过颜色主题后,访问网站内其他页面也会受到影响;
  4. 页面加载、跳转时没有背景色闪烁。

深色模式在 Next.js 和 Tailwind CSS 结合使用的时候会变得无比简单。

功能实现

功能上我是跟着 Danilo Leal 博客里的这篇文章,一步一步实现适配到深色模式的。主要是使用了 next-themes 提供的能力。没什么难度和卡点。

样式支持

标题是 Tailwind CSS 3.2 的配图,使用科技风格的蓝紫色渐变作为背景,图片来自 Tailwind CSS 官方。
图片来自 Tailwind CSS

使用 Tailwind CSS 之后,设计深色模式的样式也变得简单很多了。只要在类名前加上dark:,比如这样:text-neutral-800 dark:text-neutral-100,dark:后面的内容就是当切换成深色模式后的样式。

而且在与媒体查询、:hover、:active 等效果配合使用时候,也可以直接叠加,不需要在 CSS 内过多的声明或嵌套。

比如一个按钮的背景色,在不同的颜色主题和状态(默认或 :hover)下色值会不同。同时我也希望在移动端设备尺寸下,不要有 :hover 改变背景色的效果。那么类名大概会是这样:

<Button
className="
bg-neutral-100 //浅色模式时,按钮的默认背景色
dark:bg-neutral-900 //深色模式时,按钮的默认背景色
sm:hover:bg-neutral-200 //视窗宽度是移动端以上时,:hover 状态的背景色
dark:sm:hover:bg-neutral-800 //深色模式且视窗宽度是移动端以上时,:hover 状态的背景色
">...
</Button>

在我看来,这种做法比传统的 CSS 做法更直观,不用专门语义化一个颜色,或者在冗长的 CSS 里维护两套主题色。所以得益于使用了 Tailwind CSS,我在写样式的时候效率提升了很多。

使用外部组件/图标库

这里可以记录一个我做成了响应式适配的组件:Header。在宽度足够时会将各页面入口平铺展示;而在移动端尺寸下,会收起在一个按钮中,点击后展开一个菜单,在里面提供页面和功能的入口。

拖动右侧手柄,缩小容器宽度来查看 Header 组件的适配的效果。默认是按钮平铺展示,容器宽度小到一定程度后将按钮收在汉堡包菜单中,点击图标出现相应的按钮。

组件

实际上我是通过媒体查询视窗宽度来实现的响应式适配。Header 操作区会分成两部分,一部分是平铺的按钮,另一部分是菜单功能。即:

  1. 当视窗宽度 > 移动端尺寸时,菜单功能的按钮被隐藏;
  2. 而视窗宽度 ≤ 移动端尺寸时,平铺的按钮被隐藏。
<>
<div className="hidden sm:block"> // 平铺的按钮,视窗宽度 > 移动端尺寸时出现
<Link>作品</Link>
<Link>博客</Link>
<Link>关于我</Link>
</div>
<div className="sm:hidden"> // Headless UI 的菜单组件,视窗宽度 ≤ 移动端尺寸时出现
<Menu> ... </Menu>
</div>
</>

至于展开的菜单,我是用了 Headless UI 的 Menu 组件来实现的(经过轻微改造),这里面内置了展开收起的动画,以及无障碍访问相关的特点。组件挺好使的,而且文档也很完善,提供了很多功能和描述。

Headless UI 的 Menu 组件界面截图

重构后博客文章里的目录,我也是用类似的方法来做响应式适配的。这部分的内容在下一篇文章中呈现。

图标

虽然说在工作上我做过不少图标,也负责过图标库的管理和迭代。但在这次重构 LRD.IM 的项目中,我没有自己去设计图标,用的都是外部资源。

因为在我看来图标只要能辅助表达出意思就行了,没有必要在这上面花太多功夫。把时间和精力放在其他更有意义的地方。

网站中我主要依赖外部的图标库 React-Icons。里面包含了很多主流图标库的内容,比如:Ant Design、Boostrape、Remix 等等。

React-Icons 网站界面截图

而我主要使用了 Ionicons 5 系列的图标,比较符合设计风格。用起来很简单快捷:

import { IoLink, IoList } from "react-icons/io5"; // 加载图标库

<IoLink /> //直接使用图标
<IoList className="text-xl" /> //为图标添加样式
使用框架来构建网站的好处是:能够很方便地用上各种插件和库。这是在旧版网站里不敢想象的事情。

The Joy of React 课程的收获

上一篇文章中提到在项目后期我参加了 The Joy of React 课程,在系统地学习了一些 React 的知识后对代码做了些改进,比如对图片展示组件的改进。

设计图片组件

在我的作品详情页面中,「图片」是一个会被频繁用到的媒体。而图片的呈现又有多种方式。

用三张截图分别展示图片组件的多种变量。从上至下分别是图片尺寸、图片描述、长图滚动和图片放大。

上图中能看到,我的图片组件会有六个属性允许配置或填写。

  1. src:填入图片的路径(必须)
  2. alt 文本
  3. 图片尺寸:大 / 小
  4. 图片滚动:允许 / 禁止
  5. 点击放大:允许 / 禁止
  6. 图片描述:内容 / 为空

而其中这几种属性可以互相组合,比如:

  1. 大尺寸图片 + 允许滚动 + 禁止点击放大 + 有图片描述
  2. 小尺寸图片 + 禁止滚动 + 允许点击放大 + 无图片描述
  3. 小尺寸图片 + 允许滚动 + 禁止点击放大 + 无图片描述

所以我在设计的图片组件时,开放了这些属性,允许在页面中自由配置某一张图片的样式和功能。同时将常被用到的属性会被设定为默认值,尽量减少在页面中的代码量。得出这样的一个 API:

export default function ProjectImage({ src, alt, size, scroll, zoom, children }) {
return (
<>
<figure className={scroll === true ? "scroll" : ""}> //scroll 为 true 则添加允许图片滚动的样式
<div className={`${size === "small" ? "max-w-2xl" : ""}`}> //scroll 为 small 则添加限制图片容器宽度的样式
{zoom === false ? ( //zoom 被设置为 false 时,使用不能点击放大的图片组件
<Image
src={src} //读取外部填写的图片路径
alt={alt} //读取外部填写的图片 alt 文本
/>
) : (<Zoom //zoom 被设置为 true (默认值)时,使用允许点击放大的图片组件
src={src}
alt={alt}
></Zoom>
)}
</div>
</figure>
{children && <figcaption>{children}</figcaption>} //children 非空时,将其渲染出来
</>
);
}

同时又存在着一个互斥关系,比如:允许滚动的图片,禁止点击放大;禁止滚动的图片,允许点击放大。(因为当下我用到的图片放大组件对长图片的支持并没有很完美),补充相应代码:

export default function ProjectImage({ src, alt, size, scroll, zoom, children
}) {
zoom = !scroll;
return (
<>...</>
);
}

最后在页面中使用该组件时,只需要填上必填的src,如果有其他尺寸或滚动上的属性配置,也传递进去就好了。

//默认:大尺寸图片 + 禁止滚动 + 允许点击放大 + 无图片描述
<ProjectImage src="01.png" />

//配置为:大尺寸图片 + 允许滚动 + 禁止点击放大 + 有图片描述
<ProjectImage src="02.png" scroll={true}>
一个文本示例。
</ProjectImage>

//配置为:小尺寸图片 + 禁止滚动 + 允许点击放大 + 有图片描述
<ProjectImage src="03.png" size="small">
另一个文本示例。
</ProjectImage>

可以对比一下在使用组件前后,源文件的对比。代码可读性提高了许多,同时也更方便管理和迭代了。

后如果我想有什么调整或者新功能,只要改动组件就好,再也不用在编辑器里打开数十个 html 文件逐个修改了。也不用在一堆代码高亮后的标签内寻找内容了。

用两张在代码编辑器里的截图展示使用组件前后,源文件代码量的对比。左侧是使用前,用红框标记代码量,一共 43 行代码;右侧是使用后,用绿框标记代码量,一共是 11 行代码。

图片组件比较常用,后面也会根据具体用途的变动和个人能力的长进来不断优化。

预告

下一篇文章将会介绍我是如何使用 mdx-bundler 来重构整个博客功能模块,包括 mdx-remark 插件、内容生成方式、目录组件、RSS 生成等内容。以及我为了增强阅读体验所做的工作。敬请期待吧~(自说自话 🙄)

本文于 2023 年 03 月 12 日首发于 LRD.IM
❌
❌