发布时间:2026-11-13 14:55:35 浏览次数:2
上一���博文中,我们扩充了线条对象(fabric.Line)的属性列表,使用户可以为画布中选中的线条增加或修改端点样式(多种剪头、圆形、菱形等)。
这篇博文是《前端canvas项目实战——简历制作网站》付费专栏系列博文的第五篇——右侧属性栏(字体、字号、行间距),主要的内容有:
如有需要,可以:
动手体验
CodeSandbox会自动对代码进行编译,并提供地址以供体验代码效果
由于CSDN的链接跳转有问题,会导致页面无法工作,请复制以下链接在浏览器打开:
https://cy37vt.c***.app/
动态效果演示
我们可以修改字体、字号和行间距了
作为简历,其中包含最多的就是文字。因此,文字的各种样式至关重要,我们在本节初步实现字体、字号和行间距的编辑能力。
当我们实现越来越多的编辑模块时,object-props.js文件越来越大。其中包含了很多我们为下拉菜单的菜单项设置的常量,这些常量不需要经常修改,但占据了很多行。为了避免这个文件过于庞大,以及做好Modal和View的分离,我们将这些数据拆分到一个constants.js常量文件中。
const fontFamilyOptions = [ { key: "黑体", value: "SimHei", platform: "windows" }, { key: "黑体", value: "STHeitiSC-Light", platform: "mac" }, ... "Times New Roman", "Georgia", ...];const fontSizeOptions = [ { key: "初号", value: 36 }, { key: "小初", value: 31 }, ... 9, 10, ...];const lineHeightOptions = [ 0, 2, 4, ...];export { fontFamilyOptions, fontSizeOptions, lineHeightOptions }; 我们将本节新增定义的fontFamilyOptions, fontSizeOptions和lineHeightOptions提取到了这个文件中,它们分别是字体、字号和行间距的可取值列表。
这里的3个编辑模块的代码逻辑大同小异,且互相独立,各不影响。所以仅列出fontFamily字体属性编辑模块的实现。
import { fontFamilyOptions } from "../../apis/constants"; const isWindows = navigator.userAgent.toUpperCase().indexOf("WIN") !== -1; const isMac = navigator.userAgent.toUpperCase().indexOf("MAC") !== -1; const FontFamilyWrapper = (props) => { const optionFilter = (option) => { return ( !option.hasOwnProperty("key") || (option.platform === "windows" && isWindows) || (option.platform === "mac" && isMac) ); }; const menuItems = uSEMemo(() => { return fontFamilyOptions.filter(optionFilter).map((option, index) => { let _key = option, _value = option; if (option.hasOwnProperty("key")) { _key = option.key; _value = option.value; } return ( `font-family-${_key}`} value={_value} style={{ fontFamily: _value }} {_key} ); }); }); return ( props.key} 字体 fontFamily} bordered={false} style={{ width: "100%" }} onChange={(value) = canvasAPI.updateFontProperty("fontFamily", value)}> {menuItems} ); }; 由上述代码可见,共分为4个部分,下面分别讲解:
static updateFontProperty(key, newValue) { let { activeObject, canvas } = store.getState(); ObjectAPI.updateProperty(activeObject, key, newValue); canvas.renderAll(); } 这里的代码很简单,直接调用了updateProperty方法,去更新整个Textbox的fontFamily、fontSize和lineHeight等属性。
updateProperty方法的实现在上一篇博文中有列出,这里不再赘述。如需回顾,可点击前往
在目前的实现中,我们可以直接设置整个Textbox的属性,这样其中的所有字符都会设置为相同的属性。但有时,我们会选中其中的部分文字,然后单独更新它们的属性。 这个时候就需要更加细致的实现来区分两种情况。
首先确定目标,我们要实现的效果如下图所示:
我们实现以下代码在一个CanvasAPI.js文件中:
// 1. 判断是否对整个Textbox更新属性 static shouldUpdateTheWholeTextbox(object, key) { return !object?.isEditing || key === "lineHeight"; } // 2. 更新Textbox的属性 static updateFontProperty(key, newValue) { let { activeObject, canvas } = store.getState(); if (this.shouldUpdateTheWholeTextbox(activeObject, key)) { CanvasAPI._updateFontPropertyForWholeObject(key, newValue); } else { CanvasAPI._updateFontPropertyForSelection(key, newValue); } canvas.renderAll(); } // 3. 更新整个Textbox的属性 static _updateFontPropertyForWholeObject(key, newValue) { let { activeObject } = store.getState(); ObjectAPI.updateProperty(activeObject, key, newValue); } // 4. 更新Textbox中当前选中的部分文字的属性 static _updateFontPropertyForSelection(key, newValue) { let { activeObject, canvas } = store.getState(); let style = {}; style[key] = newValue; activeObject.setSelectionStyles(style); } 代码逻辑比较清晰,共分为4个方法,下面分别解析:
1. shouldUpdateTheWholeTextbox方法: 判断当前状态下,应该整体更新文本框的属性,还是仅更新选中的文字的属性。逻辑上,处于非编辑态的文本框适用前者,否则适用后者。这里有一个特殊属性lineHeight行间距。根据定义,这个属性只能对整个文本框设置,不能仅对选中的文字设置。
2. updateFontProperty方法: 前文中实现过的方法,这里根据shouldUpdateTheWholeTextbox的返回值区分两种状态,调用不同的方法更新文本框属性。
3. _updateFontPropertyForWholeObject方法: 更新整个文本框的属性。
4. _updateFontPropertyForSelection方法: 仅更新文本框中当前选中的文字的属性。
按照惯例,本节的完整代码我也托管在了CodeSandbox中,点击前往,查看完整代码
这篇博文中,我们实现了对文字的字体、字号和行间距的编辑。同时,根据我们日常的使用习惯,实现了对部分用户选中的文字的属性进行单独地编辑。
作为简历中占据最大部分空间的文字对象,本章的实现很大程度上实现了用户在制作简历时的核心需要。当然,这还远远不够。在下一篇博文中,我们将实现设置文字的加粗、斜体、删除线、下划线等能力。
如有需要,可以: