MoreRSS

site iconZhangXinXu | 张鑫旭修改

出版《CSS选择器世界》,喜欢钓鱼、写作。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

ZhangXinXu | 张鑫旭的 RSS 预览

Canvas也支持锥形渐变了createConicGradient方法

2025-10-27 15:43:08

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11914
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

封面图

一、千呼万唤始出来

好消息,Canvas也支持锥形渐变了,方法名称是createConicGradient()方法。

兼容性参见下图:

canvas锥形渐变兼容性

所有现代浏览器都已经支持,且已经支持了2年了。

需要使用Canvas锥形渐变的场景

最近遇到了个需求,必须使用Canvas实现锥形渐变,而不能是CSS。

那就是下图所示的饼图效果:

饼图需求示意

如果单论实现,无论是CSS还是Canvas都可以,CSS更佳,因为成本更低。

但是,注意看图片的左上角,还有一个下载为图片的功能。

html2canvas是不支持CSS锥形渐变的,保存的图片是空白。

所以需要Canvas实现,转换为图片,这样就能截图保存了。

canvas实现锥形渐变效果图

也是就用到了这个createConicGradient()方法来绘制饼图。

二、createConicGradient语法

语法如下:

createConicGradient(startAngle, x, y)

表示创建一个锥形渐变开始的位置。

其中startAngle是锥形的圆弧所在,需要注意的是,和CSS不同,在Canvas中,角度0表示的是三点钟方向,有就是水平朝右,但是CSS是12点钟方向,垂直朝上。

我们通过一个案例来了解下createConicGradient()方法是如何使用的。

<canvas></canvas>

绘制代码为:

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

// 尺寸
const size = 300;
canvas.width = size;
canvas.height = size;

// 创建锥形渐变
const gradient = ctx.createConicGradient(-0.5 * Math.PI, size / 2, size / 2);

// 色带颜色
const arrColor = ['#10239E', '#2F54EB','#597EF7', '#85A5FF', '#D6E4FF'];
// 各自占据的百分比
const arrPercent = [0.07, 0.13, 0.2, 0.27, 0.33];

// 添加中断点
let sumPercent = 0;
arrPercent.forEach((percent, index) => {
  gradient.addColorStop(sumPercent, arrColor[index]);
  sumPercent += percent;
  gradient.addColorStop(sumPercent, arrColor[index]);
});

// 设置渐变为填充样式
ctx.fillStyle = gradient;
// 绘制圆形
ctx.ellipse(size / 2, size / 2, size / 2 - 30, size / 2 - 30, 0, 0, 2 * Math.PI);
// 填充
ctx.fill();

在浏览器中的实时绘制效果如下:

完美!

在过去,本文所展示的饼图效果,我们可以使用arc()扇形绘制方法模拟,非本文重点,不做展开。

三、结语

如果你让AI实现锥形渐变,大概率会使用CSS conic-gradient()锥形渐变,但是你让他解决html2canvas无法导出图片的问题,AI就会扯东扯西,不知道该如何是好了。

所以,新时代,我们学习前端,可能具体的技术细节不需要掌握,但是,结构、方向、策略、细节还是需要掌握的。

比方说本文的案例,你需要知道使用Canvas来绘制渐变,指导AI使用这个方法,他就能搞定,否则,AI就会迷路。

其中这样的例子很多。

例如,之前有同事想要在手机端实现划词交互效果,问AI,结果AI弄了一大堆代码,使用鼠标事件实现的,很啰嗦。于是同事就问我,我就说试试selectionchange事件,这么一点拨,AI立马就糊涂状态变成了大师。

还有案例,可编辑输入框类似于AT成组的交互,AI的实现也是,洋洋洒洒,代码多得不得了,感觉把整个编辑器都弄进来了。

实际,走DOM监控单向数据流,就百来行代码的事情。

所以说,学习新特性还是有用的。

我也不会担心自己被AI取代,只要持续学习,不排斥新事物,我只会比之前更加具有竞争力。

好了,又扯多了,最后,我家侍妾慕沛灵压阵,道友请转发!

慕沛灵 常服 红色

😉😊😇
🥰😍😘

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11914

(本篇完)

CSS reading-flow和reading-order属性简介

2025-10-20 17:56:39

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11889
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

继续介绍前端前沿新特性,这次介绍的是两个改进键盘无障碍访问的CSS属性reading-flowreading-order

一、Tabindex属性的问题

在Web开发中,DOM文档的属性和视觉表现顺序不一致是很正常的。

但是,此时,如果我们不进行干预,用户在使用Tab键进行索引访问的时候,顺序就会出现问题,导致困惑。

在过去,我们会使用tabindex属性进行交互处理。举个例子:

<div class="box" aria-owns="第一 第三 第二">
  <a href="#" tabindex="1" id="one">第一</a>
  <a href="#" tabindex="3" id="two">第二</a>
  <a href="#" tabindex="2" id="three">第三</a>
</div>

tabindex值为3的地2项就会被最后一个获取。

关于tabindex属性的具体规则,可以参见我之前的文章“HTML tabindex属性与web网页键盘无障碍访问”,或者购买《HTML并不简单》这本书,其中有详细介绍。

在比较简单的页面,我们使用tabindex属性是没问题的,但是页面比较复杂,有非常多的地方有类似的结构,那就会出现tabindex设置冲突的问题,因为tabindex的索引控制是全局的。

对于,对于这种局部布局的tabindex属性调整,需要有更加友好的特性,在这种背景下,reading-flowreading-order属性应运而生。

二、重点关注reading-flow属性

在大多数场景下,我们都是使用reading-flow属性,且需要与Flex布局和Grid布局配合使用。

我们先看使用案例,HTML和CSS代码如下所示:

<div class="box">
 <a href="##">张</a>
 <a href="##">鑫</a>
 <a href="##">旭</a>
</div>
.box {
  display: flex;
  :nth-child(1) {
    order: 2;
  }
}

实时效果如下所示,您可以尝试使用 TAB 键查找下一个可聚焦元素,使用 TAB+SHIFT 键查找上一个可聚焦元素,观察焦点聚焦的顺序。

友情提示,可以先点击框框的空白处,再按下Tab键,下同。

结果会发现,第一个被聚焦的元素是视觉表现上排在随后的元素,如下截图所示:

键盘聚焦顺序

这就会产生困惑,对吧,此时我们可以使用 reading-flow 属性优化此问题,一行代码的事情:

.box {
  reading-flow: flex-visual;
}

我们再来看下实时渲染效果(Chrome 137+):

此时第一个聚焦的元素就是最前面的“鑫”字啦。

第一个聚焦示意

flex-flow的作用

如果Flex容器设置设置reading-flow:flex-flow,那么,浏览器读取内容的方向就会和flex-flow属性保持一致。

PS:flex-flow属性是flex-directionflex-wrap属性的缩写属性。

例如flex容器新增CSS样式:

.box {
  flex-direction: row-reverse;
  reading-flow: flex-flow;
}

那么焦点聚焦的顺序就会是“鑫-旭-张”,从后往前依次聚焦,实时渲染效果如下:

如果我们取消第一项所设置的order:2,焦点方向还是从后往前,也就是按照Flex方向的聚焦顺序,不受DOM在文档中的顺序影响。

三、Grid布局中的reading-flow属性

由于Grid是二维布局的,因此,在Grid布局中,reading-flow属性支持的值要多一些,示意:

reading-flow: grid-columns;
reading-flow: grid-rows;
reading-flow: grid-order;

还是通过案例进行学习。

HTML基本结构和CSS如下:

.wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
}
.wrapper a:nth-child(2) {
  grid-column: 3;
  grid-row: 2 / 4;
}
.wrapper a:nth-child(5) {
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}

此时的布局效果渲染如下,Tab索引顺序则按照DOM的顺序执行,也就是甲乙丙丁戊,但是,这并不是布局上的视觉顺序。

如果我们希望Tab顺序按照视觉顺序水平聚焦,则就可以设置:

.wrapper {
  reading-flow: grid-rows;
}

实时渲染效果如下:

此时,焦点聚焦的顺序就是“戊-甲-乙-丙-丁”,如下示意图所示:

Gird布局横向聚焦顺序示意

再看看grid-columns的效果:

.wrapper {
  reading-flow: grid-columns;
}

可以键盘访问下面的布局亲自感受焦点顺序(Chrome 137+):

此时,焦点聚焦的顺序就是“戊-丙-丁-甲-乙”,如下示意图所示:

垂直方向视觉焦点

关于grid-order

这个用在使用order属性改变网格顺序的场景下,此时,焦点属性会优先按照order属性切换,例如:

.wrapper {
  reading-flow: grid-order;
}
.wrapper a:nth-child(4) {
  order: -1;
}

此时,优先被聚焦的是“丁”这个设置了order:-1的网格。

实时效果:

四、什么时候使用reading-order属性

reading-order属性通常和reading-flow:source-order声明配合使用,可以强制任意布局中,子项的焦点获取顺序,值为数值,可以是负值,例如:

<div class="follow">
 <a href="##">欢迎</a>
 <a href="##">抖音</a>
 <a href="##">关注</a>
<a href="##" class="me">最会钓鱼的程序员</a>
</div>
.follow {
  display: flow-root;
  reading-flow: source-order;
}
.me {
  reading-order: -1;
}

实时效果如下,可以看到,我的抖音钓鱼账号的名称“最会钓鱼的程序员”被第一个聚焦了!

截图示意:

聚焦order设置

四、兼容性、结语

目前reading-flowreading-order属性仅Chrome浏览器,极其使用其内核的浏览器支持:

reading-flow兼容性

不过此特性是渐进增强特性,可以放心使用,基本上,我建议,只要是Flex布局,都可以加上reading-flow:flex-visual这么一句话,浏览器不支持,或者Flex布局本身顺序正常,那就还和现在一样,但是如果浏览器支持,用户的无障碍访问体验就会UP,这种只有好处,没有坏处的事情,没有理由不去做他!

结语碎碎念

这些边边角角的CSS新特性实在是太多了,我每周介绍一个,感觉都来不及。

但是,怎么讲呢?大多都是锦上添花的东西,现有的技术也能解决,但是由于兼容性等原因,学了,也不能立即使用,这就导致这些新特性啊,大多都会湮没在时代的洪流中。

以后这种学习的事情啊,我觉得都会交给AI了。

来,我的仆人AI酱,帮我把这段代码的无障碍访问体验提高下。

然后AI酱:“好滴,我最美丽的主人,让我看看这段代码,哦,这样子,我明白了,确实可以提升,我搜到了一个名叫钓鱼佬的博客,里面有介绍到reading-flowreading-order属性,可以一用……”

瞧瞧没,需要学习吗?不需要。

那我写这些东西还有什么意义呢?值得深思的问题。

好了,就这样吧,感谢阅读,欢迎转发,在新特性的学习这方面,人类比AI还是有个半年到一年的优势的。

有请落云宗柳玉掌门压阵:

柳玉

😉😊😇
🥰😍😘

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11889

(本篇完)

CSS field-sizing属性简介

2025-10-13 11:59:37

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11880
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

封面图

一、长话短说

CSS field-sizing是一个CSS新特性,专门给输入型表单元素使用的,例如<input><textarea>元素等。

是这样的,在过去,无论是单行输入框,还是多行文本域,其宽度在内容输入的时候,都是固定的,如果希望尺寸跟着内容的宽度走,需要使用JavaScript代码帮忙处理,现在,无需这么麻烦,使用field-sizing设置下就好了,例如:

input { field-sizing: content }
<input placeholder="输入内容">

此时,你在输入框内键入内容,可以看到,输入框的宽度基于你输入的内容多少自动撑大或缩小了。

实时效果如下所示(Chrome 123+,或者最新的Safari),大家可以再下面的输入框随便写点什么内容:

是不是可以看到,输入框的宽度紧跟着文字内容多少变化了?

二、语法速览

语法很简单,就下面这几个属性值:

field-sizing: content;
field-sizing: fixed;

其中:

  • fixed是默认值,表示尺寸固定。
  • content表示尺寸根据内容多少进行变化。

没什么好讲的。

三、补充说明

一些补充说明:

  • 当输入框设置了field-sizing:content声明的时候,原本会影响尺寸的size属性就会变得无效。
  • textarea元素的rowscols属性也会无效。
  • field-sizing属性也可以用在<select>元素上。
  • 实际使用的时候,可以配合min-widthmax-width属性限制输入框的最小尺寸和最大尺寸。避免内容过多的时候,影响排版布局。

四、打道回府

好了,其实就这么点内容,我觉得这个特性还是有点用处的。

最后,兼容性:

field-sizing兼容性

Safari已经明确支持了。

好,就这么多!感谢阅读,欢迎点赞,转发。

😉😊😇
🥰😍😘

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11880

(本篇完)

使用Intl.Segmenter返回更准确的字符长度

2025-09-30 10:57:06

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11883
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

分词与字符长度

一、Emoji字符长度问题

我们平常获取字符串的长度都是直接使用length属性,但对于某些字符,返回的结果会在预期之外,例如:

"鑫空间".length

"🌝".length

"🇮🇳".length

"👨‍👩‍👧‍👦".length

"दरबार".length

结果如下:

"鑫空间".length // 3

"🌝".length    // 2

"🇮🇳".length    // 4

"👨‍👩‍👧‍👦".length    // 11

"दरबार".length  // 5

看到没,看起来Emoji表情字符的长度是1,但是,实际返回的Emoji长度并不是1,不仅不是1,不同的Emoji返回的长度还不一样,这就会给我们精确统计字符长度带来困扰。

怎么办呢?

二、返回字符的真实长度

我们可以使用Intl.Segmenter()返回字符串的真实长度,例如,我们不妨给字符串扩展一个名为 realLength 的方法,完整代码如下所示:

Object.defineProperty(String.prototype, 'realLength', {
  get: function() {
    return Array.from(
      new Intl.Segmenter("en", {
        // 颗粒度:字位,默认值,可省略
        granularity: "grapheme" 
      }).segment(this)
	).length;
  }
});

此时,我们就可以返回字符串真实的长度了。

"鑫空间".realLength // 3

"🌝".realLength    // 1

"🇮🇳".realLength    // 1

"👨‍👩‍👧‍👦".realLength    // 1

"दरबार".realLength  // 4

是不是很美丽?

紫灵

三、Emoji字符长度不是1的原因

JavaScript使用UTF-16编码,这种编码方式最多支持 2x 16 共 65,536 个字符,6万多个字符看起来多,但是世界上那么多语言,已经不够用了,尤其Emoji表情字符,都在65,536 个字符开外。

JS想要表示,只能组合多个特殊的 2 字节代码单元以生成人类可读的字符。

例如:

Array.from({ length: "🌝".length }, (_, i) => "🌝"[i])
// [ '\ud83c', '\udf1d' ]

于是,JS代码直接使用length属性访问的时候,返回值就是2,但是人类理解肯定是1个字符。

这就是Emoji字符长度不是1的原因。

四、关于Intl.Segmenter

Intl.Segmenter 是 JavaScript 中一个专门用于文本分段的强大工具,它能够根据不同的语言和文本规则,将字符串智能地分割成有意义的单位,如字符、单词或句子。

核心概念与语法

Intl.Segmenter 的核心作用在于进行语言敏感的分段。

传统的字符串分割方法(如 split(‘ ‘))对于英语这类使用空格分隔单词的语言勉强适用,但对于中文、日文等不依赖空格的语言就无能为力了,甚至处理包含复杂表情符号(Emoji)的文本时也会出错。

Intl.Segmenter 则依据 Unicode 标准,能够理解不同语言的语法习惯,进行精准的边界检测。

使用示意:

const segmenter = new Intl.Segmenter([locales[, options]]);

其中:

locales
表示语言,使用一个 BCP 47 语言标签的字符串,如 “zh-CN”、”en-US”、”ja”等。它指定了分段所依据的语言规则。如果省略,则会使用运行时环境的默认语言设置。
options
可选参数,包括下面这些:

granularity

表示分段的粒度,是最重要的选项。可取值为:

  • “grapheme”(默认值):在用户感知的字符(字形簇)边界分割。例如,一个基础字符加上修饰符(如 “a” + “́” 组成 “á”)会被视为一个整体,复杂的 Emoji 序列(如家庭表情 👨‍👩‍👧‍👦)也不会被拆散。
  • “word”:在单词边界分割。它能正确识别中文的词汇单元(如将“我真的很强”分割为“我”、“真的”、“很”、“强”),并能区分标点符号和空格(isWordLike 属性为 false)。
  • “sentence”:在句子边界分割。它能智能区分句号的不同用途,例如不会将数字 “100.000” 中的点号误判为句子结束。

localeMatcher

指定所使用的语言匹配算法,可以是 “best fit”(默认值,使用环境提供的可能最匹配的算法)或 “lookup”(使用特定的 BCP 47 算法)。

基本使用方法

创建分段器实例后,通过调用其 segment(inputString) 方法对文本进行分段。该方法返回一个 Segments 可迭代对象。

例如:

// 创建一个中文词段器
const segmenter = new Intl.Segmenter('zh-CN', { granularity: 'word' });
const text = "《HTML并不简单》是国内唯一一本精讲HTML的技术书籍";
const segments = segmenter.segment(text); // 返回一个 Segments 对象

// 遍历
for (const segment of segments) {
  console.log(`片段: "${segment.segment}", 起始索引: ${segment.index}, 是否像词: ${segment.isWordLike}`);
}

在我的Chrome浏览器下,输出的结果是:

// 片段: "《", 起始索引: 0, 是否像词: false
// 片段: "HTML", 起始索引: 1, 是否像词: true
// 片段: "并不", 起始索引: 5, 是否像词: true
// 片段: "简单", 起始索引: 7, 是否像词: true
// 片段: "》", 起始索引: 9, 是否像词: false
// 片段: "是", 起始索引: 10, 是否像词: true
// 片段: "国内", 起始索引: 11, 是否像词: true
// 片段: "唯一", 起始索引: 13, 是否像词: true
// 片段: "一本", 起始索引: 15, 是否像词: true
// 片段: "精", 起始索引: 17, 是否像词: true
// 片段: "讲", 起始索引: 18, 是否像词: true
// 片段: "HTML", 起始索引: 19, 是否像词: true
// 片段: "的", 起始索引: 23, 是否像词: true
// 片段: "技术", 起始索引: 24, 是否像词: true
// 片段: "书籍", 起始索引: 26, 是否像词: true

可以看到浏览器自带对中文句子进行分词了。

兼容性

目前Intl.Segmenter所有现代浏览器均已支持,前端也能自动分词分句了。

Intl.Segmenter兼容性

五、结语

Intl命名对象还有很多其他方法,多是与语言、金钱、数字、字符处理相关的。

详见我之前的这篇文章:“JS Intl对象完整简介及在中文中的应用

还是非常强大与实用的。

就是语法复杂了点,学习成本比较高,真正使用的时候,需要去搜索查找资料。

不过现在都有AI了,只需要知道有这么个东西就好了,AI会帮你搞定。

行吧,就说这么多。

明天就是国庆节了,祝大家国庆节快乐!

不说了,我要准备出发去钓鱼了!

欢迎大家关注我的钓鱼账号:“最会钓鱼的程序员”。

随时了解我国庆节的战况。

张鑫旭本人

😉😊😇
🥰😍😘

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11883

(本篇完)

CSS scroll-target-group加:target-current滚动菜单自动高亮

2025-09-19 20:12:32

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11837
本文可全文转载,但需要保留原作者、出处以及文中链接,AI抓取保留原文地址,任何网站均可摘要聚合,商用请联系授权。

一、又一个JS交互被干掉了

本文要介绍的 CSS scroll-target-group属性以及:target-current伪类,可以实现滚动的时候,基于位置不同,对应的菜单项自动高亮的效果。

关于这种效果的实现,我之前还专门写文章介绍过:“尝试使用JS IntersectionObserver让标题和导航联动”。

没想到,短短几年之后,纯CSS就能实现这样的效果了。

眼见为实,滚动下面内嵌的局部滚动条(需要Chrome 140+),大家就可以看到对应的效果了。

  • 前言
  • 第1章
  • 第2章
  • 欢迎来到我的博客

    滚动该页面,观察右上角的导航菜单,会发现当前所在的章节会被高亮显示。

    前言

    本博客09年更新到现在,已经16年历史了,见证了自己的成长,以及前端行业的发展。

    如果你觉得其中的内容还不错,欢迎分享,欢迎点赞。

    第1章

    第1章的内容

    也欢迎关注我的抖音账号“张鑫旭本人”。

    第2章

    我平时还喜欢钓鱼,钓友可以关注我的抖音账号“最会钓鱼的程序员”。

    或者参见下图所示的GIF效果。

    滚动导航自动高亮

    是不是很赞?

    二、如何实现导航菜单匹配?

    实现代码非常简单,HTML代码就下面这些:

    <menu>
        <li><a href="#intro">前言</a></li>
        <li><a href="#ch1">第1章</a></li>
        <li><a href="#ch2">第2章</a></li>
    </menu>
    
    <article>
        <h1>欢迎来到我的博客</h1>
        <section id="intro">...</section>
        <section id="ch1">...</section>
        <section id="ch2">...</section>
    </article>

    CSS代码也非常简单,就这么点内容:

    menu {
        position: fixed;
        scroll-target-group: auto;
    }
    
    a:target-current {
        color: red;
    }

    结束了,就结束了,对吧,给菜单容器设置scroll-target-group:auto,然后菜单里面的链接元素使用:target-current设置匹配样式就可以了。

    此时,链接元素对应的href锚点元素进入区域的时候,链接元素就会高亮啦!

    牛逼!

    牛逼

    三、关于scroll-target-group属性

    下面快速介绍下scroll-target-group属性。

    该属性可以让锚点元素有类似于::scroll-marker伪元素的特性( CSS Carousel API中的一个特性),关于::scroll-marker伪元素,可以参见我前几个月刚写的文章:“CSS ::scroll-button ::scroll-marker伪元素又是干嘛用的”。

    需要使用的时候,直接设置值为auto就可以了。

    兼容性

    非常新的一个特性,MDN连文档都没有,Chrome 140浏览器支持。

    scroll-target-group的兼容性

    四、关于:target-current伪类

    :target-current伪类相对支持早一些,和::scroll-marker伪元素等特性同一时间支持的,基于滚动位置匹配scroll-marker-group或者scroll-target-group里面的锚点或标记元素。

    使用示意:

    ::scroll-marker {
      background-color: white;
    }
    
    ::scroll-marker:target-current {
      background-color: black;
    }

    兼容性

    Chrome 135+浏览器支持。

    :target-current兼容性

    五、结语说明

    很好很强,静待浏览器全面支持。

    我发现CSS的野心挺大的,看架势,要覆盖几乎Web上常见的交互,JS退让为逻辑处理。

    不过一来学习成本高,二来以后有AI,三来有成熟替代方案,未来会有几个人使用呢?我看悬。

    所以前端没啥搞头了,不如来钓鱼吧,欢迎大家关注我的钓鱼账号:“最会钓鱼的程序员”。

    周周更新!

    张鑫旭本人

    😉😊😇
    🥰😍😘

    本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
    本文地址:https://www.zhangxinxu.com/wordpress/?p=11837

    (本篇完)