第三方库笔记

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

可视化组件

  1. EmbeddingView:展示嵌入数据的 2D 散点图视图,支持百万级数据点

  2. EmbeddingViewMosaic:与 Mosaic 协调器集成的嵌入视图

  3. EmbeddingAtlas:完整的嵌入可视化前端界面组件

  4. 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() 处理