第三方库笔记
2026-7-17
原始笔记链接:https://cloud.seatable.cn/dtable/external-links/59b453a8639945478de2/
0047 双向绑定和vuex是否冲突
vuex 是 vue 的状态管理工具
这个涉及的不多,这个实际上是不冲突的(新版本使用单向数据流,取消了双向绑定的情况)
可以在时间回调当中使用 mutation 修改state的值,或者是用set的双向绑定来计算属性
0103 多语言网站应该怎么处理
翻译模块 react-intl 处理 i18n
时间模块(dayjs moment)这里需要根据当地时间处理时区转换
使用一些数字和格式的模块 格式化数字和货币
0168 常用的 UI 组件库有哪些?
通用组件
用户交互组件:表单,输入框,按钮 Form Input Button Switch Popover Select
展示信息组件:Nav Card Swiper(走马灯)
提示组件:Toaster Tooltip Dialog Popover
其他特殊:图标,日历,进度条
PC 端组件库
1、ant-design:github 星标 92K,国内阿里巴巴提供技术支持,Select 组件支持单选和多选,支持50多个配置和选项。https://ant-design.antgroup.com/components/select-cn
2、element-plus:github 星标 24K https://element-plus.org/zh-CN/component/select.html#select-%E9%80%89%E6%8B%A9%E5%99%A8
3、Material-UI:github 星标 94K https://mui.com/material-ui/react-select/
4、Bootstrap:github 星标 171K https://getbootstrap.com/docs/4.0/components/forms/#select-menu
5、Semantic UI:github 星标 51K https://semantic-ui.com/collections/form.html#select
移动端组件库
主要是 ant Design mobile,现在已经到 5.x.x 参考 https://mobile.ant.design/zh/components/button
0169 你自己的项目有哪些?
这个主要是项目的页面和广度
1、文件管理项目 前端 React 文件结构
2、表格管理项目 前端 React 表格结构
3、小说编辑器 React全栈
4、校园网小程序 小程序
0178 react-dnd 实现拖拽的基本思路
基于项目中的 dnd 版本,2.6.0 版本
react-dnd 是一个支持 react 拖动库,使用了高阶组件和 redux 等设计思路,基本使用
1、设置最外层一个可拖动对象 html5DragLayer 拖动上下文
1
2
3
4
|
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
export default DragDropContext(HTML5Backend);
|
html5DragDropContext(DropTarget) 包裹被拖动组件
2、主要函数:
dragSource:拖动的源,包括 beginDrag endDrag isDragging 三个对象,用来表示拖动不同阶段返回的值(当前拖动的内容,当前拖动的索引等)
dropTarget:释放对象,包括 drop 函数,通过 monitor.getItem 获取拖动的对象,执行对应操作
dragCollect:拖动的函数收集,类似 map States to Props 函数,把外部的函数映射到内部
dropCollect:释放的函数收集,同上,把释放的函数映射到组件内部
1
|
DropTarget('ViewStructure', dropTarget, dropCollect) (DragSource('ViewStructure', dragSource, dragCollect)(Item));
|
0373 Next.js
Next.js 是一个基于 React 的开源 JavaScript 框架,用于构建服务器端渲染(SSR)和静态网站生成(SSG)的 Web 应用程序。
1. 服务器端渲染(SSR)
服务器端渲染是指在服务器上生成完整的 HTML 页面,然后将其发送到客户端。这有助于提高搜索引擎优化(SEO),因为搜索引擎爬虫可以直接抓取到完整的 HTML 内容。同时,对于初始加载速度要求较高的场景,SSR 也能提供更好的用户体验,因为用户可以更快地看到完整渲染的页面。
2. 静态网站生成(SSG)
Next.js 允许你在构建时生成静态 HTML 文件。这些文件可以直接部署到静态文件服务器上,具有极高的性能和可扩展性。静态网站生成适合内容更新不频繁的网站,如博客、文档网站等。
3. 自动代码分割
Next.js 会自动进行代码分割,将应用程序拆分成多个较小的文件。这样,当用户访问应用程序时,只会加载当前页面所需的代码,从而减少初始加载时间。
4. 路由系统
Next.js 提供了一个简单而强大的路由系统,基于文件系统。你可以通过在pages目录下创建文件来定义路由,无需手动配置复杂的路由规则。
5. API 路由
Next.js 允许你在项目中创建 API 路由,这些路由可以处理后端逻辑,如数据库查询、调用第三方 API 等。API 路由可以与前端代码共享同一个项目,方便开发和部署。
6. 支持多种渲染模式
Next.js 支持多种渲染模式,包括 SSR、SSG、客户端渲染(CSR)等。你可以根据不同的页面需求选择合适的渲染模式。
7. 优化的性能
Next.js 对性能进行了优化,包括自动优化图片、字体加载等。这些优化可以提高应用程序的加载速度和用户体验。
常用函数
getStaticProps:用于在构建时获取数据并将页面预渲染为静态 HTML。它确保数据在构建时可用,并且不会因后续请求而更改。
1
2
3
4
5
6
7
8
9
10
|
export async function getStaticProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return {
props: {
data
}
};
}
|
getServerSideProps:用于在每次请求时,获取数据,并在服务器上预渲染页面(SSR 核心)。当您需要获取可能经常更改或特定于用户的数据时,可以使用它。
1
2
3
4
5
6
7
8
9
|
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return {
props: {
data
}
};
}
|
实际的 SSR 案例:
CSR 渲染方案:使用 express,客户端访问 URL,进入路由函数,对应不同的视图函数,展示不同的 ejs 静态模板文件,返回给客户端,客户端执行 JS 代码,然后请求数据。
1
2
3
4
5
6
7
8
9
10
|
// pages/index.js
export default function Home() {
return (
<html>
<h1>客户端渲染博客列表</h1>
<div id="root"></div>
<script href="./app.bundle.js"></script>
</html>
);
}
|
SSR 渲染方案:使用 next,客户端访问 URL,进入路由函数,对应不同的视图函数,展示 ejs 模板文件中,已经包括了 JS,在服务器执行 JS 网络请求获取数据,进行渲染页面,将渲染好的页面返回客户端,实现了 SSR。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
// pages/index.js
export default function Home({ posts }) {
return (
<div style={{ maxWidth: 800, margin: '0 auto', padding: '20px' }}>
<h1>服务端渲染博客列表</h1>
<div>
{posts.map((post) => (
<article key={post.id} style={{ marginBottom: '30px' }}>
<h2>{post.title}</h2>
<p>作者:{post.author}</p>
<p>{post.content}</p>
</article>
))}
</div>
</div>
);
}
// 服务端数据获取函数(SSR 核心)
export async function getServerSideProps() {
// 在服务端请求数据(模拟 API)
const res = await fetch('https://jsonplaceholder.typicode.com/posts?_limit=5');
const posts = await res.json();
// 转换数据格式
const formattedPosts = posts.map((post) => ({
id: post.id,
title: post.title,
content: post.body, // 用接口返回的 body 作为内容
author: `作者${post.userId}`, // 模拟作者
}));
// 将数据传递给页面组件 Home
return {
props: {
posts: formattedPosts,
},
};
}
|
getStaticPaths:用于动态路由中,以指定应在构建时预渲染的路径列表。它通常用于获取带有参数的动态路由的数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
export async function getStaticPaths() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
const paths = posts.map((post) => ({
params: { id: post.id }
}));
return {
paths,
fallback: false
};
}
|
0253 axios 版本问题
升级 axios 版本问题
造成 jest 单元测试不通过的解决
本质原因:早期 axios 是 common-js 打包的,新版本没有支持 common-js 打包。Jest 执行单元测试在 node 环境下,不支持 es6 语法,所以 import axios 就会报错。解决思路是,把 import 语法替换掉
1
2
3
|
moduleNameMapper: {
'^axios$': require.resolve('axios'),
},
|
就是 module name 映射关系,把 import axios 变成 require.resolve(‘axios’) 这样 Jest 就可以测试通过了
具体参考 https://juejin.cn/post/6898738304754286605
0254 HTMLtoCanvas
HTMLtoCanvas 第三方库学习
1
|
canvas.toDataUrl('image/png', 1.0)
|
配置:
allowTaint
taintTest
allowCORS
使用场景:
统计中 canvas 导出生成 PNG,主页看板娘的 canvas 拍照显示成 png 的功能。
0259 reactstrap 中 popover 点击外部问题
Popover 点击问题:原来通过 event.target.className === ‘xxx’ 判断,这样如果改变了类名,那么这里判断失效。
最好的办法是 dom.contains() 判断 dom 之间的包含关系,至少使用 includes(‘xxx’) 的形式,避免类名变化造成的问题。如果牵头的层级比较多,这个就可能造成一个事件在树节点中依次传,性能比较差。
这样性能可能不太好。最好的办法是类似对话框,增加一个后面的遮挡,这个层监听点击事件。
0887 WebGL是什么
WebGL 是一种 3D 绘图标准,这种绘图技术标准允许把 JavaScript 和 OpenGL ES 2.0 结合在一起,通过增加 OpenGL ES 2.0 的一个 JavaScript 绑定,WebGL 可以为 HTML5 Canvas 提供硬件 3D 加速渲染,这样 Web 开发人员就可以借助系统显卡来在浏览器里更流畅地展示 3D 场景和模型了,还能创建复杂的导航和数据视觉化。
适用人群:开发 3D 模型和场景的程序员。
WebGL 涉及 JavaScript、HTML 代码,2D-3D 绘图。
英文:http://webglfundamentals.org/
在线教程 W3C:https://www.w3cschool.cn/webgl/
官网文档:http://www.hewebgl.com/
这个未来可以做一个 demo 放在展示中
案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>WebGL之3D地球</title>
<style>
/* 禁止系统默认滚动条 */
html,
body {
height: 100%;
overflow: hidden;
}
</style>
</head>
<body>
<!-- 用于显示和统计图形的性能 -->
<div id="stats-output"></div>
<!-- 作为Three.js渲染器输出3D图形 -->
<canvas id="webglcanvas"></canvas>
<!-- webgl库 -->
<script src="./libs/three.min.js"></script>
<script src="./libs/stats.min.js"></script>
<script>
</script>
</body>
</html>
|
具体 JS 代码案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
let canvas, //画布标签 绘图API
stats, //性能检测器
camera, //相机
scene, //场景
renderer, //渲染器
group, //物体组
mouseX = 0, //鼠标横向位置
mouseY = 0, //鼠标纵向位置
windowHalfX = window.innerWidth / 2, //视口大小的一般
windowHalfY = window.innerHeight / 2; //视口大小的一半
init(); //构建地球
animate(); //使地球旋转起来
function init() {
// 获取canvas画布
canvas = document.getElementById("webglcanvas");
// stats性能检测器初始化
stats = initStats();
// 3D绘制
// 相机
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 2000);
camera.position.z = 500; //相机的远近
// 场景
scene = new THREE.Scene();
// 创建一个组合
group = new THREE.Group();
scene.add(group); //将组合添加进场景中渲染
// 地球 数学形状 贴图
let loader = new THREE.TextureLoader();
loader.load("./img/land_ocean_ice_cloud_2048.jpg", function (texture) {
// console.log(texture)
let geometry = new THREE.SphereGeometry(200, 20, 20); //形状
let material = new THREE.MeshBasicMaterial({ map: texture }); //材质
let mesh = new THREE.Mesh(geometry, material); //物体
group.add(mesh);
});
// 渲染器
renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true, // true/false表示是否开启反锯齿,
/*
alpha: false, // true/false 表示是否可以设置背景色透明,
precision: 'highp', // highp/mediump/lowp 表示着色精度选择,
premultipliedAlpha: false, // true/false 表示是否可以设置像素深度(用来度量图像的分辨率),
maxLights: 3, // 最大灯光数,
stencil: false // false/true 表示是否使用模板字体或图案
*/
});
// 指定渲染器宽高
renderer.setSize(window.innerWidth, window.innerHeight);
// 绑定鼠标移动事件
document.addEventListener("mousemove", onDocumentMouseMove, false);
// 窗口大小改变监听
window.addEventListener("resize", onWindowResize, false);
}
// 监听鼠标移动方向, 从而确定地球南北半球
function onDocumentMouseMove(ev) {
ev = ev || event;
mouseX = ev.clientX - windowHalfX;
mouseY = ev.clientY - windowHalfY;
}
// 监听窗口大小, 从而根据窗口大小改变地球大小,类似响应式
function onWindowResize() {
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
// 请求运动帧
requestAnimationFrame(animate);
render();
}
// 地球旋转逻辑函数
function render() {
// 更新性能监视器
stats.update();
camera.position.x += (mouseX - camera.position.x) * 0.05;
camera.position.y += (mouseX - camera.position.y) * 0.05;
// 拍摄角度, 可改变地球视角
camera.lookAt(scene.position);
// 地球自转速度
group.rotation.y -= 0.005;
// 核心 递归调用
renderer.render(scene, camera);
}
function initStats() {
stats = new Stats();
//设置统计模式
stats.setMode(0); // 0: fps, 1: ms
//统计信息显示在左上角
stats.domElement.style.position = "absolute";
stats.domElement.style.left = "10px";
stats.domElement.style.top = "10px";
//将统计对象添加到对应的<div>元素中
document.getElementById("stats-output").appendChild(stats.domElement);
return stats;
}
// ecchat 数据可视化
// 平面的世界是错误的, css perspective:1000px transform-style:perserve-3d
// Camera Scene render(渲染容器) Light -> canvas
|
0900 embedding-atlas
embedding-atlas 是一个由 Apple 开发的开源库,专注专注主要用于大规模嵌入(Embedding)的计算与交互式可视化。它提供了一系列组件和算法,方便开发者在自己的应用中集成集成嵌入数据的可视化功能,支持处理数百万数百万级别的数据点。
https://github.com/apple/embedding-atlas
https://apple.github.io/embedding-atlas/overview.html
可视化组件
-
EmbeddingView:展示嵌入数据的 2D 散点图视图,支持百万级数据点
-
EmbeddingViewMosaic:与 Mosaic 协调器集成的嵌入视图
-
EmbeddingAtlas:完整的嵌入可视化前端界面组件
-
Table:数据表格组件,用于展示嵌入数据的详细信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import { EmbeddingAtlas } from "embedding-atlas/react";
function MyComponent() {
const coordinator = new Coordinator(); // Mosaic 协调器
return (
<EmbeddingAtlas
coordinator={coordinator}
data={{
table: "data_table",
id: "id_column",
projection: { x: "x_column", y: "y_column" },
text: "text_column"
}}
/>
);
}
|
注意1:开发环境下缺少依赖的解决
这个库支持了浏览器和 nodejs,也支持命令行和 Python,功能很强大,如果和 webpack5 使用,需要额外加入配置文件,忽略打包过程中缺少的 nodejs 模块。
1
2
3
4
5
6
7
8
9
10
11
12
|
fallback: {
// Node.js core modules that are not available in the browser
// Setting them to false tells webpack to ignore them
"worker_threads": false,
"fs": false,
"path": false,
"crypto": false,
"stream": false,
"util": false,
"buffer": false,
"process": false
},
|
注意2: 生产环境下前端模块出错的解决。
dev 环境下,控制台出错,显示请求 127.0.0.1:3003/xxx/xxx.chunk.js 模块跨域,加载 571 模块出错。
问题分析
seaqa-web 项目早期不存在这个问题,最近新加入了某个第三方库 https://github.com/apple/embedding-atlas 后出现问题,测试去掉这个库就没有问题,定位到问题可能是这个第三方库造成。embedding-atlas 项目目前还在开发中,没有发布正式版本,升级到最新版(0.13.0)还存在同样的错误,没有修复这个问题。
embedding-atlas 第三方包含有私有代码,可能使用了动态 import 或 webpack 异步加载逻辑,也可能 embedding-atlas 内部使用常量 __webpack_public_path__ 为 http://127.0.0.1:3003/,覆盖了 seaqa-web 的配置。动态 import() 语句会被 Webpack 识别为「异步模块」,并在构建时被拆分为独立的异步 chunk(571.chunk.js、483.chunk.js),而非打包到主 bundle 中,所以 dev 上出现多个包跨域的出错,主 bundle 打包加载正常,571.chunk.js 加载不正常。
解决方案
增加配置 webpack output: { asyncChunks: false }强制所有模块(包括异步模块)打包到主 chunk 中,禁用 embedding-atlas异步 chunk 的生成,浏览器直接加载主 bundle,就不会出现异步模块的跨域问题。
局限性
经测试,这个方案可以解决模块跨域问题,控制台不会出错。
但是这个方案存在局限性,embedding-atlas 的异步模块,默认在使用时才异步加载,现在打包到主 bundle 中,造成主 bundle 体积增加,会在首屏一起加载,增加了加载耗时。
其他思考
1、为什么开发环境下没有这个问题,生产环境下出现了这个错误:开发环境下(dev)使用 devServer 是 127.0.0.1:3003 和 embedding-atlas 是同源,所以浏览器不存在跨域的报错。生产环境下(build)上线后 seaqa-dev.seafile.com 就存在跨域问题,浏览器显示错误。开发环境下和生产环境下,webpack 打包策略不同,开发环境下直接加载所有模块,不会打包主模块和异步模块。生产环境中,原始配置是主模块和异步模块,所以出现模块加载出错。
2、能否本地写死 public_path,避免第三方库的影响?例如增加生产环境中的环境变量,设置 PUBLIC_URL="https://sea-qa-dev.seafile.com/assets/bundles" ,或者 webpack_public_path 为常量?可以临时这样写解决问题,不是根本解决方案。如果未来前端代码,在不同域名的生产环境部署,每一个生产环境专门修改 PUBLIC_URL 并重新打包,不符合实际使用场景。所以不建议写死 PUBLIC_PATH 或者 PAULIC_URL。
0287 react-i18n fallbackLng 是什么
配置项设置了 fallBackLng 表示备用语言,就是主要翻译的语言不显示时,使用备用语言显示。
也造成了界面中加载了两种语言,可能多加载 100 kb 的资源。


0293 jsdom 模拟 node 环境下 window
需求:
node 环境下测试,需要使用全局变量 window ,但是node没有window只有global对象,所以需要这个第三方库模拟虚拟 dom 完成一些测试。
部分项目的测试文件中使用到了window.app,在jest测试中默认情况下是在Node.js环境中运行的,而window在Node.js中未定义,会报错,这里应该使用 jsdom 来手动的创建一下window,
1
2
3
4
5
|
import { JSDOM } from 'jsdom';
const { window } = new JSDOM('<!doctype html><html><body></body></html>');
global.window = window;
|
官方链接:https://www.npmjs.com/package/jsdom
官方案例
1
2
3
4
5
|
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);
console.log(dom.window.document.querySelector("p").textContent); // "Hello world"
|
0706 dayjs 的注意事项
dayjs 是一个处理日期的库,是 moment 的简化版
注意:如果很多项目存在依赖关系,那么 dayjs 应该选择统一的版本,例如 1.10.7,否则多个版本同时存在,可能日期格式化不正确
0707 calendar 的注意事项
calendar 是阿里巴巴早期做的一个日历组件
如果现在使用,平替的是 html 原生的 input date 可以实现
这个库注意:
1、翻译问题:一部分是库自己的翻译,另一部分翻译是使用的日期库的翻译( moment 或者 dayjs 中的翻译)需要什么语言就用什么翻译,这里一定要引入
1
2
|
import 'dayjs/locale/zh-cn';
import 'dayjs/locale/en-gb';
|
2、 value 没有值时 defaultValue 的翻译 = dayjs.now() 处理