diff --git a/404.html b/404.html index 448ba7e5..13cf7aa0 100644 --- a/404.html +++ b/404.html @@ -25,7 +25,7 @@
Skip to content

404

PAGE NOT FOUND

But if you don't change your direction, and if you keep looking, you may end up where you are heading.

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/analysis/cli/create-vue.html b/analysis/cli/create-vue.html index c11fabc1..3ababac2 100644 --- a/analysis/cli/create-vue.html +++ b/analysis/cli/create-vue.html @@ -854,7 +854,7 @@ ...sorted, } } - + \ No newline at end of file diff --git a/analysis/react/18.2.0/base/fiber.html b/analysis/react/18.2.0/base/fiber.html index 46ed6609..d26325c2 100644 --- a/analysis/react/18.2.0/base/fiber.html +++ b/analysis/react/18.2.0/base/fiber.html @@ -76,7 +76,7 @@ } ReactDOM.render(<App />, document.getElementById('root'))
  1. 首次执行 ReactDOM.render 时会创建 fiberRootNode(源码中叫 fiberRoot)和 rootFiber

为什么要区分 fiberRootNoderootFiber

因为在一个 React 应用中我们可以多次调用 ReactDOM.render 来渲染不同的组件树,这时它们会拥有不同的 rootFiber。但是整个应用的根节点只有一个那就是 fiberRootNode

这时 fiberRootNodecurrent 指针会指向当前页面上已渲染内容对应 Fiber 树(即 current Fiber 树

rootFiber

js
fiberRootNode.current = rootFiber

由于是首屏渲染,页面中还没有挂载任何 DOM,所以 fiberRootNode.current 指向的 rootFiber 是没有任何 子 Fiber 节点的(即current Fiber 树为空)

  1. 接下来进入 render 阶段,根据组件返回的 JSX 在内存中依次创建 Fiber 节点 并连接在一起构建 Fiber 树,其被称为workInProgress Fiber 树(下图中右侧为内存中构建的树,左侧为页面显示的树)

在构建 workInProgress Fiber 树 时会尝试复用 current Fiber 树 中已有的 Fiber 节点 内的属性,在首屏渲染时只有 rootFiber 存在对应的 current fiber(即 rootFiber.alternate

workInProgressFiber

  1. 图中右侧已构建完的 workInProgress Fiber 树 会在 commit 阶段 渲染到页面

此时 DOM 更新为右侧树对应的界面。fiberRootNodecurrent 指针指向 workInProgress Fiber 树 使其变更为current Fiber 树(即下图所示)

wipTreeFinish

update 阶段

  1. 当我们点击 p 节点 触发状态改变时,会开启一次新的 render 阶段 并构建一棵新的 workInProgress Fiber 树

wipTreeUpdate

mount 时一样,workInProgress fiber 的创建会复用 current Fiber 树 中对应的节点数据

决定是否复用的过程就是 Diff 算法

  1. workInProgress Fiber 树render 阶段 完成构建后进入 commit 阶段 渲染到页面上。在渲染完毕后workInProgress Fiber 树 变更为 current Fiber 树

currentTreeUpdate


相关资料

- + \ No newline at end of file diff --git a/analysis/react/18.2.0/base/file.html b/analysis/react/18.2.0/base/file.html index 5248aac7..aa4348d2 100644 --- a/analysis/react/18.2.0/base/file.html +++ b/analysis/react/18.2.0/base/file.html @@ -63,7 +63,7 @@ ├── react-server-dom-webpack ├── react-server-native-relay └─ react-suspense-test-utils # React Suspense 组件的测试工具包 - + \ No newline at end of file diff --git a/analysis/react/18.2.0/base/idea.html b/analysis/react/18.2.0/base/idea.html index 7fda7105..9ef1a692 100644 --- a/analysis/react/18.2.0/base/idea.html +++ b/analysis/react/18.2.0/base/idea.html @@ -35,7 +35,7 @@ }

源码地址 workLoopConcurrent | ReactFiberWorkLoop.old.js

在 React16 中,Reconciler 与 Renderer 不再是交替工作。当 Scheduler 将任务交给 Reconciler 后,Reconciler 会为变化的虚拟 DOM 打上代表增/删/更新的标记,类似这样:

js
export const Placement = /*                    */ 0b00000000000000000000000010
 export const Update = /*                       */ 0b00000000000000000000000100
 export const Deletion = /*                     */ 0b00000000000000000000001000

同时整个 Scheduler 与 Reconciler 的工作都在内存中进行。只有当所有组件都完成 Reconciler 的工作,才会统一交给 Renderer,这样就保证了整个过程不会出现中断导致页面渲染不完全的情况

Renderer(渲染器)

Renderer 根据 Reconciler 为 Fiber 节点打的标记,同步执行对应的 DOM 操作

在 React 16 架构中的更新流程

update-process

红框中的步骤随时可能由于以下原因被中断:

由于红框中的工作都在内存中进行,不会更新页面上的 DOM,所以即使反复中断用户也不会看见更新不完全的 DOM


相关资料

- + \ No newline at end of file diff --git a/analysis/react/18.2.0/base/jsx.html b/analysis/react/18.2.0/base/jsx.html index 6c989ba6..d0a3481f 100644 --- a/analysis/react/18.2.0/base/jsx.html +++ b/analysis/react/18.2.0/base/jsx.html @@ -121,7 +121,7 @@ function App() { return _jsx('h1', { children: 'Hello world' }) }

jsx 方法和上面的 createElement 方法一样,都是对参数进行处理,最后调用 ReactElement 方法返回 React Element 对象

- + \ No newline at end of file diff --git a/analysis/react/18.2.0/base/mode-process.html b/analysis/react/18.2.0/base/mode-process.html index d9b4fa93..7320181e 100644 --- a/analysis/react/18.2.0/base/mode-process.html +++ b/analysis/react/18.2.0/base/mode-process.html @@ -31,7 +31,7 @@ export const LegacyRoot = 0 export const ConcurrentRoot = 1

渲染流程

React 应用程序的渲染流程可以分为三个阶段:

rendercommit 阶段统称为 work,即 React 在工作中。如果任务正在 Scheduler 内调度就不属于 work 阶段

legacy 模式的调用栈

legacy-process

concurrent 模式的调用栈

concurrent-process

- + \ No newline at end of file diff --git a/analysis/react/18.2.0/base/virtual-dom.html b/analysis/react/18.2.0/base/virtual-dom.html index a92cbf04..e55b3256 100644 --- a/analysis/react/18.2.0/base/virtual-dom.html +++ b/analysis/react/18.2.0/base/virtual-dom.html @@ -33,7 +33,7 @@ str += k + ' ' } console.log('' + str)

DOM

可以看到原生 DOM 对象上有很多属性和方法,而我们在操作 DOM 后,浏览器会进行重排(Reflow)和重绘(Repaint),一旦操作不当,就会造成性能问题

什么是 Virtual DOM

Virtual DOM 是 JavaScript 和 DOM 之间的一个映射缓存,其本质上是一个轻量级的 JavaScript 对象树,它通过这个树来描述 DOM 树的结构和属性

Virtual DOM 的工作原理

  1. 创建 Virtual DOM:当应用初始化时或数据发生变化时,会创建或更新 Virtual DOM
  2. Diff 算法:在生成新的 Virtual DOM 之后,会与之前的 Virtual DOM 进行比较,找出两者之间的差异。这个过程称为 Diff 算法,它能够高效地计算出需要更新的最小操作集合
  3. 更新原生 DOM:通过 Diff 算法的结果,确定了哪些部分需要更新,然后将这些变化应用到真实 DOM 上。这个阶段真正将变化应用到 DOM 上,通常使用最小的 DOM 操作来实现更新,从而减少了 DOM 操作的开销。

可以看到 Virtual DOM 的本质是一种在内存中进行 DOM 树的处理和优化的机制。通过在 JavaScript 对象上进行操作,可以避免频繁的直接 DOM 操作,从而提高了应用的性能和响应速度。虽然 Virtual DOM 本身会引入一定的计算开销,但由于减少了真实 DOM 操作,整体上还是对性能有所提升

Virtual DOM 的优缺点

优点

缺点


相关资料

网上都说操作真实 DOM 慢,但测试结果却比 React 更快,为什么? - 尤雨溪的回答

- + \ No newline at end of file diff --git a/analysis/react/18.2.0/process/begin-work.html b/analysis/react/18.2.0/process/begin-work.html index e52f97bd..6e9ef517 100644 --- a/analysis/react/18.2.0/process/begin-work.html +++ b/analysis/react/18.2.0/process/begin-work.html @@ -420,7 +420,7 @@ export const Hydrating = /* */ 0b00000000000001000000000000 export const Visibility = /* */ 0b00000000000010000000000000 export const StoreConsistency = /* */ 0b00000000000100000000000000

在通知 Renderer 将 Fiber 节点 对应的 DOM 节点 渲染到页面上需要满足以下两个条件:

  1. fiber.stateNode 存在(即 Fiber 节点 中保存了对应的 DOM 节点
  2. fiber.flags 中包含 Placement 标记(即 DOM 节点 需要被插入到页面上)

在首屏渲染时如何满足上述两个条件?

  1. fiber.stateNode 会在 completeWork 中创建
  2. mount 时只有 rootFiber 会赋值 Placement flags,其他 Fiber 节点 都不会赋值 Placement flags,因此在 commit 阶段,插入操作仅会在根节点执行一次,避免了重复的 DOM 操作

如果在 mountChildFibers 时也会赋值 Placement flags,那么整棵 Fiber 的每个节点都会具有 Placement flags,这会导致在 commit 段执行大量的 DOM 插入操作,效率极低;

因此 React 进行了优化:mount 时只有 rootFiber 会赋值 Placement flags,从而确保在 commit 阶段只有一次插入操作,有效地提升了渲染性能

- + \ No newline at end of file diff --git a/analysis/react/18.2.0/process/commit-before-mutation-effects.html b/analysis/react/18.2.0/process/commit-before-mutation-effects.html index b0f0eba7..9e0cecaf 100644 --- a/analysis/react/18.2.0/process/commit-before-mutation-effects.html +++ b/analysis/react/18.2.0/process/commit-before-mutation-effects.html @@ -178,7 +178,7 @@ } } } - + \ No newline at end of file diff --git a/analysis/react/18.2.0/process/commit-layout-effects.html b/analysis/react/18.2.0/process/commit-layout-effects.html index da0bfe03..1c598978 100644 --- a/analysis/react/18.2.0/process/commit-layout-effects.html +++ b/analysis/react/18.2.0/process/commit-layout-effects.html @@ -334,7 +334,7 @@ } } } - + \ No newline at end of file diff --git a/analysis/react/18.2.0/process/commit-mutation-effects.html b/analysis/react/18.2.0/process/commit-mutation-effects.html index 9b285f37..1384c9bc 100644 --- a/analysis/react/18.2.0/process/commit-mutation-effects.html +++ b/analysis/react/18.2.0/process/commit-mutation-effects.html @@ -523,7 +523,7 @@ ) } } - + \ No newline at end of file diff --git a/analysis/react/18.2.0/process/commit-root.html b/analysis/react/18.2.0/process/commit-root.html index f708a4d9..fc832d8e 100644 --- a/analysis/react/18.2.0/process/commit-root.html +++ b/analysis/react/18.2.0/process/commit-root.html @@ -524,7 +524,7 @@ return null }

可以看到在 layput 阶段之后 主要做了以下工作:

- + \ No newline at end of file diff --git a/analysis/react/18.2.0/process/complete-work.html b/analysis/react/18.2.0/process/complete-work.html index 90c28845..4bb92bac 100644 --- a/analysis/react/18.2.0/process/complete-work.html +++ b/analysis/react/18.2.0/process/complete-work.html @@ -375,7 +375,7 @@ </button> ) }

updatePayload

- + \ No newline at end of file diff --git a/analysis/react/18.2.0/process/init.html b/analysis/react/18.2.0/process/init.html index aa8dc97c..966628fb 100644 --- a/analysis/react/18.2.0/process/init.html +++ b/analysis/react/18.2.0/process/init.html @@ -236,7 +236,7 @@ // 返回当前更新的优先级 return lane } - + \ No newline at end of file diff --git a/analysis/react/18.2.0/process/schedule-update-on-fiber.html b/analysis/react/18.2.0/process/schedule-update-on-fiber.html index 2cc77e19..ef9b39ba 100644 --- a/analysis/react/18.2.0/process/schedule-update-on-fiber.html +++ b/analysis/react/18.2.0/process/schedule-update-on-fiber.html @@ -530,7 +530,7 @@ div Fiber completeWork App Fiber completeWork rootFiber completeWork

相关资料

- + \ No newline at end of file diff --git a/analysis/react/18.html b/analysis/react/18.html index 567427c6..f013622a 100644 --- a/analysis/react/18.html +++ b/analysis/react/18.html @@ -293,7 +293,7 @@ } export default App

执行堆栈图

从执行堆栈图看到,由于组件数量繁多(10000 个),JavaScript 执行时间为 300ms,也就是意味着在没有并发特性的情况下:一次性渲染 10000 个标签的时候,页面会阻塞大约 0.3 秒,造成卡顿;但是如果开启并发更新就不会存在这样的问题

并发模式总结

fiber 的含义

  1. 架构角度:在旧的架构中,Reconciler(协调器)采用递归的方式执行,无法中断,节点数据保存在递归的调用栈中,被称为 Stack Reconciler,stack 就是调用栈;在新的架构中,Reconciler(协调器)是基于 fiber 实现的,节点数据保存在 fiber 中,所以被称为 fiber Reconciler
  2. 静态数据结构角度:每个 fiber 对应一个组件,保存了这个组件类型对应的 dom 节点信息,这时,fiber 节点就是我们所说的虚拟DOM
  3. 动态工作单元角度:fiber 节点保存了该节点需要更新的状态以及需要执行的副作用

相关资料

React18 新特性解读 & 完整版升级指南

- + \ No newline at end of file diff --git a/analysis/react/interview.html b/analysis/react/interview.html index 9f722456..503bd672 100644 --- a/analysis/react/interview.html +++ b/analysis/react/interview.html @@ -155,7 +155,7 @@ } } }

属性代理和反向继承的总结

属性代理耦合度低,适用于多个业务组件的复用,而反向继承耦合度高,适用于单个业务组件的复用;通过反向继承方式实现的高阶组件比属性代理实现的高阶组件功能更强大,个性化程度更高

高阶组件的缺点


相关资料

setState 是同步更新还是异步更新

setState 在类组件中是 this.setState 方法,在函数组件中是 useState 返回值的修改函数 setState 用于变更状态,触发组件重新渲染,更新视图 UI

setState 是同步更新还是异步更新指的是:在调用 setState 之后是否马上能得到最新的 state 值,如果能就是同步,如果不能就是异步(React 官方定义是异步的)

React 18 之前

legacy 模式:ReactDOM.render(<App />, rootNode)

legacy 模式下,只要在 React 可以控制的地方,setState 的执行都是异步的,比如在 React 生命周期事件和合成事件中,都会走合并操作,延迟更新的策略
而在 React 无法控制的地方,如监听原生事件和异步调用的地方,setState 的执行都是就是同步的。比如在 addEventListenersetTimeoutsetIntervalPromiseMessageChannel 的回调函数中

React 18 之后

concurrent 模式:ReactDOM.createRoot(rootNode).render(<App />)

concurrent 模式下,由于默认启用了并发更新,所以 setState 的执行都是异步的,即不管是在 React 可以控制的地方还是无法控制的地方,默认都会走合并操作,延迟更新的策略

为什么 setState 是异步的?

RFClarification: why is setState asynchronous?


相关资料

- + \ No newline at end of file diff --git a/analysis/utils/await-to-js.html b/analysis/utils/await-to-js.html index 21a0361d..49e00478 100644 --- a/analysis/utils/await-to-js.html +++ b/analysis/utils/await-to-js.html @@ -73,7 +73,7 @@ }) ) }

相关资料

- + \ No newline at end of file diff --git a/analysis/utils/clsx.html b/analysis/utils/clsx.html index 66914f6c..68de2817 100644 --- a/analysis/utils/clsx.html +++ b/analysis/utils/clsx.html @@ -115,7 +115,7 @@ } export default clsx - + \ No newline at end of file diff --git a/analysis/utils/only-allow.html b/analysis/utils/only-allow.html index efd662a7..81a9e209 100644 --- a/analysis/utils/only-allow.html +++ b/analysis/utils/only-allow.html @@ -144,7 +144,7 @@ // 返回 pmFromUserAgent 函数处理的结果 return pmFromUserAgent(process.env.npm_config_user_agent) } - + \ No newline at end of file diff --git a/assets/fe_monorepo_index.md.BIhnHzT9.js b/assets/fe_monorepo_index.md.LxRgU25L.js similarity index 99% rename from assets/fe_monorepo_index.md.BIhnHzT9.js rename to assets/fe_monorepo_index.md.LxRgU25L.js index 17b60895..637d0cff 100644 --- a/assets/fe_monorepo_index.md.BIhnHzT9.js +++ b/assets/fe_monorepo_index.md.LxRgU25L.js @@ -21,7 +21,7 @@ import{_ as s,h as i,o as a,aa as n}from"./chunks/framework.C-tu2utv.js";const g ├── .git ├── src └── index.js - └── package.json

Multi-Repo 的优缺点

优点

缺点


如何选择

在选择时主要取决于项目需求、团队结构和偏好,没有哪种方式是绝对正确的,都要根据实际需求结合其优缺点来进行选择,下面是一些常见的考虑因素:

搭建 Monorepo 项目

常见的 Monorepo 实现

  1. 使用 pnpm/npm/yarnworkspace 功能
  2. 再搭配 Monorepo 管理工具
    1. pnpm
    2. lerna
    3. nx
    4. bazel
    5. rushstack

目前主流的方式是使用 pnpm 来做 Monorepo,其无须使用第三方工具就可以进行管理

安装 pnpm

sh
curl -fsSL https://get.pnpm.io/install.sh | sh -
sh
brew install pnpm
sh
npm install -g pnpm

相关资料

安装 | pnpm

创建项目

sh
# 创建并进入 my-monorepo 文件夹
+    └── package.json

Multi-Repo 的优缺点

优点

缺点


如何选择

在选择时主要取决于项目需求、团队结构和偏好,没有哪种方式是绝对正确的,都要根据实际需求结合其优缺点来进行选择,下面是一些常见的考虑因素:

搭建 Monorepo 项目

常见的 Monorepo 实现

  1. 使用 pnpm/npm/yarnworkspace 功能
  2. 再搭配 Monorepo 管理工具
    1. pnpm
    2. lerna
    3. nx
    4. bazel
    5. rushstack

目前主流的方式是使用 pnpm 来做 Monorepo,其无须使用第三方工具就可以进行管理

安装 pnpm

sh
curl -fsSL https://get.pnpm.io/install.sh | sh -
sh
brew install pnpm
sh
npm install -g pnpm

相关资料

安装 | pnpm

创建项目

sh
# 创建并进入 my-monorepo 文件夹
 mkdir my-monorepo
 cd my-monorepo
 
diff --git a/assets/fe_monorepo_index.md.BIhnHzT9.lean.js b/assets/fe_monorepo_index.md.LxRgU25L.lean.js
similarity index 100%
rename from assets/fe_monorepo_index.md.BIhnHzT9.lean.js
rename to assets/fe_monorepo_index.md.LxRgU25L.lean.js
diff --git a/assets/fe_node_pkg.md.DTBhy2rk.js b/assets/fe_node_pkg.md.q2jkodkv.js
similarity index 98%
rename from assets/fe_node_pkg.md.DTBhy2rk.js
rename to assets/fe_node_pkg.md.q2jkodkv.js
index 8df146b3..7346e51a 100644
--- a/assets/fe_node_pkg.md.DTBhy2rk.js
+++ b/assets/fe_node_pkg.md.q2jkodkv.js
@@ -37,7 +37,7 @@ import{_ as p,G as t,h as r,q as s,e as a,L as n,b as e,aa as l,o as h}from"./ch
 // recommend
 {
   "licenses": "MIT"
-}

文件配置

type

'commonjs' | 'module' 表明包使用的模块语法( Node@14 以上版本支持 ES Module

bin

string | { \${binName}: \${binFilePath} } 声明包的脚本文件

脚本文件一般在文件头以 SheBang 声明运行脚本的语言

sh
npm install demo -g
+}

文件配置

type

'commonjs' | 'module' 表明包使用的模块语法( Node@14 以上版本支持 ES Module

bin

string | { \${binName}: \${binFilePath} } 声明包的脚本文件

脚本文件一般在文件头以 SheBang 声明运行脚本的语言

sh
npm install demo -g
 
 d
 # log: Npm is COOL
js
#!/usr/bin/env node
@@ -50,14 +50,14 @@ import{_ as p,G as t,h as r,q as s,e as a,L as n,b as e,aa as l,o as h}from"./ch
 }
sh
.
 ├── bin
    └── demo.js
-└── package.json

files

Array<string> 指明将此项目作为依赖包安装时包含的文件,默认为排除以下文件的全部内容:

TIP

files 字段作用类似的还有 .npmignore.gitignore

files 类似于白名单,往往产物内容更少更方便。而 ignore 文件类似于黑名单,需要开发者持续维护

types

string => filePath 声明此项目的 TypeScript 类型文件

TIP

  • typestypings 意义完全相同,可替换使用
  • 当主声明文件命名为 index.d.ts,并且位于包的根目录与 index.js 同级,则可以省略 types 字段,但建议保持良好的声明式习惯

参阅 TypeScript | Docs

main

string 标准化的工具包主入口

默认为 index.js ,主要用于 Node.jscjs 模块

js
const foo = require('foo') // => from "main" field
+└── package.json

files

Array<string> 指明将此项目作为依赖包安装时包含的文件,默认为排除以下文件的全部内容:

TIP

files 字段作用类似的还有 .npmignore.gitignore

files 类似于白名单,往往产物内容更少更方便。而 ignore 文件类似于黑名单,需要开发者持续维护

types

string => filePath 声明此项目的 TypeScript 类型文件

TIP

  • typestypings 意义完全相同,可替换使用
  • 当主声明文件命名为 index.d.ts,并且位于包的根目录与 index.js 同级,则可以省略 types 字段,但建议保持良好的声明式习惯

参阅 TypeScript | Docs

main

string 标准化的工具包主入口

默认为 index.js ,主要用于 Node.jscjs 模块

js
const foo = require('foo') // => from "main" field
 // foo => { value: 1 }
js
// foo.cjs
 module.exports = {
   value: 1,
 }
json
// package.json
 {
   "main": "./foo.cjs"
-}

browser

string 工具包主入口

当项目仅服务于浏览器端,则应采用此字段代替 main 字段

html
<script src="foo.js"></script>

module

string 工具包主入口

非官方支持的字段,基本上是 WebpackRollup 等打包工具为支持 ES Module 而约定的字段

exports

`,31),v=s("code",null,"Record",-1),f=l(`

为工具包主入口及其语义版本升级提供了更可靠的保证,支持多模块、多环境、子路径等定义形式。

json
{
+}

browser

string 工具包主入口

当项目仅服务于浏览器端,则应采用此字段代替 main 字段

html
<script src="foo.js"></script>

TIP

参阅 package-browser-field-spec

module

string 工具包主入口

非官方支持的字段,基本上是 WebpackRollup 等打包工具为支持 ES Module 而约定的字段

TIP

参阅 what-is-the-module-package-json-field-for | stackoverflow

exports

`,31),v=s("code",null,"Record",-1),C=l(`

为工具包主入口及其语义版本升级提供了更可靠的保证,支持多模块、多环境、子路径等定义形式。

json
{
   "exports": {
     ".": {
       "node-addons": "", // for C++ plugins
@@ -115,7 +115,7 @@ import{_ as p,G as t,h as r,q as s,e as a,L as n,b as e,aa as l,o as h}from"./ch
       }
     }
   }
-}

脚本配置

scripts

Record<string, string> 带有以下默认生命周期的脚本命令: <pre> | <post>

特殊的 prepareprepublishOnlyscripts 文档

TIP

在 pnpm@6 与 yarn2 中, preinstall 将在 install 后执行,而不是在 install 之前

为此 pnpm 提供了 pnpm:devPreinstall 钩子以兼容开发者的使用习惯

config

Record<string, string> process.env 配置命令行的环境变量

js
#!/usr/bin/env node
+}

脚本配置

scripts

Record<string, string> 带有以下默认生命周期的脚本命令: <pre> | <post>

  • install
  • uninstall
  • start
  • restart
  • stop
  • test
  • pack
  • publish
  • 自定义脚本命令

特殊的 prepareprepublishOnlyscripts 文档

TIP

在 pnpm@6 与 yarn2 中, preinstall 将在 install 后执行,而不是在 install 之前

为此 pnpm 提供了 pnpm:devPreinstall 钩子以兼容开发者的使用习惯

config

Record<string, string> process.env 配置命令行的环境变量

js
#!/usr/bin/env node
 
 console.log(process.env.npm_package_config_port) // 8732
 console.log(process.env.npm_package_config_foo) // bar
json
{
@@ -150,4 +150,4 @@ import{_ as p,G as t,h as r,q as s,e as a,L as n,b as e,aa as l,o as h}from"./ch
   {
     "cpu": ["!arm"]
   }
-}

第三方配置

sideEffects

boolean | Array<string => filePath> 声明存在副作用的模块,用于 Webpack 等打包工具的导出优化

对于模块是否有副作用的定义,基本是指开发者在设计时是否产生了副作用,而不必关心经过打包工具处理后的最终产物。

unpkg

string => filePath 在发布到 npm 后,可以使用此字段为项目对应的文件开启 CDN 服务,默认为 main

TIP

参阅 unpkg | docs

jsdelivr

string => filePath 类似于 unpkg

cosmiconfig

基于 cosmiconfig 实现的相关配置仅在此简单罗列常用工具

`,74);function C(B,D,j,A,_,x){const i=t("Badge");return h(),r("div",null,[o,d,s("h3",c,[a("name "),n(i,null,{default:e(()=>[a("required")]),_:1}),a(),u]),g,s("h3",E,[a("version "),n(i,null,{default:e(()=>[a("required")]),_:1}),a(),b]),m,s("ul",null,[s("li",null,[y,a(),n(i,null,{default:e(()=>[a("recommend")]),_:1})]),F]),q,s("p",null,[v,a(" 最新标准的导出接口 "),n(i,null,{default:e(()=>[a("recommend")]),_:1})]),f])}const S=p(k,[["render",C]]);export{P as __pageData,S as default}; +}

第三方配置

sideEffects

boolean | Array<string => filePath> 声明存在副作用的模块,用于 Webpack 等打包工具的导出优化

对于模块是否有副作用的定义,基本是指开发者在设计时是否产生了副作用,而不必关心经过打包工具处理后的最终产物。

unpkg

string => filePath 在发布到 npm 后,可以使用此字段为项目对应的文件开启 CDN 服务,默认为 main

TIP

参阅 unpkg | docs

jsdelivr

string => filePath 类似于 unpkg

cosmiconfig

基于 cosmiconfig 实现的相关配置仅在此简单罗列常用工具

`,74);function f(B,D,j,_,A,w){const i=t("Badge");return h(),r("div",null,[o,d,s("h3",c,[a("name "),n(i,null,{default:e(()=>[a("required")]),_:1}),a(),u]),g,s("h3",E,[a("version "),n(i,null,{default:e(()=>[a("required")]),_:1}),a(),b]),m,s("ul",null,[s("li",null,[y,a(),n(i,null,{default:e(()=>[a("recommend")]),_:1})]),F]),q,s("p",null,[v,a(" 最新标准的导出接口 "),n(i,null,{default:e(()=>[a("recommend")]),_:1})]),C])}const S=p(k,[["render",f]]);export{P as __pageData,S as default}; diff --git a/assets/fe_node_pkg.md.DTBhy2rk.lean.js b/assets/fe_node_pkg.md.q2jkodkv.lean.js similarity index 98% rename from assets/fe_node_pkg.md.DTBhy2rk.lean.js rename to assets/fe_node_pkg.md.q2jkodkv.lean.js index 8df146b3..7346e51a 100644 --- a/assets/fe_node_pkg.md.DTBhy2rk.lean.js +++ b/assets/fe_node_pkg.md.q2jkodkv.lean.js @@ -37,7 +37,7 @@ import{_ as p,G as t,h as r,q as s,e as a,L as n,b as e,aa as l,o as h}from"./ch // recommend { "licenses": "MIT" -}

文件配置

type

'commonjs' | 'module' 表明包使用的模块语法( Node@14 以上版本支持 ES Module

  • 默认为 commonjs, 对于 mjs 后缀名文件采用 ESM 语法解析

  • 设置为 module 时,对于 cjs 后缀名文件采用 commonjs 语法解析

bin

string | { \${binName}: \${binFilePath} } 声明包的脚本文件

脚本文件一般在文件头以 SheBang 声明运行脚本的语言

sh
npm install demo -g
+}

文件配置

type

'commonjs' | 'module' 表明包使用的模块语法( Node@14 以上版本支持 ES Module

  • 默认为 commonjs, 对于 mjs 后缀名文件采用 ESM 语法解析

  • 设置为 module 时,对于 cjs 后缀名文件采用 commonjs 语法解析

bin

string | { \${binName}: \${binFilePath} } 声明包的脚本文件

脚本文件一般在文件头以 SheBang 声明运行脚本的语言

sh
npm install demo -g
 
 d
 # log: Npm is COOL
js
#!/usr/bin/env node
@@ -50,14 +50,14 @@ import{_ as p,G as t,h as r,q as s,e as a,L as n,b as e,aa as l,o as h}from"./ch
 }
sh
.
 ├── bin
    └── demo.js
-└── package.json

files

Array<string> 指明将此项目作为依赖包安装时包含的文件,默认为排除以下文件的全部内容:

  • .git
  • CVS
  • .svn
  • .hg
  • .lock-wscript
  • .wafpickle-N
  • .*.swp
  • .DS_Store
  • ._*
  • npm-debug.log
  • .npmrc
  • node_modules
  • config.gypi
  • *.orig
  • package.json / npm-shrinkwrap.json

TIP

files 字段作用类似的还有 .npmignore.gitignore

files 类似于白名单,往往产物内容更少更方便。而 ignore 文件类似于黑名单,需要开发者持续维护

types

string => filePath 声明此项目的 TypeScript 类型文件

TIP

  • typestypings 意义完全相同,可替换使用
  • 当主声明文件命名为 index.d.ts,并且位于包的根目录与 index.js 同级,则可以省略 types 字段,但建议保持良好的声明式习惯

参阅 TypeScript | Docs

main

string 标准化的工具包主入口

默认为 index.js ,主要用于 Node.jscjs 模块

js
const foo = require('foo') // => from "main" field
+└── package.json

files

Array<string> 指明将此项目作为依赖包安装时包含的文件,默认为排除以下文件的全部内容:

  • .git
  • CVS
  • .svn
  • .hg
  • .lock-wscript
  • .wafpickle-N
  • .*.swp
  • .DS_Store
  • ._*
  • npm-debug.log
  • .npmrc
  • node_modules
  • config.gypi
  • *.orig
  • package.json / npm-shrinkwrap.json

TIP

files 字段作用类似的还有 .npmignore.gitignore

files 类似于白名单,往往产物内容更少更方便。而 ignore 文件类似于黑名单,需要开发者持续维护

types

string => filePath 声明此项目的 TypeScript 类型文件

TIP

  • typestypings 意义完全相同,可替换使用
  • 当主声明文件命名为 index.d.ts,并且位于包的根目录与 index.js 同级,则可以省略 types 字段,但建议保持良好的声明式习惯

参阅 TypeScript | Docs

main

string 标准化的工具包主入口

默认为 index.js ,主要用于 Node.jscjs 模块

js
const foo = require('foo') // => from "main" field
 // foo => { value: 1 }
js
// foo.cjs
 module.exports = {
   value: 1,
 }
json
// package.json
 {
   "main": "./foo.cjs"
-}

browser

string 工具包主入口

当项目仅服务于浏览器端,则应采用此字段代替 main 字段

html
<script src="foo.js"></script>

module

string 工具包主入口

非官方支持的字段,基本上是 WebpackRollup 等打包工具为支持 ES Module 而约定的字段

exports

`,31),v=s("code",null,"Record",-1),f=l(`

为工具包主入口及其语义版本升级提供了更可靠的保证,支持多模块、多环境、子路径等定义形式。

json
{
+}

browser

string 工具包主入口

当项目仅服务于浏览器端,则应采用此字段代替 main 字段

html
<script src="foo.js"></script>

module

string 工具包主入口

非官方支持的字段,基本上是 WebpackRollup 等打包工具为支持 ES Module 而约定的字段

exports

`,31),v=s("code",null,"Record",-1),C=l(`

为工具包主入口及其语义版本升级提供了更可靠的保证,支持多模块、多环境、子路径等定义形式。

json
{
   "exports": {
     ".": {
       "node-addons": "", // for C++ plugins
@@ -115,7 +115,7 @@ import{_ as p,G as t,h as r,q as s,e as a,L as n,b as e,aa as l,o as h}from"./ch
       }
     }
   }
-}

脚本配置

scripts

Record<string, string> 带有以下默认生命周期的脚本命令: <pre> | <post>

  • install
  • uninstall
  • start
  • restart
  • stop
  • test
  • pack
  • publish
  • 自定义脚本命令

特殊的 prepareprepublishOnlyscripts 文档

TIP

在 pnpm@6 与 yarn2 中, preinstall 将在 install 后执行,而不是在 install 之前

为此 pnpm 提供了 pnpm:devPreinstall 钩子以兼容开发者的使用习惯

config

Record<string, string> process.env 配置命令行的环境变量

js
#!/usr/bin/env node
+}

脚本配置

scripts

Record<string, string> 带有以下默认生命周期的脚本命令: <pre> | <post>

  • install
  • uninstall
  • start
  • restart
  • stop
  • test
  • pack
  • publish
  • 自定义脚本命令

特殊的 prepareprepublishOnlyscripts 文档

TIP

在 pnpm@6 与 yarn2 中, preinstall 将在 install 后执行,而不是在 install 之前

为此 pnpm 提供了 pnpm:devPreinstall 钩子以兼容开发者的使用习惯

config

Record<string, string> process.env 配置命令行的环境变量

js
#!/usr/bin/env node
 
 console.log(process.env.npm_package_config_port) // 8732
 console.log(process.env.npm_package_config_foo) // bar
json
{
@@ -150,4 +150,4 @@ import{_ as p,G as t,h as r,q as s,e as a,L as n,b as e,aa as l,o as h}from"./ch
   {
     "cpu": ["!arm"]
   }
-}

第三方配置

sideEffects

boolean | Array<string => filePath> 声明存在副作用的模块,用于 Webpack 等打包工具的导出优化

对于模块是否有副作用的定义,基本是指开发者在设计时是否产生了副作用,而不必关心经过打包工具处理后的最终产物。

unpkg

string => filePath 在发布到 npm 后,可以使用此字段为项目对应的文件开启 CDN 服务,默认为 main

TIP

参阅 unpkg | docs

jsdelivr

string => filePath 类似于 unpkg

cosmiconfig

基于 cosmiconfig 实现的相关配置仅在此简单罗列常用工具

`,74);function C(B,D,j,A,_,x){const i=t("Badge");return h(),r("div",null,[o,d,s("h3",c,[a("name "),n(i,null,{default:e(()=>[a("required")]),_:1}),a(),u]),g,s("h3",E,[a("version "),n(i,null,{default:e(()=>[a("required")]),_:1}),a(),b]),m,s("ul",null,[s("li",null,[y,a(),n(i,null,{default:e(()=>[a("recommend")]),_:1})]),F]),q,s("p",null,[v,a(" 最新标准的导出接口 "),n(i,null,{default:e(()=>[a("recommend")]),_:1})]),f])}const S=p(k,[["render",C]]);export{P as __pageData,S as default}; +}

第三方配置

sideEffects

boolean | Array<string => filePath> 声明存在副作用的模块,用于 Webpack 等打包工具的导出优化

对于模块是否有副作用的定义,基本是指开发者在设计时是否产生了副作用,而不必关心经过打包工具处理后的最终产物。

unpkg

string => filePath 在发布到 npm 后,可以使用此字段为项目对应的文件开启 CDN 服务,默认为 main

TIP

参阅 unpkg | docs

jsdelivr

string => filePath 类似于 unpkg

cosmiconfig

基于 cosmiconfig 实现的相关配置仅在此简单罗列常用工具

`,74);function f(B,D,j,_,A,w){const i=t("Badge");return h(),r("div",null,[o,d,s("h3",c,[a("name "),n(i,null,{default:e(()=>[a("required")]),_:1}),a(),u]),g,s("h3",E,[a("version "),n(i,null,{default:e(()=>[a("required")]),_:1}),a(),b]),m,s("ul",null,[s("li",null,[y,a(),n(i,null,{default:e(()=>[a("recommend")]),_:1})]),F]),q,s("p",null,[v,a(" 最新标准的导出接口 "),n(i,null,{default:e(()=>[a("recommend")]),_:1})]),C])}const S=p(k,[["render",f]]);export{P as __pageData,S as default}; diff --git a/assets/pit_editor.md.B3A8EYgt.js b/assets/pit_editor.md.D7PRr_VP.js similarity index 94% rename from assets/pit_editor.md.B3A8EYgt.js rename to assets/pit_editor.md.D7PRr_VP.js index 2404cc06..f6d2bc0b 100644 --- a/assets/pit_editor.md.B3A8EYgt.js +++ b/assets/pit_editor.md.D7PRr_VP.js @@ -1 +1 @@ -import{_ as s,h as i,o as e,aa as a}from"./chunks/framework.C-tu2utv.js";const m=JSON.parse('{"title":"编辑器踩坑记录","description":"记录个人遇到或他人分享的编辑器相关踩坑记录","frontmatter":{"description":"记录个人遇到或他人分享的编辑器相关踩坑记录"},"headers":[],"relativePath":"pit/editor.md","filePath":"pit/editor.md","lastUpdated":1715327095000}'),t={name:"pit/editor.md"},o=a('

编辑器踩坑记录

在 VSCode 使用 GUI 时提示 xxx: command not found

husky 为例

在 VSCode 中使用 GUI(源代码管理 - 输入框)进行 git commit 时,提示 Git: .husky/commit-msg: line 4: npx: command not found

原因

  1. 使用了 fnmnvm 存在了多个版本的 Node.js
  2. 在终端外部启动的 GUI 不会初始化 Node.js,导致 $PATH 中没有 Node.js
  3. 当使用 VSCode GUI 时,就会导致 Node.js 相关的命令丢失

解决方法

一共有如下几种方案

  1. 通过 VSCode 的 code 命令打开编辑器(使用命令行进入到项目目录 code .
  2. 添加 ~/.config/husky/init.sh~/.huskyrc 文件(内容如下)

~/.huskyrc 高版本已弃用

bash
eval "$(fnm env --use-on-cd)"
bash
export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"

shell 启动文件快速且轻量级时可直接在 ~/.config/husky/init.sh~/.huskyrc 配置如下

Oh My ZSH: 你们针对我?

sh
. ~/.zshrc
',14),n=[o];function d(l,p,c,h,r,k){return e(),i("div",null,n)}const g=s(t,[["render",d]]);export{m as __pageData,g as default}; +import{_ as s,h as i,o as e,aa as a}from"./chunks/framework.C-tu2utv.js";const m=JSON.parse('{"title":"编辑器踩坑记录","description":"记录个人遇到或他人分享的编辑器相关踩坑记录","frontmatter":{"description":"记录个人遇到或他人分享的编辑器相关踩坑记录"},"headers":[],"relativePath":"pit/editor.md","filePath":"pit/editor.md","lastUpdated":1715327095000}'),t={name:"pit/editor.md"},o=a('

编辑器踩坑记录

在 VSCode 使用 GUI 时提示 xxx: command not found

husky 为例

在 VSCode 中使用 GUI(源代码管理 - 输入框)进行 git commit 时,提示 Git: .husky/commit-msg: line 4: npx: command not found

原因

  1. 使用了 fnmnvm 存在了多个版本的 Node.js
  2. 在终端外部启动的 GUI 不会初始化 Node.js,导致 $PATH 中没有 Node.js
  3. 当使用 VSCode GUI 时,就会导致 Node.js 相关的命令丢失

解决方法

一共有如下几种方案

  1. 通过 VSCode 的 code 命令打开编辑器(使用命令行进入到项目目录 code .
  2. 添加 ~/.config/husky/init.sh~/.huskyrc 文件(内容如下)

~/.huskyrc 高版本已弃用

bash
eval "$(fnm env --use-on-cd)"
bash
export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"

shell 启动文件快速且轻量级时可直接在 ~/.config/husky/init.sh~/.huskyrc 配置如下

Oh My ZSH: 你们针对我?

sh
. ~/.zshrc
',14),n=[o];function d(l,c,p,h,r,k){return e(),i("div",null,n)}const g=s(t,[["render",d]]);export{m as __pageData,g as default}; diff --git a/assets/pit_editor.md.B3A8EYgt.lean.js b/assets/pit_editor.md.D7PRr_VP.lean.js similarity index 88% rename from assets/pit_editor.md.B3A8EYgt.lean.js rename to assets/pit_editor.md.D7PRr_VP.lean.js index 1d947be4..976b1208 100644 --- a/assets/pit_editor.md.B3A8EYgt.lean.js +++ b/assets/pit_editor.md.D7PRr_VP.lean.js @@ -1 +1 @@ -import{_ as s,h as i,o as e,aa as a}from"./chunks/framework.C-tu2utv.js";const m=JSON.parse('{"title":"编辑器踩坑记录","description":"记录个人遇到或他人分享的编辑器相关踩坑记录","frontmatter":{"description":"记录个人遇到或他人分享的编辑器相关踩坑记录"},"headers":[],"relativePath":"pit/editor.md","filePath":"pit/editor.md","lastUpdated":1715327095000}'),t={name:"pit/editor.md"},o=a("",14),n=[o];function d(l,p,c,h,r,k){return e(),i("div",null,n)}const g=s(t,[["render",d]]);export{m as __pageData,g as default}; +import{_ as s,h as i,o as e,aa as a}from"./chunks/framework.C-tu2utv.js";const m=JSON.parse('{"title":"编辑器踩坑记录","description":"记录个人遇到或他人分享的编辑器相关踩坑记录","frontmatter":{"description":"记录个人遇到或他人分享的编辑器相关踩坑记录"},"headers":[],"relativePath":"pit/editor.md","filePath":"pit/editor.md","lastUpdated":1715327095000}'),t={name:"pit/editor.md"},o=a("",14),n=[o];function d(l,c,p,h,r,k){return e(),i("div",null,n)}const g=s(t,[["render",d]]);export{m as __pageData,g as default}; diff --git a/assets/workflow_library_dayjs.md.DQfFzX36.js b/assets/workflow_library_dayjs.md.D5iAKsy5.js similarity index 96% rename from assets/workflow_library_dayjs.md.DQfFzX36.js rename to assets/workflow_library_dayjs.md.D5iAKsy5.js index 24bfbe70..3456397f 100644 --- a/assets/workflow_library_dayjs.md.DQfFzX36.js +++ b/assets/workflow_library_dayjs.md.D5iAKsy5.js @@ -1,4 +1,4 @@ -import{V as rs}from"./chunks/vmp_components.DUnU2hKs.js";import{l as ss,p as Es,B as ds,o as ns,h as ts,q as s,f as U,e as h,H as ys,L as is,b as as,g as gs,aa as hs}from"./chunks/framework.C-tu2utv.js";var ls=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function ks(M){return M&&M.__esModule&&Object.prototype.hasOwnProperty.call(M,"default")?M.default:M}var es={exports:{}};(function(M,I){(function(m,F){M.exports=F()})(ls,function(){var m=1e3,F=6e4,S=36e5,H="millisecond",D="second",j="minute",T="hour",w="day",Y="week",v="month",P="quarter",A="year",$="date",N="Invalid Date",G=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,x=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,K={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(l){var n=["th","st","nd","rd"],i=l%100;return"["+l+(n[(i-20)%10]||n[i]||n[0])+"]"}},O=function(l,n,i){var k=String(l);return!k||k.length>=n?l:""+Array(n+1-k.length).join(i)+l},X={s:O,z:function(l){var n=-l.utcOffset(),i=Math.abs(n),k=Math.floor(i/60),a=i%60;return(n<=0?"+":"-")+O(k,2,"0")+":"+O(a,2,"0")},m:function l(n,i){if(n.date()1)return l(E[0])}else{var c=n.name;y[c]=n,a=c}return!k&&a&&(W=a),a||!k&&W},d=function(l,n){if(t(l))return l.clone();var i=typeof n=="object"?n:{};return i.date=l,i.args=arguments,new o(i)},p=X;p.l=g,p.i=t,p.w=function(l,n){return d(l,{locale:n.$L,utc:n.$u,x:n.$x,$offset:n.$offset})};var o=function(){function l(i){this.$L=g(i.locale,null,!0),this.parse(i),this.$x=this.$x||i.x||{},this[e]=!0}var n=l.prototype;return n.parse=function(i){this.$d=function(k){var a=k.date,r=k.utc;if(a===null)return new Date(NaN);if(p.u(a))return new Date;if(a instanceof Date)return new Date(a);if(typeof a=="string"&&!/Z$/i.test(a)){var E=a.match(G);if(E){var c=E[2]-1||0,u=(E[7]||"0").substring(0,3);return r?new Date(Date.UTC(E[1],c,E[3]||1,E[4]||0,E[5]||0,E[6]||0,u)):new Date(E[1],c,E[3]||1,E[4]||0,E[5]||0,E[6]||0,u)}}return new Date(a)}(i),this.init()},n.init=function(){var i=this.$d;this.$y=i.getFullYear(),this.$M=i.getMonth(),this.$D=i.getDate(),this.$W=i.getDay(),this.$H=i.getHours(),this.$m=i.getMinutes(),this.$s=i.getSeconds(),this.$ms=i.getMilliseconds()},n.$utils=function(){return p},n.isValid=function(){return this.$d.toString()!==N},n.isSame=function(i,k){var a=d(i);return this.startOf(k)<=a&&a<=this.endOf(k)},n.isAfter=function(i,k){return d(i){const S=R(),D=R().endOf("D").diff(S);if(D<=0){cancelAnimationFrame(I.value);return}m.value=R.duration(D),I.value=requestAnimationFrame(F)};return Es(()=>{I.value=requestAnimationFrame(F)}),ds(()=>{cancelAnimationFrame(I.value)}),(S,H)=>(ns(),ts(ys,null,[s("div",os,[ms,s("div",bs,[s("div",{class:"countdown",innerHTML:m.value.format("[]HH[] 时 []mm[] 分 []ss[] 秒")},null,8,Cs),s("div",fs,U(m.value.format("D 天 HH 时 mm 分 ss 秒")),1),s("div",Bs,U(m.value.format("DD : HH : mm : ss")),1),s("div",Ds,U(m.value.format("HH-mm-ss")),1)])]),s("div",vs,[As,s("div",ws,[s("span",null,U(m.value.hours()),1),h(" 时 "),s("span",null,U(m.value.minutes()),1),h(" 分 "),s("span",null,U(m.value.seconds()),1),h(" 秒 "),s("span",null,U(m.value.milliseconds()),1)])])],64))}},_s=hs(`

Day.js 使用技巧

使用 Day.js 实现倒计时

js
import dayjs from 'dayjs'
+import{V as rs}from"./chunks/vmp_components.DUnU2hKs.js";import{l as ss,p as Es,B as ds,o as ns,h as ts,q as s,f as L,e as h,H as ys,L as is,b as as,g as gs,aa as hs}from"./chunks/framework.C-tu2utv.js";var ls=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function ks(M){return M&&M.__esModule&&Object.prototype.hasOwnProperty.call(M,"default")?M.default:M}var es={exports:{}};(function(M,U){(function(m,F){M.exports=F()})(ls,function(){var m=1e3,F=6e4,S=36e5,H="millisecond",D="second",j="minute",T="hour",w="day",Y="week",v="month",P="quarter",A="year",$="date",N="Invalid Date",Q=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,x=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,X={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(l){var n=["th","st","nd","rd"],i=l%100;return"["+l+(n[(i-20)%10]||n[i]||n[0])+"]"}},O=function(l,n,i){var k=String(l);return!k||k.length>=n?l:""+Array(n+1-k.length).join(i)+l},R={s:O,z:function(l){var n=-l.utcOffset(),i=Math.abs(n),k=Math.floor(i/60),a=i%60;return(n<=0?"+":"-")+O(k,2,"0")+":"+O(a,2,"0")},m:function l(n,i){if(n.date()1)return l(E[0])}else{var c=n.name;y[c]=n,a=c}return!k&&a&&(q=a),a||!k&&q},d=function(l,n){if(t(l))return l.clone();var i=typeof n=="object"?n:{};return i.date=l,i.args=arguments,new o(i)},p=R;p.l=g,p.i=t,p.w=function(l,n){return d(l,{locale:n.$L,utc:n.$u,x:n.$x,$offset:n.$offset})};var o=function(){function l(i){this.$L=g(i.locale,null,!0),this.parse(i),this.$x=this.$x||i.x||{},this[e]=!0}var n=l.prototype;return n.parse=function(i){this.$d=function(k){var a=k.date,r=k.utc;if(a===null)return new Date(NaN);if(p.u(a))return new Date;if(a instanceof Date)return new Date(a);if(typeof a=="string"&&!/Z$/i.test(a)){var E=a.match(Q);if(E){var c=E[2]-1||0,u=(E[7]||"0").substring(0,3);return r?new Date(Date.UTC(E[1],c,E[3]||1,E[4]||0,E[5]||0,E[6]||0,u)):new Date(E[1],c,E[3]||1,E[4]||0,E[5]||0,E[6]||0,u)}}return new Date(a)}(i),this.init()},n.init=function(){var i=this.$d;this.$y=i.getFullYear(),this.$M=i.getMonth(),this.$D=i.getDate(),this.$W=i.getDay(),this.$H=i.getHours(),this.$m=i.getMinutes(),this.$s=i.getSeconds(),this.$ms=i.getMilliseconds()},n.$utils=function(){return p},n.isValid=function(){return this.$d.toString()!==N},n.isSame=function(i,k){var a=d(i);return this.startOf(k)<=a&&a<=this.endOf(k)},n.isAfter=function(i,k){return d(i){const S=G(),D=G().endOf("D").diff(S);if(D<=0){cancelAnimationFrame(U.value);return}m.value=G.duration(D),U.value=requestAnimationFrame(F)};return Es(()=>{U.value=requestAnimationFrame(F)}),ds(()=>{cancelAnimationFrame(U.value)}),(S,H)=>(ns(),ts(ys,null,[s("div",os,[ms,s("div",bs,[s("div",{class:"countdown",innerHTML:m.value.format("[]HH[] 时 []mm[] 分 []ss[] 秒")},null,8,Cs),s("div",fs,L(m.value.format("D 天 HH 时 mm 分 ss 秒")),1),s("div",Bs,L(m.value.format("DD : HH : mm : ss")),1),s("div",Ds,L(m.value.format("HH-mm-ss")),1)])]),s("div",vs,[As,s("div",ws,[s("span",null,L(m.value.hours()),1),h(" 时 "),s("span",null,L(m.value.minutes()),1),h(" 分 "),s("span",null,L(m.value.seconds()),1),h(" 秒 "),s("span",null,L(m.value.milliseconds()),1)])])],64))}},_s=hs(`

Day.js 使用技巧

使用 Day.js 实现倒计时

js
import dayjs from 'dayjs'
 import duration from 'dayjs/plugin/duration'
 
 // 配置 duration 插件
@@ -80,7 +80,7 @@ import{V as rs}from"./chunks/vmp_components.DUnU2hKs.js";import{l as ss,p as Es,
 `),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"      <"),s("span",{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"}},"span"),s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},">{{ count."),s("span",{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"}},"milliseconds"),s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"() }}")]),h(`
 `),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"    ")]),h(`
 `),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"  ")]),h(`
-`),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"")])])]),s("div",{class:"line-numbers-wrapper","aria-hidden":"true"},[s("span",{class:"line-number"},"1"),s("br"),s("span",{class:"line-number"},"2"),s("br"),s("span",{class:"line-number"},"3"),s("br"),s("span",{class:"line-number"},"4"),s("br"),s("span",{class:"line-number"},"5"),s("br"),s("span",{class:"line-number"},"6"),s("br"),s("span",{class:"line-number"},"7"),s("br"),s("span",{class:"line-number"},"8"),s("br"),s("span",{class:"line-number"},"9"),s("br"),s("span",{class:"line-number"},"10"),s("br"),s("span",{class:"line-number"},"11"),s("br"),s("span",{class:"line-number"},"12"),s("br"),s("span",{class:"line-number"},"13"),s("br"),s("span",{class:"line-number"},"14"),s("br"),s("span",{class:"line-number"},"15"),s("br"),s("span",{class:"line-number"},"16"),s("br"),s("span",{class:"line-number"},"17"),s("br"),s("span",{class:"line-number"},"18"),s("br"),s("span",{class:"line-number"},"19"),s("br"),s("span",{class:"line-number"},"20"),s("br"),s("span",{class:"line-number"},"21"),s("br"),s("span",{class:"line-number"},"22"),s("br"),s("span",{class:"line-number"},"23"),s("br"),s("span",{class:"line-number"},"24"),s("br"),s("span",{class:"line-number"},"25"),s("br"),s("span",{class:"line-number"},"26"),s("br"),s("span",{class:"line-number"},"27"),s("br"),s("span",{class:"line-number"},"28"),s("br"),s("span",{class:"line-number"},"29"),s("br"),s("span",{class:"line-number"},"30"),s("br"),s("span",{class:"line-number"},"31"),s("br"),s("span",{class:"line-number"},"32"),s("br"),s("span",{class:"line-number"},"33"),s("br"),s("span",{class:"line-number"},"34"),s("br"),s("span",{class:"line-number"},"35"),s("br"),s("span",{class:"line-number"},"36"),s("br"),s("span",{class:"line-number"},"37"),s("br"),s("span",{class:"line-number"},"38"),s("br"),s("span",{class:"line-number"},"39"),s("br"),s("span",{class:"line-number"},"40"),s("br"),s("span",{class:"line-number"},"41"),s("br"),s("span",{class:"line-number"},"42"),s("br"),s("span",{class:"line-number"},"43"),s("br"),s("span",{class:"line-number"},"44"),s("br"),s("span",{class:"line-number"},"45"),s("br"),s("span",{class:"line-number"},"46"),s("br"),s("span",{class:"line-number"},"47"),s("br"),s("span",{class:"line-number"},"48"),s("br"),s("span",{class:"line-number"},"49"),s("br"),s("span",{class:"line-number"},"50"),s("br"),s("span",{class:"line-number"},"51"),s("br"),s("span",{class:"line-number"},"52"),s("br"),s("span",{class:"line-number"},"53"),s("br"),s("span",{class:"line-number"},"54"),s("br"),s("span",{class:"line-number"},"55"),s("br"),s("span",{class:"line-number"},"56"),s("br"),s("span",{class:"line-number"},"57"),s("br"),s("span",{class:"line-number"},"58"),s("br"),s("span",{class:"line-number"},"59"),s("br"),s("span",{class:"line-number"},"60"),s("br"),s("span",{class:"line-number"},"61"),s("br"),s("span",{class:"line-number"},"62"),s("br")])],-1),js=hs(`

优点

  • 使用 Day.js 对象的 format 方法进行格式化
    • 无需自己实现格式化函数
    • 个位数时都不需要字符串补位操作
    • 在使用 format 时,在方括号中的字符不会被格式化替换
  • 兼容性良好

缺点

当需求场景超出 Day.js 对象的 format 方法的能力时(即不是标准的年月日时分秒格式)需要自己实现格式化函数

  • 40 天 13 时 14 分 00 秒
  • 52 时 13 分 14 秒
  • 100 分 50 秒

常用预设范围

常用于 antdRangePicker 组件

js
import dayjs from 'dayjs'
+`),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"")])])]),s("div",{class:"line-numbers-wrapper","aria-hidden":"true"},[s("span",{class:"line-number"},"1"),s("br"),s("span",{class:"line-number"},"2"),s("br"),s("span",{class:"line-number"},"3"),s("br"),s("span",{class:"line-number"},"4"),s("br"),s("span",{class:"line-number"},"5"),s("br"),s("span",{class:"line-number"},"6"),s("br"),s("span",{class:"line-number"},"7"),s("br"),s("span",{class:"line-number"},"8"),s("br"),s("span",{class:"line-number"},"9"),s("br"),s("span",{class:"line-number"},"10"),s("br"),s("span",{class:"line-number"},"11"),s("br"),s("span",{class:"line-number"},"12"),s("br"),s("span",{class:"line-number"},"13"),s("br"),s("span",{class:"line-number"},"14"),s("br"),s("span",{class:"line-number"},"15"),s("br"),s("span",{class:"line-number"},"16"),s("br"),s("span",{class:"line-number"},"17"),s("br"),s("span",{class:"line-number"},"18"),s("br"),s("span",{class:"line-number"},"19"),s("br"),s("span",{class:"line-number"},"20"),s("br"),s("span",{class:"line-number"},"21"),s("br"),s("span",{class:"line-number"},"22"),s("br"),s("span",{class:"line-number"},"23"),s("br"),s("span",{class:"line-number"},"24"),s("br"),s("span",{class:"line-number"},"25"),s("br"),s("span",{class:"line-number"},"26"),s("br"),s("span",{class:"line-number"},"27"),s("br"),s("span",{class:"line-number"},"28"),s("br"),s("span",{class:"line-number"},"29"),s("br"),s("span",{class:"line-number"},"30"),s("br"),s("span",{class:"line-number"},"31"),s("br"),s("span",{class:"line-number"},"32"),s("br"),s("span",{class:"line-number"},"33"),s("br"),s("span",{class:"line-number"},"34"),s("br"),s("span",{class:"line-number"},"35"),s("br"),s("span",{class:"line-number"},"36"),s("br"),s("span",{class:"line-number"},"37"),s("br"),s("span",{class:"line-number"},"38"),s("br"),s("span",{class:"line-number"},"39"),s("br"),s("span",{class:"line-number"},"40"),s("br"),s("span",{class:"line-number"},"41"),s("br"),s("span",{class:"line-number"},"42"),s("br"),s("span",{class:"line-number"},"43"),s("br"),s("span",{class:"line-number"},"44"),s("br"),s("span",{class:"line-number"},"45"),s("br"),s("span",{class:"line-number"},"46"),s("br"),s("span",{class:"line-number"},"47"),s("br"),s("span",{class:"line-number"},"48"),s("br"),s("span",{class:"line-number"},"49"),s("br"),s("span",{class:"line-number"},"50"),s("br"),s("span",{class:"line-number"},"51"),s("br"),s("span",{class:"line-number"},"52"),s("br"),s("span",{class:"line-number"},"53"),s("br"),s("span",{class:"line-number"},"54"),s("br"),s("span",{class:"line-number"},"55"),s("br"),s("span",{class:"line-number"},"56"),s("br"),s("span",{class:"line-number"},"57"),s("br"),s("span",{class:"line-number"},"58"),s("br"),s("span",{class:"line-number"},"59"),s("br"),s("span",{class:"line-number"},"60"),s("br"),s("span",{class:"line-number"},"61"),s("br"),s("span",{class:"line-number"},"62"),s("br")])],-1),js=hs(`

优点

  • 使用 Day.js 对象的 format 方法进行格式化
    • 无需自己实现格式化函数
    • 个位数时都不需要字符串补位操作
    • 在使用 format 时,在方括号中的字符不会被格式化替换
  • 兼容性良好

缺点

当需求场景超出 Day.js 对象的 format 方法的能力时(即不是标准的年月日时分秒格式)需要自己实现格式化函数

  • 40 天 13 时 14 分 00 秒
  • 52 时 13 分 14 秒
  • 100 分 50 秒

常用预设范围

常用于 antdRangePicker 组件

js
import dayjs from 'dayjs'
 
 // 获取当前的时间
 const now = dayjs()
@@ -152,4 +152,4 @@ import{V as rs}from"./chunks/vmp_components.DUnU2hKs.js";import{l as ss,p as Es,
   近90天: [now.subtract(90, 'day'), now],
   近180天: [now.subtract(180, 'day'), now],
   近一年: [now.subtract(1, 'year'), now],
-}

注意点

  • 相对范围的截止时间为当前时间
  • 绝对范围的截止时间为最后一天的 23:59:00
`,6),xs=JSON.parse('{"title":"Day.js 使用技巧","description":"","frontmatter":{},"headers":[],"relativePath":"workflow/library/dayjs.md","filePath":"workflow/library/dayjs.md","lastUpdated":1702913488000}'),Os={name:"workflow/library/dayjs.md"},Ts=Object.assign(Os,{setup(M){return(I,m)=>(ns(),ts("div",null,[_s,is(gs(rs),{lang:"vue",meta:"preview",code:"%3Cscript%20setup%3E%0Aimport%20%7B%20ref%2C%20onMounted%2C%20onUnmounted%20%7D%20from%20'vue'%0Aimport%20dayjs%20from%20'dayjs'%0Aimport%20duration%20from%20'dayjs%2Fplugin%2Fduration'%0A%0Adayjs.extend(duration)%0A%0Aconst%20timer%20%3D%20ref(null)%0Aconst%20count%20%3D%20ref(dayjs.duration(0))%0A%0A%2F%2F%20%E8%AE%A1%E7%AE%97%E5%80%92%E8%AE%A1%E6%97%B6%E7%9A%84%E6%97%B6%E9%97%B4%E5%B7%AE%0Aconst%20countdown%20%3D%20()%20%3D%3E%20%7B%0A%20%20const%20now%20%3D%20dayjs()%0A%20%20const%20target%20%3D%20dayjs().endOf('D')%0A%20%20const%20diff%20%3D%20target.diff(now)%0A%0A%20%20if%20(diff%20%3C%3D%200)%20%7B%0A%20%20%20%20cancelAnimationFrame(timer.value)%0A%20%20%20%20return%0A%20%20%7D%0A%0A%20%20count.value%20%3D%20dayjs.duration(diff)%0A%20%20timer.value%20%3D%20requestAnimationFrame(countdown)%0A%7D%0A%0AonMounted(()%20%3D%3E%20%7B%0A%20%20timer.value%20%3D%20requestAnimationFrame(countdown)%0A%7D)%0A%0AonUnmounted(()%20%3D%3E%20%7B%0A%20%20cancelAnimationFrame(timer.value)%0A%7D)%0A%3C%2Fscript%3E%0A%0A%3Ctemplate%3E%0A%20%20%3Cdiv%20class%3D%22flex%20m-1%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22w-36%22%3E%E4%BD%BF%E7%94%A8%20format%20%E6%96%B9%E6%B3%95%EF%BC%9A%3C%2Fdiv%3E%0A%20%20%20%20%3Cdiv%20class%3D%22flex-1%22%3E%0A%20%20%20%20%20%20%3Cdiv%0A%20%20%20%20%20%20%20%20class%3D%22countdown%22%0A%20%20%20%20%20%20%20%20v-html%3D%22%0A%20%20%20%20%20%20%20%20%20%20count.format('%5B%3Cspan%3E%5DHH%5B%3C%2Fspan%3E%5D%20%E6%97%B6%20%5B%3Cspan%3E%5Dmm%5B%3C%2Fspan%3E%5D%20%E5%88%86%20%5B%3Cspan%3E%5Dss%5B%3C%2Fspan%3E%5D%20%E7%A7%92')%0A%20%20%20%20%20%20%20%20%22%0A%20%20%20%20%20%20%3E%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('D%20%E5%A4%A9%20HH%20%E6%97%B6%20mm%20%E5%88%86%20ss%20%E7%A7%92')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('DD%20%3A%20HH%20%3A%20mm%20%3A%20ss')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('HH-mm-ss')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%20%20%3Cdiv%20class%3D%22flex%20m-1%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22w-36%22%3E%E4%BD%BF%E7%94%A8%E5%8F%96%E5%80%BC%E6%96%B9%E6%B3%95%EF%BC%9A%3C%2Fdiv%3E%0A%20%20%20%20%3Cdiv%20class%3D%22countdown%22%3E%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.hours()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E6%97%B6%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.minutes()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E5%88%86%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.seconds()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E7%A7%92%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.milliseconds()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Ftemplate%3E",component:"CodePreview"},{code:as(()=>[Ms]),default:as(()=>[is($s)]),_:1}),js]))}});export{xs as __pageData,Ts as default}; +}

注意点

  • 相对范围的截止时间为当前时间
  • 绝对范围的截止时间为最后一天的 23:59:00
`,6),xs=JSON.parse('{"title":"Day.js 使用技巧","description":"","frontmatter":{},"headers":[],"relativePath":"workflow/library/dayjs.md","filePath":"workflow/library/dayjs.md","lastUpdated":1702913488000}'),Os={name:"workflow/library/dayjs.md"},Ts=Object.assign(Os,{setup(M){return(U,m)=>(ns(),ts("div",null,[_s,is(gs(rs),{lang:"vue",meta:"preview",code:"%3Cscript%20setup%3E%0Aimport%20%7B%20ref%2C%20onMounted%2C%20onUnmounted%20%7D%20from%20'vue'%0Aimport%20dayjs%20from%20'dayjs'%0Aimport%20duration%20from%20'dayjs%2Fplugin%2Fduration'%0A%0Adayjs.extend(duration)%0A%0Aconst%20timer%20%3D%20ref(null)%0Aconst%20count%20%3D%20ref(dayjs.duration(0))%0A%0A%2F%2F%20%E8%AE%A1%E7%AE%97%E5%80%92%E8%AE%A1%E6%97%B6%E7%9A%84%E6%97%B6%E9%97%B4%E5%B7%AE%0Aconst%20countdown%20%3D%20()%20%3D%3E%20%7B%0A%20%20const%20now%20%3D%20dayjs()%0A%20%20const%20target%20%3D%20dayjs().endOf('D')%0A%20%20const%20diff%20%3D%20target.diff(now)%0A%0A%20%20if%20(diff%20%3C%3D%200)%20%7B%0A%20%20%20%20cancelAnimationFrame(timer.value)%0A%20%20%20%20return%0A%20%20%7D%0A%0A%20%20count.value%20%3D%20dayjs.duration(diff)%0A%20%20timer.value%20%3D%20requestAnimationFrame(countdown)%0A%7D%0A%0AonMounted(()%20%3D%3E%20%7B%0A%20%20timer.value%20%3D%20requestAnimationFrame(countdown)%0A%7D)%0A%0AonUnmounted(()%20%3D%3E%20%7B%0A%20%20cancelAnimationFrame(timer.value)%0A%7D)%0A%3C%2Fscript%3E%0A%0A%3Ctemplate%3E%0A%20%20%3Cdiv%20class%3D%22flex%20m-1%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22w-36%22%3E%E4%BD%BF%E7%94%A8%20format%20%E6%96%B9%E6%B3%95%EF%BC%9A%3C%2Fdiv%3E%0A%20%20%20%20%3Cdiv%20class%3D%22flex-1%22%3E%0A%20%20%20%20%20%20%3Cdiv%0A%20%20%20%20%20%20%20%20class%3D%22countdown%22%0A%20%20%20%20%20%20%20%20v-html%3D%22%0A%20%20%20%20%20%20%20%20%20%20count.format('%5B%3Cspan%3E%5DHH%5B%3C%2Fspan%3E%5D%20%E6%97%B6%20%5B%3Cspan%3E%5Dmm%5B%3C%2Fspan%3E%5D%20%E5%88%86%20%5B%3Cspan%3E%5Dss%5B%3C%2Fspan%3E%5D%20%E7%A7%92')%0A%20%20%20%20%20%20%20%20%22%0A%20%20%20%20%20%20%3E%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('D%20%E5%A4%A9%20HH%20%E6%97%B6%20mm%20%E5%88%86%20ss%20%E7%A7%92')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('DD%20%3A%20HH%20%3A%20mm%20%3A%20ss')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('HH-mm-ss')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%20%20%3Cdiv%20class%3D%22flex%20m-1%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22w-36%22%3E%E4%BD%BF%E7%94%A8%E5%8F%96%E5%80%BC%E6%96%B9%E6%B3%95%EF%BC%9A%3C%2Fdiv%3E%0A%20%20%20%20%3Cdiv%20class%3D%22countdown%22%3E%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.hours()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E6%97%B6%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.minutes()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E5%88%86%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.seconds()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E7%A7%92%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.milliseconds()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Ftemplate%3E",component:"CodePreview"},{code:as(()=>[Ms]),default:as(()=>[is($s)]),_:1}),js]))}});export{xs as __pageData,Ts as default}; diff --git a/assets/workflow_library_dayjs.md.DQfFzX36.lean.js b/assets/workflow_library_dayjs.md.D5iAKsy5.lean.js similarity index 92% rename from assets/workflow_library_dayjs.md.DQfFzX36.lean.js rename to assets/workflow_library_dayjs.md.D5iAKsy5.lean.js index 463fc57b..49613f6d 100644 --- a/assets/workflow_library_dayjs.md.DQfFzX36.lean.js +++ b/assets/workflow_library_dayjs.md.D5iAKsy5.lean.js @@ -1,4 +1,4 @@ -import{V as rs}from"./chunks/vmp_components.DUnU2hKs.js";import{l as ss,p as Es,B as ds,o as ns,h as ts,q as s,f as U,e as h,H as ys,L as is,b as as,g as gs,aa as hs}from"./chunks/framework.C-tu2utv.js";var ls=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function ks(M){return M&&M.__esModule&&Object.prototype.hasOwnProperty.call(M,"default")?M.default:M}var es={exports:{}};(function(M,I){(function(m,F){M.exports=F()})(ls,function(){var m=1e3,F=6e4,S=36e5,H="millisecond",D="second",j="minute",T="hour",w="day",Y="week",v="month",P="quarter",A="year",$="date",N="Invalid Date",G=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,x=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,K={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(l){var n=["th","st","nd","rd"],i=l%100;return"["+l+(n[(i-20)%10]||n[i]||n[0])+"]"}},O=function(l,n,i){var k=String(l);return!k||k.length>=n?l:""+Array(n+1-k.length).join(i)+l},X={s:O,z:function(l){var n=-l.utcOffset(),i=Math.abs(n),k=Math.floor(i/60),a=i%60;return(n<=0?"+":"-")+O(k,2,"0")+":"+O(a,2,"0")},m:function l(n,i){if(n.date()1)return l(E[0])}else{var c=n.name;y[c]=n,a=c}return!k&&a&&(W=a),a||!k&&W},d=function(l,n){if(t(l))return l.clone();var i=typeof n=="object"?n:{};return i.date=l,i.args=arguments,new o(i)},p=X;p.l=g,p.i=t,p.w=function(l,n){return d(l,{locale:n.$L,utc:n.$u,x:n.$x,$offset:n.$offset})};var o=function(){function l(i){this.$L=g(i.locale,null,!0),this.parse(i),this.$x=this.$x||i.x||{},this[e]=!0}var n=l.prototype;return n.parse=function(i){this.$d=function(k){var a=k.date,r=k.utc;if(a===null)return new Date(NaN);if(p.u(a))return new Date;if(a instanceof Date)return new Date(a);if(typeof a=="string"&&!/Z$/i.test(a)){var E=a.match(G);if(E){var c=E[2]-1||0,u=(E[7]||"0").substring(0,3);return r?new Date(Date.UTC(E[1],c,E[3]||1,E[4]||0,E[5]||0,E[6]||0,u)):new Date(E[1],c,E[3]||1,E[4]||0,E[5]||0,E[6]||0,u)}}return new Date(a)}(i),this.init()},n.init=function(){var i=this.$d;this.$y=i.getFullYear(),this.$M=i.getMonth(),this.$D=i.getDate(),this.$W=i.getDay(),this.$H=i.getHours(),this.$m=i.getMinutes(),this.$s=i.getSeconds(),this.$ms=i.getMilliseconds()},n.$utils=function(){return p},n.isValid=function(){return this.$d.toString()!==N},n.isSame=function(i,k){var a=d(i);return this.startOf(k)<=a&&a<=this.endOf(k)},n.isAfter=function(i,k){return d(i){const S=R(),D=R().endOf("D").diff(S);if(D<=0){cancelAnimationFrame(I.value);return}m.value=R.duration(D),I.value=requestAnimationFrame(F)};return Es(()=>{I.value=requestAnimationFrame(F)}),ds(()=>{cancelAnimationFrame(I.value)}),(S,H)=>(ns(),ts(ys,null,[s("div",os,[ms,s("div",bs,[s("div",{class:"countdown",innerHTML:m.value.format("[]HH[] 时 []mm[] 分 []ss[] 秒")},null,8,Cs),s("div",fs,U(m.value.format("D 天 HH 时 mm 分 ss 秒")),1),s("div",Bs,U(m.value.format("DD : HH : mm : ss")),1),s("div",Ds,U(m.value.format("HH-mm-ss")),1)])]),s("div",vs,[As,s("div",ws,[s("span",null,U(m.value.hours()),1),h(" 时 "),s("span",null,U(m.value.minutes()),1),h(" 分 "),s("span",null,U(m.value.seconds()),1),h(" 秒 "),s("span",null,U(m.value.milliseconds()),1)])])],64))}},_s=hs("",6),Ms=s("div",{class:"language-vue vp-adaptive-theme line-numbers-mode"},[s("button",{title:"Copy Code",class:"copy"}),s("span",{class:"lang"},"vue"),s("pre",{class:"shiki shiki-themes github-light github-dark vp-code"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"<"),s("span",{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"}},"script"),s("span",{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"}}," setup"),s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},">")]),h(` +import{V as rs}from"./chunks/vmp_components.DUnU2hKs.js";import{l as ss,p as Es,B as ds,o as ns,h as ts,q as s,f as L,e as h,H as ys,L as is,b as as,g as gs,aa as hs}from"./chunks/framework.C-tu2utv.js";var ls=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function ks(M){return M&&M.__esModule&&Object.prototype.hasOwnProperty.call(M,"default")?M.default:M}var es={exports:{}};(function(M,U){(function(m,F){M.exports=F()})(ls,function(){var m=1e3,F=6e4,S=36e5,H="millisecond",D="second",j="minute",T="hour",w="day",Y="week",v="month",P="quarter",A="year",$="date",N="Invalid Date",Q=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,x=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,X={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(l){var n=["th","st","nd","rd"],i=l%100;return"["+l+(n[(i-20)%10]||n[i]||n[0])+"]"}},O=function(l,n,i){var k=String(l);return!k||k.length>=n?l:""+Array(n+1-k.length).join(i)+l},R={s:O,z:function(l){var n=-l.utcOffset(),i=Math.abs(n),k=Math.floor(i/60),a=i%60;return(n<=0?"+":"-")+O(k,2,"0")+":"+O(a,2,"0")},m:function l(n,i){if(n.date()1)return l(E[0])}else{var c=n.name;y[c]=n,a=c}return!k&&a&&(q=a),a||!k&&q},d=function(l,n){if(t(l))return l.clone();var i=typeof n=="object"?n:{};return i.date=l,i.args=arguments,new o(i)},p=R;p.l=g,p.i=t,p.w=function(l,n){return d(l,{locale:n.$L,utc:n.$u,x:n.$x,$offset:n.$offset})};var o=function(){function l(i){this.$L=g(i.locale,null,!0),this.parse(i),this.$x=this.$x||i.x||{},this[e]=!0}var n=l.prototype;return n.parse=function(i){this.$d=function(k){var a=k.date,r=k.utc;if(a===null)return new Date(NaN);if(p.u(a))return new Date;if(a instanceof Date)return new Date(a);if(typeof a=="string"&&!/Z$/i.test(a)){var E=a.match(Q);if(E){var c=E[2]-1||0,u=(E[7]||"0").substring(0,3);return r?new Date(Date.UTC(E[1],c,E[3]||1,E[4]||0,E[5]||0,E[6]||0,u)):new Date(E[1],c,E[3]||1,E[4]||0,E[5]||0,E[6]||0,u)}}return new Date(a)}(i),this.init()},n.init=function(){var i=this.$d;this.$y=i.getFullYear(),this.$M=i.getMonth(),this.$D=i.getDate(),this.$W=i.getDay(),this.$H=i.getHours(),this.$m=i.getMinutes(),this.$s=i.getSeconds(),this.$ms=i.getMilliseconds()},n.$utils=function(){return p},n.isValid=function(){return this.$d.toString()!==N},n.isSame=function(i,k){var a=d(i);return this.startOf(k)<=a&&a<=this.endOf(k)},n.isAfter=function(i,k){return d(i){const S=G(),D=G().endOf("D").diff(S);if(D<=0){cancelAnimationFrame(U.value);return}m.value=G.duration(D),U.value=requestAnimationFrame(F)};return Es(()=>{U.value=requestAnimationFrame(F)}),ds(()=>{cancelAnimationFrame(U.value)}),(S,H)=>(ns(),ts(ys,null,[s("div",os,[ms,s("div",bs,[s("div",{class:"countdown",innerHTML:m.value.format("[]HH[] 时 []mm[] 分 []ss[] 秒")},null,8,Cs),s("div",fs,L(m.value.format("D 天 HH 时 mm 分 ss 秒")),1),s("div",Bs,L(m.value.format("DD : HH : mm : ss")),1),s("div",Ds,L(m.value.format("HH-mm-ss")),1)])]),s("div",vs,[As,s("div",ws,[s("span",null,L(m.value.hours()),1),h(" 时 "),s("span",null,L(m.value.minutes()),1),h(" 分 "),s("span",null,L(m.value.seconds()),1),h(" 秒 "),s("span",null,L(m.value.milliseconds()),1)])])],64))}},_s=hs("",6),Ms=s("div",{class:"language-vue vp-adaptive-theme line-numbers-mode"},[s("button",{title:"Copy Code",class:"copy"}),s("span",{class:"lang"},"vue"),s("pre",{class:"shiki shiki-themes github-light github-dark vp-code"},[s("code",null,[s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"<"),s("span",{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"}},"script"),s("span",{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"}}," setup"),s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},">")]),h(` `),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"}},"import"),s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}}," { ref, onMounted, onUnmounted } "),s("span",{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"}},"from"),s("span",{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"}}," 'vue'")]),h(` `),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"}},"import"),s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}}," dayjs "),s("span",{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"}},"from"),s("span",{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"}}," 'dayjs'")]),h(` `),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"}},"import"),s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}}," duration "),s("span",{style:{"--shiki-light":"#D73A49","--shiki-dark":"#F97583"}},"from"),s("span",{style:{"--shiki-light":"#032F62","--shiki-dark":"#9ECBFF"}}," 'dayjs/plugin/duration'")]),h(` @@ -59,4 +59,4 @@ import{V as rs}from"./chunks/vmp_components.DUnU2hKs.js";import{l as ss,p as Es, `),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}}," <"),s("span",{style:{"--shiki-light":"#22863A","--shiki-dark":"#85E89D"}},"span"),s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},">{{ count."),s("span",{style:{"--shiki-light":"#6F42C1","--shiki-dark":"#B392F0"}},"milliseconds"),s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"() }}")]),h(` `),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}}," ")]),h(` `),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}}," ")]),h(` -`),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"")])])]),s("div",{class:"line-numbers-wrapper","aria-hidden":"true"},[s("span",{class:"line-number"},"1"),s("br"),s("span",{class:"line-number"},"2"),s("br"),s("span",{class:"line-number"},"3"),s("br"),s("span",{class:"line-number"},"4"),s("br"),s("span",{class:"line-number"},"5"),s("br"),s("span",{class:"line-number"},"6"),s("br"),s("span",{class:"line-number"},"7"),s("br"),s("span",{class:"line-number"},"8"),s("br"),s("span",{class:"line-number"},"9"),s("br"),s("span",{class:"line-number"},"10"),s("br"),s("span",{class:"line-number"},"11"),s("br"),s("span",{class:"line-number"},"12"),s("br"),s("span",{class:"line-number"},"13"),s("br"),s("span",{class:"line-number"},"14"),s("br"),s("span",{class:"line-number"},"15"),s("br"),s("span",{class:"line-number"},"16"),s("br"),s("span",{class:"line-number"},"17"),s("br"),s("span",{class:"line-number"},"18"),s("br"),s("span",{class:"line-number"},"19"),s("br"),s("span",{class:"line-number"},"20"),s("br"),s("span",{class:"line-number"},"21"),s("br"),s("span",{class:"line-number"},"22"),s("br"),s("span",{class:"line-number"},"23"),s("br"),s("span",{class:"line-number"},"24"),s("br"),s("span",{class:"line-number"},"25"),s("br"),s("span",{class:"line-number"},"26"),s("br"),s("span",{class:"line-number"},"27"),s("br"),s("span",{class:"line-number"},"28"),s("br"),s("span",{class:"line-number"},"29"),s("br"),s("span",{class:"line-number"},"30"),s("br"),s("span",{class:"line-number"},"31"),s("br"),s("span",{class:"line-number"},"32"),s("br"),s("span",{class:"line-number"},"33"),s("br"),s("span",{class:"line-number"},"34"),s("br"),s("span",{class:"line-number"},"35"),s("br"),s("span",{class:"line-number"},"36"),s("br"),s("span",{class:"line-number"},"37"),s("br"),s("span",{class:"line-number"},"38"),s("br"),s("span",{class:"line-number"},"39"),s("br"),s("span",{class:"line-number"},"40"),s("br"),s("span",{class:"line-number"},"41"),s("br"),s("span",{class:"line-number"},"42"),s("br"),s("span",{class:"line-number"},"43"),s("br"),s("span",{class:"line-number"},"44"),s("br"),s("span",{class:"line-number"},"45"),s("br"),s("span",{class:"line-number"},"46"),s("br"),s("span",{class:"line-number"},"47"),s("br"),s("span",{class:"line-number"},"48"),s("br"),s("span",{class:"line-number"},"49"),s("br"),s("span",{class:"line-number"},"50"),s("br"),s("span",{class:"line-number"},"51"),s("br"),s("span",{class:"line-number"},"52"),s("br"),s("span",{class:"line-number"},"53"),s("br"),s("span",{class:"line-number"},"54"),s("br"),s("span",{class:"line-number"},"55"),s("br"),s("span",{class:"line-number"},"56"),s("br"),s("span",{class:"line-number"},"57"),s("br"),s("span",{class:"line-number"},"58"),s("br"),s("span",{class:"line-number"},"59"),s("br"),s("span",{class:"line-number"},"60"),s("br"),s("span",{class:"line-number"},"61"),s("br"),s("span",{class:"line-number"},"62"),s("br")])],-1),js=hs("",6),xs=JSON.parse('{"title":"Day.js 使用技巧","description":"","frontmatter":{},"headers":[],"relativePath":"workflow/library/dayjs.md","filePath":"workflow/library/dayjs.md","lastUpdated":1702913488000}'),Os={name:"workflow/library/dayjs.md"},Ts=Object.assign(Os,{setup(M){return(I,m)=>(ns(),ts("div",null,[_s,is(gs(rs),{lang:"vue",meta:"preview",code:"%3Cscript%20setup%3E%0Aimport%20%7B%20ref%2C%20onMounted%2C%20onUnmounted%20%7D%20from%20'vue'%0Aimport%20dayjs%20from%20'dayjs'%0Aimport%20duration%20from%20'dayjs%2Fplugin%2Fduration'%0A%0Adayjs.extend(duration)%0A%0Aconst%20timer%20%3D%20ref(null)%0Aconst%20count%20%3D%20ref(dayjs.duration(0))%0A%0A%2F%2F%20%E8%AE%A1%E7%AE%97%E5%80%92%E8%AE%A1%E6%97%B6%E7%9A%84%E6%97%B6%E9%97%B4%E5%B7%AE%0Aconst%20countdown%20%3D%20()%20%3D%3E%20%7B%0A%20%20const%20now%20%3D%20dayjs()%0A%20%20const%20target%20%3D%20dayjs().endOf('D')%0A%20%20const%20diff%20%3D%20target.diff(now)%0A%0A%20%20if%20(diff%20%3C%3D%200)%20%7B%0A%20%20%20%20cancelAnimationFrame(timer.value)%0A%20%20%20%20return%0A%20%20%7D%0A%0A%20%20count.value%20%3D%20dayjs.duration(diff)%0A%20%20timer.value%20%3D%20requestAnimationFrame(countdown)%0A%7D%0A%0AonMounted(()%20%3D%3E%20%7B%0A%20%20timer.value%20%3D%20requestAnimationFrame(countdown)%0A%7D)%0A%0AonUnmounted(()%20%3D%3E%20%7B%0A%20%20cancelAnimationFrame(timer.value)%0A%7D)%0A%3C%2Fscript%3E%0A%0A%3Ctemplate%3E%0A%20%20%3Cdiv%20class%3D%22flex%20m-1%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22w-36%22%3E%E4%BD%BF%E7%94%A8%20format%20%E6%96%B9%E6%B3%95%EF%BC%9A%3C%2Fdiv%3E%0A%20%20%20%20%3Cdiv%20class%3D%22flex-1%22%3E%0A%20%20%20%20%20%20%3Cdiv%0A%20%20%20%20%20%20%20%20class%3D%22countdown%22%0A%20%20%20%20%20%20%20%20v-html%3D%22%0A%20%20%20%20%20%20%20%20%20%20count.format('%5B%3Cspan%3E%5DHH%5B%3C%2Fspan%3E%5D%20%E6%97%B6%20%5B%3Cspan%3E%5Dmm%5B%3C%2Fspan%3E%5D%20%E5%88%86%20%5B%3Cspan%3E%5Dss%5B%3C%2Fspan%3E%5D%20%E7%A7%92')%0A%20%20%20%20%20%20%20%20%22%0A%20%20%20%20%20%20%3E%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('D%20%E5%A4%A9%20HH%20%E6%97%B6%20mm%20%E5%88%86%20ss%20%E7%A7%92')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('DD%20%3A%20HH%20%3A%20mm%20%3A%20ss')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('HH-mm-ss')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%20%20%3Cdiv%20class%3D%22flex%20m-1%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22w-36%22%3E%E4%BD%BF%E7%94%A8%E5%8F%96%E5%80%BC%E6%96%B9%E6%B3%95%EF%BC%9A%3C%2Fdiv%3E%0A%20%20%20%20%3Cdiv%20class%3D%22countdown%22%3E%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.hours()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E6%97%B6%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.minutes()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E5%88%86%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.seconds()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E7%A7%92%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.milliseconds()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Ftemplate%3E",component:"CodePreview"},{code:as(()=>[Ms]),default:as(()=>[is($s)]),_:1}),js]))}});export{xs as __pageData,Ts as default}; +`),s("span",{class:"line"},[s("span",{style:{"--shiki-light":"#24292E","--shiki-dark":"#E1E4E8"}},"")])])]),s("div",{class:"line-numbers-wrapper","aria-hidden":"true"},[s("span",{class:"line-number"},"1"),s("br"),s("span",{class:"line-number"},"2"),s("br"),s("span",{class:"line-number"},"3"),s("br"),s("span",{class:"line-number"},"4"),s("br"),s("span",{class:"line-number"},"5"),s("br"),s("span",{class:"line-number"},"6"),s("br"),s("span",{class:"line-number"},"7"),s("br"),s("span",{class:"line-number"},"8"),s("br"),s("span",{class:"line-number"},"9"),s("br"),s("span",{class:"line-number"},"10"),s("br"),s("span",{class:"line-number"},"11"),s("br"),s("span",{class:"line-number"},"12"),s("br"),s("span",{class:"line-number"},"13"),s("br"),s("span",{class:"line-number"},"14"),s("br"),s("span",{class:"line-number"},"15"),s("br"),s("span",{class:"line-number"},"16"),s("br"),s("span",{class:"line-number"},"17"),s("br"),s("span",{class:"line-number"},"18"),s("br"),s("span",{class:"line-number"},"19"),s("br"),s("span",{class:"line-number"},"20"),s("br"),s("span",{class:"line-number"},"21"),s("br"),s("span",{class:"line-number"},"22"),s("br"),s("span",{class:"line-number"},"23"),s("br"),s("span",{class:"line-number"},"24"),s("br"),s("span",{class:"line-number"},"25"),s("br"),s("span",{class:"line-number"},"26"),s("br"),s("span",{class:"line-number"},"27"),s("br"),s("span",{class:"line-number"},"28"),s("br"),s("span",{class:"line-number"},"29"),s("br"),s("span",{class:"line-number"},"30"),s("br"),s("span",{class:"line-number"},"31"),s("br"),s("span",{class:"line-number"},"32"),s("br"),s("span",{class:"line-number"},"33"),s("br"),s("span",{class:"line-number"},"34"),s("br"),s("span",{class:"line-number"},"35"),s("br"),s("span",{class:"line-number"},"36"),s("br"),s("span",{class:"line-number"},"37"),s("br"),s("span",{class:"line-number"},"38"),s("br"),s("span",{class:"line-number"},"39"),s("br"),s("span",{class:"line-number"},"40"),s("br"),s("span",{class:"line-number"},"41"),s("br"),s("span",{class:"line-number"},"42"),s("br"),s("span",{class:"line-number"},"43"),s("br"),s("span",{class:"line-number"},"44"),s("br"),s("span",{class:"line-number"},"45"),s("br"),s("span",{class:"line-number"},"46"),s("br"),s("span",{class:"line-number"},"47"),s("br"),s("span",{class:"line-number"},"48"),s("br"),s("span",{class:"line-number"},"49"),s("br"),s("span",{class:"line-number"},"50"),s("br"),s("span",{class:"line-number"},"51"),s("br"),s("span",{class:"line-number"},"52"),s("br"),s("span",{class:"line-number"},"53"),s("br"),s("span",{class:"line-number"},"54"),s("br"),s("span",{class:"line-number"},"55"),s("br"),s("span",{class:"line-number"},"56"),s("br"),s("span",{class:"line-number"},"57"),s("br"),s("span",{class:"line-number"},"58"),s("br"),s("span",{class:"line-number"},"59"),s("br"),s("span",{class:"line-number"},"60"),s("br"),s("span",{class:"line-number"},"61"),s("br"),s("span",{class:"line-number"},"62"),s("br")])],-1),js=hs("",6),xs=JSON.parse('{"title":"Day.js 使用技巧","description":"","frontmatter":{},"headers":[],"relativePath":"workflow/library/dayjs.md","filePath":"workflow/library/dayjs.md","lastUpdated":1702913488000}'),Os={name:"workflow/library/dayjs.md"},Ts=Object.assign(Os,{setup(M){return(U,m)=>(ns(),ts("div",null,[_s,is(gs(rs),{lang:"vue",meta:"preview",code:"%3Cscript%20setup%3E%0Aimport%20%7B%20ref%2C%20onMounted%2C%20onUnmounted%20%7D%20from%20'vue'%0Aimport%20dayjs%20from%20'dayjs'%0Aimport%20duration%20from%20'dayjs%2Fplugin%2Fduration'%0A%0Adayjs.extend(duration)%0A%0Aconst%20timer%20%3D%20ref(null)%0Aconst%20count%20%3D%20ref(dayjs.duration(0))%0A%0A%2F%2F%20%E8%AE%A1%E7%AE%97%E5%80%92%E8%AE%A1%E6%97%B6%E7%9A%84%E6%97%B6%E9%97%B4%E5%B7%AE%0Aconst%20countdown%20%3D%20()%20%3D%3E%20%7B%0A%20%20const%20now%20%3D%20dayjs()%0A%20%20const%20target%20%3D%20dayjs().endOf('D')%0A%20%20const%20diff%20%3D%20target.diff(now)%0A%0A%20%20if%20(diff%20%3C%3D%200)%20%7B%0A%20%20%20%20cancelAnimationFrame(timer.value)%0A%20%20%20%20return%0A%20%20%7D%0A%0A%20%20count.value%20%3D%20dayjs.duration(diff)%0A%20%20timer.value%20%3D%20requestAnimationFrame(countdown)%0A%7D%0A%0AonMounted(()%20%3D%3E%20%7B%0A%20%20timer.value%20%3D%20requestAnimationFrame(countdown)%0A%7D)%0A%0AonUnmounted(()%20%3D%3E%20%7B%0A%20%20cancelAnimationFrame(timer.value)%0A%7D)%0A%3C%2Fscript%3E%0A%0A%3Ctemplate%3E%0A%20%20%3Cdiv%20class%3D%22flex%20m-1%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22w-36%22%3E%E4%BD%BF%E7%94%A8%20format%20%E6%96%B9%E6%B3%95%EF%BC%9A%3C%2Fdiv%3E%0A%20%20%20%20%3Cdiv%20class%3D%22flex-1%22%3E%0A%20%20%20%20%20%20%3Cdiv%0A%20%20%20%20%20%20%20%20class%3D%22countdown%22%0A%20%20%20%20%20%20%20%20v-html%3D%22%0A%20%20%20%20%20%20%20%20%20%20count.format('%5B%3Cspan%3E%5DHH%5B%3C%2Fspan%3E%5D%20%E6%97%B6%20%5B%3Cspan%3E%5Dmm%5B%3C%2Fspan%3E%5D%20%E5%88%86%20%5B%3Cspan%3E%5Dss%5B%3C%2Fspan%3E%5D%20%E7%A7%92')%0A%20%20%20%20%20%20%20%20%22%0A%20%20%20%20%20%20%3E%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('D%20%E5%A4%A9%20HH%20%E6%97%B6%20mm%20%E5%88%86%20ss%20%E7%A7%92')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('DD%20%3A%20HH%20%3A%20mm%20%3A%20ss')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%20%20%3Cdiv%20class%3D%22mt-1%22%3E%7B%7B%20count.format('HH-mm-ss')%20%7D%7D%3C%2Fdiv%3E%0A%20%20%20%20%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%20%20%3Cdiv%20class%3D%22flex%20m-1%22%3E%0A%20%20%20%20%3Cdiv%20class%3D%22w-36%22%3E%E4%BD%BF%E7%94%A8%E5%8F%96%E5%80%BC%E6%96%B9%E6%B3%95%EF%BC%9A%3C%2Fdiv%3E%0A%20%20%20%20%3Cdiv%20class%3D%22countdown%22%3E%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.hours()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E6%97%B6%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.minutes()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E5%88%86%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.seconds()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%20%20%E7%A7%92%0A%20%20%20%20%20%20%3Cspan%3E%7B%7B%20count.milliseconds()%20%7D%7D%3C%2Fspan%3E%0A%20%20%20%20%3C%2Fdiv%3E%0A%20%20%3C%2Fdiv%3E%0A%3C%2Ftemplate%3E",component:"CodePreview"},{code:as(()=>[Ms]),default:as(()=>[is($s)]),_:1}),js]))}});export{xs as __pageData,Ts as default}; diff --git a/assets/workflow_terminal_zsh.md.a2lFEvdG.js b/assets/workflow_terminal_zsh.md.DtxqY7k0.js similarity index 98% rename from assets/workflow_terminal_zsh.md.a2lFEvdG.js rename to assets/workflow_terminal_zsh.md.DtxqY7k0.js index c47efe04..a8095111 100644 --- a/assets/workflow_terminal_zsh.md.a2lFEvdG.js +++ b/assets/workflow_terminal_zsh.md.DtxqY7k0.js @@ -31,7 +31,7 @@ import{_ as s,h as i,o as a,aa as n}from"./chunks/framework.C-tu2utv.js";const F plugins=(其他插件 z) # 使配置生效 -source ~/.zshrc

z | Github

fast-syntax-highlighting

终端语法高亮显示

安装

sh
# 在 ~/.zshrc 中配置
+source ~/.zshrc

z | Github

fast-syntax-highlighting

终端语法高亮显示

安装

sh
# 在 ~/.zshrc 中配置
 zinit light zdharma-continuum/fast-syntax-highlighting
 
 # 使配置生效
@@ -42,7 +42,7 @@ import{_ as s,h as i,o as a,aa as n}from"./chunks/framework.C-tu2utv.js";const F
 plugins=(其他插件 fast-syntax-highlighting)
 
 # 使配置生效
-source ~/.zshrc

Fast Syntax Highlighting | Github

zsh-autosuggestions

根据您的历史记录和完成情况建议您键入的命令

安装

sh
# 在 ~/.zshrc 中配置
+source ~/.zshrc

Fast Syntax Highlighting | Github

zsh-autosuggestions

根据您的历史记录和完成情况建议您键入的命令

安装

sh
# 在 ~/.zshrc 中配置
 zinit ice lucid wait="0" atload="_zsh_autosuggest_start"
 zinit light zsh-users/zsh-autosuggestions
 
@@ -54,7 +54,7 @@ import{_ as s,h as i,o as a,aa as n}from"./chunks/framework.C-tu2utv.js";const F
 plugins=(其他插件 zsh-autosuggestions)
 
 # 使配置生效
-source ~/.zshrc

zsh-autosuggestions | Github

zsh 主题

powerlevel10k

安装

sh
# 在 ~/.zshrc 中配置
+source ~/.zshrc

zsh-autosuggestions | Github

zsh 主题

powerlevel10k

安装

sh
# 在 ~/.zshrc 中配置
 zinit ice depth=1
 zinit light romkatv/powerlevel10k
 
@@ -72,7 +72,7 @@ import{_ as s,h as i,o as a,aa as n}from"./chunks/framework.C-tu2utv.js";const F
 # 比如显示当前使用的 node 版本
 
 # 使配置生效
-source ~/.zshrc

常用配置

具体可参考 —— 茂茂的 zsh 配置文件

sh
#--------------------------------------------------#
+source ~/.zshrc

常用配置

具体可参考 —— 茂茂的 zsh 配置文件

sh
#--------------------------------------------------#
 # 加载 p10k 主题
 #--------------------------------------------------#
 zinit ice depth=1
diff --git a/assets/workflow_terminal_zsh.md.a2lFEvdG.lean.js b/assets/workflow_terminal_zsh.md.DtxqY7k0.lean.js
similarity index 100%
rename from assets/workflow_terminal_zsh.md.a2lFEvdG.lean.js
rename to assets/workflow_terminal_zsh.md.DtxqY7k0.lean.js
diff --git a/daily-notes/index.html b/daily-notes/index.html
index 5b0831f0..939ab0bb 100644
--- a/daily-notes/index.html
+++ b/daily-notes/index.html
@@ -28,7 +28,7 @@
   
   
     
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

Daily Notes 日常笔记

日常笔记记录(零零散散啥都记系列)

新写一篇小笔记

共计 46 篇(上次更新: 2024-06-20)

2024 年 (共计 4 篇)

  1. 2024-06-20 —— 漫画 APP 资源汇总

  2. 2024-05-24 —— 在 GitHub Actions 中触发其他仓库的 Actions

  3. 2024-05-20 —— 判断用户为移动端设备的若干种方式

  4. 2024-04-16 —— 浏览器的自动播放策略

2023 年 (共计 9 篇)

  1. 2023-12-13 —— 使用 shell 脚本复制项目信息到剪切板

  2. 2023-09-16 —— 使用 rollup 打包用户脚本(user script)

  3. 2023-05-21 —— 修改 node_modules 中的依赖(打补丁)

  4. 2023-05-18 —— 获取软件内置浏览器的 User-Agent

  5. 2023-03-12 —— VitePress 生成站点地图

  6. 2023-02-28 —— 使用 VitePress 打造个人前端导航网站

  7. 2023-02-20 —— 从 VuePress 迁移至 VitePress

  8. 2023-02-10 —— 不使用 JavaScript 来隐藏元素的若干方法

  9. 2023-01-06 —— 使用 shell 脚本检查并配置 git user 信息

2022 年 (共计 8 篇)

  1. 2022-12-28 —— 搭建青龙定时任务管理面板

  2. 2022-12-19 —— ShadowSocks PAC 用户自定规则

  3. 2022-10-28 —— Next.js 搭建官网踩坑小记

  4. 2022-10-19 —— 修复谷歌翻译失效

  5. 2022-09-13 —— CSS 伪类选择器中的表达式(an+b)

  6. 2022-08-16 —— 在 Github Actions 环境变量中传递数组或对象

  7. 2022-03-07 —— 常用搜索技巧

  8. 2022-01-13 —— Canvas 绘制带圆角的矩形图

2021 年 (共计 10 篇)

  1. 2021-12-16 —— Less 循环遍历和踩坑

  2. 2021-11-18 —— .npmrc 学习笔记

  3. 2021-11-09 —— Flex 语法和计算规则

  4. 2021-10-17 —— Plop 实战笔记

  5. 2021-08-19 —— 解决 Github Support for password

  6. 2021-05-31 —— 使用 npm 脚本钩子

  7. 2021-04-15 —— Webpack 打包优化(CRA 项目)

  8. 2021-01-22 —— Mac 终端小技巧

  9. 2021-01-14 —— 在 vue-cli 中使用 tailwindcss

  10. 2021-01-12 —— 修改 DNS 解决 Github 资源加载失败

2020 年 (共计 15 篇)

  1. 2020-11-27 —— CRA 接入 react-dev-inspector

  2. 2020-11-10 —— Webpack 性能分析

  3. 2020-10-22 —— puppeteer 学习笔记

  4. 2020-09-30 —— 使用 URLSearchParams 解析 URL 的查询字符串

  5. 2020-08-04 —— 获取当前 git 分支

  6. 2020-07-20 —— 语义化版本控制

  7. 2020-07-04 —— package.json 相关知识

  8. 2020-06-17 —— 使用 husky、lint-staged、commitlint 构建前端工作流

  9. 2020-06-15 —— 使用 jsdelivr 加速 Github 仓库资源

  10. 2020-06-06 —— 在项目中使用 ESLint 和 Prettier

  11. 2020-05-21 —— Tree-Shaking 相关笔记

  12. 2020-05-15 —— 使用 SVG 做动画

  13. 2020-04-30 —— 修改 CRA 的默认配置

  14. 2020-04-29 —— CSS 函数

  15. 2020-04-28 —— 使用 JS 开发命令行程序

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/daily-notes/issue-1.html b/daily-notes/issue-1.html index 1091a259..3c8e8c0b 100644 --- a/daily-notes/issue-1.html +++ b/daily-notes/issue-1.html @@ -107,7 +107,7 @@ log(chalk.blue('正在运行: npm run ' + env)) shell.exec('npm run ' + env) })

image

相关库

具体 api 可以查看对应库

  • Inquirer.js 交互式命令行工具
  • chalk 修改控制台内容输出的样式
  • shelljsUnix ShellNode.js API 层的轻量级实现,可以很方便的调用系统命令
  • commander.js 编写指令和处理命令行

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/daily-notes/issue-10.html b/daily-notes/issue-10.html index c9698ea8..677037c5 100644 --- a/daily-notes/issue-10.html +++ b/daily-notes/issue-10.html @@ -43,7 +43,7 @@ # 指定版本 npm run release -- --release-as x.y.z

相关资料

语义化版本 2.0.0语义版本控制程序 semver

- + \ No newline at end of file diff --git a/daily-notes/issue-11.html b/daily-notes/issue-11.html index 27ee6af6..390a0be6 100644 --- a/daily-notes/issue-11.html +++ b/daily-notes/issue-11.html @@ -41,7 +41,7 @@ encoding: 'utf8' }) .trim()

用途

可以根据分支名在 webpack 编译时做处理(如: 线上环境打包只允许在 master 分支)

- + \ No newline at end of file diff --git a/daily-notes/issue-12.html b/daily-notes/issue-12.html index b36a6823..06a5621c 100644 --- a/daily-notes/issue-12.html +++ b/daily-notes/issue-12.html @@ -84,7 +84,7 @@ console.log(key, value) }

冷知识

query 上的 "" key

js
const searchParams = new URLSearchParams('?=maomao')
 searchParams.get('') // "maomao"

MDN 详细介绍点这里

相关 polyfill

core-js@2.x 未包含 URLSearchParams

- + \ No newline at end of file diff --git a/daily-notes/issue-13.html b/daily-notes/issue-13.html index 80d5b962..3cd93f45 100644 --- a/daily-notes/issue-13.html +++ b/daily-notes/issue-13.html @@ -80,7 +80,7 @@ console.log('error', error) } })()

相关资料

Puppeteer GithubPuppeteer 中文文档

- + \ No newline at end of file diff --git a/daily-notes/issue-14.html b/daily-notes/issue-14.html index 5c8e5a4d..d8b9da02 100644 --- a/daily-notes/issue-14.html +++ b/daily-notes/issue-14.html @@ -59,7 +59,7 @@ config.plugin('webpack-bundle-analyzer').use(BundleAnalyzerPlugin) } } - + \ No newline at end of file diff --git a/daily-notes/issue-15.html b/daily-notes/issue-15.html index 6d515da2..7755b36b 100644 --- a/daily-notes/issue-15.html +++ b/daily-notes/issue-15.html @@ -73,7 +73,7 @@ </InspectorWrapper>, document.getElementById('root') )

use-in-react

vscode 配置

  1. 打开 vscode
  2. 使用 command + shift + p (windows: ctrl + shift + p)
  3. 搜索 code
  4. 选择 Shell Command: Install 'code' command in PATH

效果图

效果图 - + \ No newline at end of file diff --git a/daily-notes/issue-16.html b/daily-notes/issue-16.html index a53c79a2..dc12bcf3 100644 --- a/daily-notes/issue-16.html +++ b/daily-notes/issue-16.html @@ -39,7 +39,7 @@ 199.232.96.133 avatars2.githubusercontent.com 199.232.96.133 avatars3.githubusercontent.com 199.232.96.133 avatars4.githubusercontent.com

199.232.96.133 为之前获取到的 IP 地址

推荐使用 Hosts 管理工具(SwitchHosts)修改

SwitchHosts

  1. Hosts 文件语法高亮
  2. 快速切换 Hosts
  3. 在线 Hosts 方案
  4. 系统托盘图标快速切换
  5. 支持 windows macOS linux

SwitchHosts | GitHub

在 SwitchHosts 中使用远程配置文件

  1. 打开 SwitchHosts
  2. 添加 hosts
  3. 选择类型为「远程」
  4. URL 为以下链接
    1. https://gitlab.com/ineo6/hosts/-/raw/master/hosts
    2. https://raw.hellogithub.com/hosts

刷新本地 DNS 缓存

macOS

sh
sudo killall -HUP mDNSResponder

Windows

sh
ipconfig /flushdns
- + \ No newline at end of file diff --git a/daily-notes/issue-17.html b/daily-notes/issue-17.html index 1b553391..7f4e5cc1 100644 --- a/daily-notes/issue-17.html +++ b/daily-notes/issue-17.html @@ -43,7 +43,7 @@ variants: {}, plugins: [] }

配置项说明

编辑器插件

Visual Studio Code - Tailwind CSS IntelliSense

  1. 语法提示
  2. 代码高亮
  3. Linting

解决 @apply 语法错误

@apply 改为单行列出,多次调用

WeChat17d0e6cf8604e0cf180fd509d286fe93

stackoverflow@apply 语法文档

post-css-7-compatibility-build

- + \ No newline at end of file diff --git a/daily-notes/issue-18.html b/daily-notes/issue-18.html index c2db89f3..713a9f6c 100644 --- a/daily-notes/issue-18.html +++ b/daily-notes/issue-18.html @@ -69,7 +69,7 @@ # 运行 unproxy 关闭代理 unproxy

常用快捷键

操作含义
Ctrl + P上一条命令
Ctrl + R搜索命令历史
Ctrl + L清屏
Ctrl + U清除当前行
Ctrl + W删除光标前面的一个单词
Ctrl + K删除光标后面的所有字符
Ctrl + A移动光标到行首
Ctrl + E移动光标到行尾
- + \ No newline at end of file diff --git a/daily-notes/issue-19.html b/daily-notes/issue-19.html index 57a3a7aa..6f689c79 100644 --- a/daily-notes/issue-19.html +++ b/daily-notes/issue-19.html @@ -81,7 +81,7 @@ } module.exports = override(customWebpackConfig)

优化图

相关资料

- + \ No newline at end of file diff --git a/daily-notes/issue-2.html b/daily-notes/issue-2.html index 86cbaaf6..b27a9750 100644 --- a/daily-notes/issue-2.html +++ b/daily-notes/issue-2.html @@ -69,7 +69,7 @@ <div class="min-calc">min calc</div> </body> </html>

demo

顺便总结了下 CSS 的函数

数学函数

颜色函数

背景图函数

动画缓动函数

其他函数

- + \ No newline at end of file diff --git a/daily-notes/issue-20.html b/daily-notes/issue-20.html index 7bfd77b3..504ed0a3 100644 --- a/daily-notes/issue-20.html +++ b/daily-notes/issue-20.html @@ -73,7 +73,7 @@ + "prestart": "node ./scripts/checkDependence.js" } }

使用效果

npm 相关命令说明

  1. npm view <name> 查询并返回指定包的所有信息
  2. npm view <name> versions 查询并返回指定包的所有版本信息(数组格式)
  3. npm view <name> version 查询并返回指定包的最新版本号

相关资料

npm-view

- + \ No newline at end of file diff --git a/daily-notes/issue-21.html b/daily-notes/issue-21.html index 1d9c3fae..55f97b63 100644 --- a/daily-notes/issue-21.html +++ b/daily-notes/issue-21.html @@ -37,7 +37,7 @@ git remote get-url origin # 修改项目源 git remote set-url origin SSH源地址

嫌修改项目源麻烦可以使用方案二

其他

Git 配置多个 SSH-Key

方案二配置 Personal Access Token

  1. 打开 https://github.com/settings/tokens/new

  2. 输入表单内容然后点击 Generate token 按钮生成

    1. Note: 备注说明
    2. Expiration: token 有效期,怕麻烦直接选永久
    3. Select scopes: 一般选 repo 权限
  3. 复制生成好的 token

  4. 打开钥匙串搜索 github.com

编辑钥匙串

- + \ No newline at end of file diff --git a/daily-notes/issue-22.html b/daily-notes/issue-22.html index fae12f0e..2e59edee 100644 --- a/daily-notes/issue-22.html +++ b/daily-notes/issue-22.html @@ -92,7 +92,7 @@ } }) }

其他

Plop 的字符串转化函数底层(相关源码)使用了 change-case

当我们在 JS 中需要使用时可以引入该库,与模板语法处理保持统一

相关案例地址

完整案例

https://github.com/maomao1996/plop-demo

- + \ No newline at end of file diff --git a/daily-notes/issue-23.html b/daily-notes/issue-23.html index bbada832..059a4382 100644 --- a/daily-notes/issue-23.html +++ b/daily-notes/issue-23.html @@ -141,7 +141,7 @@ <div class="right"></div> </div>

解答

分析代码可以得出,我们需要计算 flex 元素的收缩系数 flex-shrink

  1. 计算 flex 元素宽度总和: 300 + 400 + 500 = 1200px
  2. 计算溢出的宽度: 1200 - 1000 = 200px
  3. 计算总权重: 3 * 300 + 2 * 400 + 1 * 500 = 2200
  4. 计算 flex 元素实际宽度(width - 溢出宽度)
    1. left: 300 - 200 * 3 * 300 / 2200 = 218.19px
    2. center: 400 - 200 * 2 * 400 / 2200 = 327.28px
    3. right: 500 - 200 * 1 * 500 / 2200 = 454.55px

CodeSandbox: flex-shrink

flex-shrink 计算公式

sh
# 总权重计算: 各元素的宽度乘以其 flex-shrink 的总和
 元素宽度 - 溢出宽度 * flex-shrink 系数 * 元素宽度 / 总权重 = 实际宽度

相关资料

flex - CSS(层叠样式表)| MDN

详解 flex-grow 与 flex-shrink

flex 布局算法

深入理解 flex 布局以及计算

- + \ No newline at end of file diff --git a/daily-notes/issue-24.html b/daily-notes/issue-24.html index 49f2ecc3..f3fb5509 100644 --- a/daily-notes/issue-24.html +++ b/daily-notes/issue-24.html @@ -45,7 +45,7 @@ # 编辑配置文件 npm config edit [-g|--global]

配置说明

配置读取顺序

  1. 命令行
  2. 项目配置(项目根目录下的 npmrc 文件)
  3. 用户配置(用 npm config get userconfig 查看文件位置)
  4. 全局配置(用 npm config get prefix 查看文件位置)
  5. 默认配置

其他包管理器

yarn

踩坑点

yarn 1 中如果同时存在 .yarnrc.npmrc 文件时, .npmrc 优先级高于 .yarnrc 当我们使用 yarn 1 时项目只需要配置 .npmrc 文件

pnpm

pnpm 使用 .npmrc 文件

- + \ No newline at end of file diff --git a/daily-notes/issue-25.html b/daily-notes/issue-25.html index c5de7aa7..244aedb8 100644 --- a/daily-notes/issue-25.html +++ b/daily-notes/issue-25.html @@ -136,7 +136,7 @@ /* 这是测试用的块级注释 */ width: 100px; }

原因: Less 编译后的代码会保留块级注释(可以用来添加版权信息等,Sass 也是如此)

注释踩坑 — Playground

相关资料

- + \ No newline at end of file diff --git a/daily-notes/issue-26.html b/daily-notes/issue-26.html index a59116d0..dc8b2bcd 100644 --- a/daily-notes/issue-26.html +++ b/daily-notes/issue-26.html @@ -199,7 +199,7 @@ </script> </body> </html>

CodeSandbox: Canvas 绘制带圆角的矩形图 — globalCompositeOperation

这是李总教我的方案,再次膜拜一下大佬

相关资料

- + \ No newline at end of file diff --git a/daily-notes/issue-27.html b/daily-notes/issue-27.html index dbd1c859..db789e67 100644 --- a/daily-notes/issue-27.html +++ b/daily-notes/issue-27.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

常用搜索技巧

搜索引擎常用技巧

  • ""(双引号): 精确搜索

    • 搜索结果中必须包含关键字且顺序一致
      • "react学习指南": 搜索 react 学习指南
  • -(减号): 排除搜索

    • 搜索结果中排除减号后面的关键词,可以设置多个排除关键词
      • react学习指南 -csdn 搜索 react 学习指南并过滤掉带 csdn 的结果
  • *(星号): 模糊搜索

    • 用星号代替某个字来进行搜索
      • 搜*技巧 搜索结果中带有 搜*技巧的网页
  • OR(或): 组合搜索

    • 在各个关键词之间加上 OR 进行多个关键词搜索
      • vue OR react 搜索结果带有 vue 或者 react
  • ..(两个点): 数字范围搜索

    • 在某个数字范围内执行搜索
      • 手机2000..3000 搜索 2000 - 3000 的手机
  • site: 指定站点搜索

    • 在指定的网址对关键词进行搜索
      • github.com 前端学习资料 在 github 上搜索前端学习资料
  • filetype: 文件类型搜索

    • 对关键词进行指定文件类型的资源搜索
      • filetype:pdf JavaScript 搜索 JavaScript 的 pdf 文件
  • inurl: 页面 url 搜索

    • 在页面网址(url)对关键词进行搜索
      • inurl:javascript 搜索页面网址带有 javascript 的网页
  • intitle: 页面 title 搜索

    • 在页面标题(title)中对关键词进行搜索
      • intitle:react学习指南 搜索页面标题带有 react 学习指南的网页
  • intext: 页面内容搜索

    • 在页面正文对关键词进行搜索
      • intext:JavaScript 搜索页面正文带有 JavaScript 的网页

Google 搜索帮助

Github 常用技巧

常用 Github 搜索技巧

  • ""(双引号): 精确搜索

    • "react-admin"
      • 搜索结果中必须包含 react-admin
  • in: 限制搜索的范围

    • in:name [关键词]
      • 范围为仓库名称
    • in:description [关键词]
      • 范围为仓库描述
    • in:readme [关键词]
      • 范围为 readme
  • stars / forks: 限制搜索的 starfork

    • stars:>100
      • star 数大于 100
    • stars:>=100
      • star 数大于等于 100
    • stars:<100
      • star 数小于 100
    • stars:<=100
      • star 数小于等于 100
    • stars:100..200
      • star 数在 100 到 200 之间(闭区间)
  • language: 限制搜索的语言

    • language:html
  • created / pushed: 限制搜索的日期范围

    • created:>2020-01-01
      • 创建日期大于 2020-01-01
    • pushed:>2020-01-01
      • 更新日期大于 2020-01-01

Github 搜索帮助

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/daily-notes/issue-28.html b/daily-notes/issue-28.html index 68681ddc..5f66cf9f 100644 --- a/daily-notes/issue-28.html +++ b/daily-notes/issue-28.html @@ -56,7 +56,7 @@ run: | echo "$JSON_DATA" > ./config.json npm run install && node index.js

GitHub Actions 表达式语法

在 index.js 中引入 json 文件

js
const config = require('./config.json')
- + \ No newline at end of file diff --git a/daily-notes/issue-29.html b/daily-notes/issue-29.html index a5ba9b17..c4ecddb5 100644 --- a/daily-notes/issue-29.html +++ b/daily-notes/issue-29.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

CSS 伪类选择器中的表达式(an+b)

CSS 伪类选择器中的表达式有如下写法

  • 数字:直接匹配具体位置的元素
  • 关键字evenodd,根据奇偶去匹配
  • 表达式:根据 an + b 的结果去匹配

语法

只针对表达式场景的语法

:nth-child(an+b) 为例:该伪类选择器会先找到所有当前元素的兄弟元素,然后按照位置的先后顺序从 1 开始进行排序,再根据伪类选择器括号中的表达式 an+b 所计算出的值对元素进行匹配

  • an 中的 a 是一个整数,表示倍数
  • an 中的 n 是一个从 0 开始增长的自然数(即 n=0,1,2,3...)
  • b 是一个整数,表示偏移值(即初始位置)

示例

  • 0n+3:等同于 3,会匹配第三个元素
  • 1n+0:等同于 1n,会匹配所有元素
  • 2n+0:等同于 2n 和关键字(even),会匹配位置为 2、4、6、8...的元素,即偶数位元素
  • 2n+1:等同于关键字(odd),会匹配位置为 1、3、5、7... 的元素,即奇数位元素
  • 3n+4:会匹配位置为 4、7、10、13... 的元素
  • 4n-1:会匹配位置为 4-1、8-1、12-1... 的元素

反向匹配

an 的值为负数时为反向匹配,会匹配偏移值 b 之前的元素,并且 b 不能省略(此时最多匹配 b 个元素)

示例

  • -n+5:会匹配前五个元素
  • -2n+5:会匹配位置为 5-2*0、5-2*1、5-2*2(即位置为 5 3 1)的元素
  • -4n+10:会匹配位置为 10-4*0、10-4*1、10-4*2(即位置为 10 6 2)的元素

注意点

  • ab 都必须为整数
  • an 必须写在 b 的前面,不能写成 b+an
  • 元素位置从 1 开始,n 是从 0 开始增长的一个自然数
  • a 为负数时,b 不可省略

相关资料

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/daily-notes/issue-3.html b/daily-notes/issue-3.html index f2363469..17b843b0 100644 --- a/daily-notes/issue-3.html +++ b/daily-notes/issue-3.html @@ -83,7 +83,7 @@ }

再去 tsconfig.json 中使用 extends 配置引入

json
{
   "extends": "./paths.json"
 }

相关 issues

fb 真霸道,自己不用 alias,也不让用户搞

- + \ No newline at end of file diff --git a/daily-notes/issue-30.html b/daily-notes/issue-30.html index 09e8b4a6..b62a32e9 100644 --- a/daily-notes/issue-30.html +++ b/daily-notes/issue-30.html @@ -88,7 +88,7 @@ 216.58.209.174 translate.googleapis.com 216.58.214.14 translate.googleapis.com 216.58.220.142 translate.googleapis.com

谷歌翻译不能用的解决方案 | 划词翻译

- + \ No newline at end of file diff --git a/daily-notes/issue-31.html b/daily-notes/issue-31.html index 648860b2..c68e56eb 100644 --- a/daily-notes/issue-31.html +++ b/daily-notes/issue-31.html @@ -120,7 +120,7 @@ } module.exports = nextConfig - + \ No newline at end of file diff --git a/daily-notes/issue-33.html b/daily-notes/issue-33.html index 89c1e14a..52a88a87 100644 --- a/daily-notes/issue-33.html +++ b/daily-notes/issue-33.html @@ -44,7 +44,7 @@ ! npmtrends 相关 ||npmtrends.com ||npm-trends-proxy.uidotdev.workers.dev

注意点

- + \ No newline at end of file diff --git a/daily-notes/issue-34.html b/daily-notes/issue-34.html index 3d29a9a2..734b2e43 100644 --- a/daily-notes/issue-34.html +++ b/daily-notes/issue-34.html @@ -67,7 +67,7 @@ # 禁用两步登录 ql resettfa

常用的定时任务库

京东薅羊毛

集合库不用都拉取,拉一个就行,重复脚本太多容易黑号

faker2 faker3

京东集合库(推荐)

打开订阅管理 - 新建订阅

  1. 名称:ql repo https://git.metauniverse-cn.com/https://github.com/shufflewzc/faker3.git "jd_|jx_|gua_|jddj_|jdCookie" "activity|backUp" "^jd[^_]|USER|function|utils|sendNotify|ZooFaker_Necklace.js|JDJRValidator_|sign_graphics_validate|ql|JDSignValidator|magic|depend|h5sts" "main"
  2. 定时规则:5 0 * * *

faker2 和 faker3 选一个拉就行

KR

京东集合库

打开订阅管理 - 新建订阅

  1. 名称:ql repo https://github.com/KingRan/KR.git "jd_|jx_|jdCookie" "activity|backUp" "^jd[^_]|USER|utils|function|sign|ql|JDJR"
  2. 定时规则:30 * * * *
  3. 文件后缀:js ts py
  4. 代理:https://ghproxy.com/(可选)

KR

  1. 下载 alook 浏览器
  2. 打开京东触屏版 https://home.m.jd.com
  3. 通过手机验证码登录
  4. 点击 工具箱 — 开发者工具 — Cookies

QLScript2 通知库

上面的两个集合库均已内置,可以不用拉取

打开订阅管理 - 新建订阅

  1. 名称:ql repo https://github.com/ccwav/QLScript2.git "jd_" "NoUsed" "ql|sendNotify|utils|USER_AGENTS|jdCookie|JS_USER_AGENTS"
  2. 定时规则:0
  3. 代理:https://ghproxy.com/(可选)
使用教程

其他库

其他说明

- + \ No newline at end of file diff --git a/daily-notes/issue-35.html b/daily-notes/issue-35.html index 7dac2fdf..fac8d84d 100644 --- a/daily-notes/issue-35.html +++ b/daily-notes/issue-35.html @@ -81,7 +81,7 @@ fi fi fi

其他

其实配置 SSH Key 就没这么多事,但如果项目使用的是 https 源,则需要修改为 SSH 源,而且个人觉得 https 源方便,在浏览器上复制 url 就行

- + \ No newline at end of file diff --git a/daily-notes/issue-36.html b/daily-notes/issue-36.html index 87b1037e..3c040f08 100644 --- a/daily-notes/issue-36.html +++ b/daily-notes/issue-36.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

不使用 JavaScript 来隐藏元素的若干方法

这是一道经典面试题,也是最近帮朋友解决稿定设计的水印时想了各种方案,所以在此总结下(目前就 11 种)

隐藏元素的若干方法 Demo

1. width height

修改元素的 width 或者 height 属性(需要配合 overflow: hidden; 使用)

特点

  1. 不占据空间
  2. 不响应事件
  3. 支持动画

2. display: none

使元素不再显示,其对布局不会有影响

特点

  1. 不占据空间
  2. 不响应事件
  3. 不支持动画

3. visibility: hidden

隐藏元素,但是其他元素的布局不改变,相当于此元素变成透明,将其子元素设为 visibility: visible 时则该子元素依然可见

visibility - CSS:层叠样式表 | MDN

特点

  1. 占据空间
  2. 不响应事件
  3. 不支持动画

4. relative + 负 z-index

当元素之间重叠的时候 z-index 较大的元素会覆盖较小的元素在上层进行显示。

将元素的 z-index 属性设置为负值来达到隐藏元素的效果(实际是将元素放在了我们看不到的层叠上下文中)

z-index - CSS:层叠样式表 | MDN

创建层叠上下文

层叠上下文 - CSS:层叠样式表 | MDN

  • 根元素
  • position 不为 static
  • flexgrid 容器的子元素且 z-index 值不为 auto
  • opacity 不为 1
  • transform 不为 none
  • filter 不为 none
  • backdrop-filter 不为 none
  • clip-path 不为 none
  • mask / mask-image / mask-border 不为 none
  • mix-blend-mode 不为 normal
  • containlayoutpaint 或包含它们其中之一的合成值
  • 设置了 isolation: isolate
  • 设置了 -webkit-overflow-scrolling: touch
  • 设置了 will-change

特点

  1. 占据空间
  2. 不响应事件
  3. 不支持动画

5. absolute + 负 left

通过 position: absolute; left: -9999px 将元素移除可视区域来达到隐藏元素的效果

特点

  1. 不占据空间
  2. 不响应事件
  3. 支持动画

6. color + background

将元素的颜色值属性 color background-color 设置为 transparent 达到隐藏元素的效果

特点

  1. 占据空间
  2. 响应事件
  3. 支持动画

7. clip clip-path

clip-path 属性使用裁剪方式创建元素的可显示区域,区域内的部分显示,区域外的隐藏。可以使用 clip-path: circle(0) 来将元素隐藏

clip-path(CSS:层叠样式表)—— MDN

特点

  1. 占据空间
  2. 不响应事件
  3. 支持动画

8. transform

transform 属性允许你旋转、缩放、倾斜或平移指定元素。可以使用 transform: scale(0) 来将元素隐藏,还可以使用 rotateY(90deg) skew(90deg) 等属性达到隐藏元素效果

transform - CSS:层叠样式表 | MDN

特点

  1. 占据空间
  2. 不响应事件
  3. 支持动画

9. opacity: 0

opacity 属性用于指定一个元素的不透明度

opacity 的属性值不为 1 时,会把元素放置在一个新的层叠上下文中

一个元素和它包含的子元素都会具有和元素背景相同的透明度,哪怕这个元素和它的子元素有不同的 opacity 属性值

opacity - CSS:层叠样式表 | MDN

特点

  1. 占据空间
  2. 响应事件
  3. 支持动画

10. filter: opacity(0)

opacity() 转化图像的透明程度(已有的 opacity 属性很相似,不同之处在于通过 filter,一些浏览器为了提升性能会提供硬件加速)

filter - CSS:层叠样式表 | MDN

特点

  1. 占据空间
  2. 响应事件
  3. 支持动画

11. 全局属性 hidden

全局属性 hidden 是一个布尔属性,如果一个元素设置了这个属性,它就不会被显示(本质上是使用 display: none

hidden - HTML(超文本标记语言) | MDN

特点

  1. 不占据空间
  2. 不响应事件
  3. 不支持动画

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/daily-notes/issue-37.html b/daily-notes/issue-37.html index c700a720..3f3cf21b 100644 --- a/daily-notes/issue-37.html +++ b/daily-notes/issue-37.html @@ -186,7 +186,7 @@ 'nav-bar-title-after': () => h(Visitor) }) })

颜值对比

不得不说差的有点多

首页

VuePress 首页VitePress 首页

内容页

VuePress 内容页VitePress 内容页

VuePress 内容页VitePress 内容页

- + \ No newline at end of file diff --git a/daily-notes/issue-38.html b/daily-notes/issue-38.html index 4ddee469..1dd4d17d 100644 --- a/daily-notes/issue-38.html +++ b/daily-notes/issue-38.html @@ -377,7 +377,7 @@ layoutClass: m-nav-layout + outline: [2, 3, 4] ---

防止我们的站点标题被收录到页面目录下

页面目录

最终效果展示

最终效果展示最终效果展示

后续可能会添加的功能

- + \ No newline at end of file diff --git a/daily-notes/issue-39.html b/daily-notes/issue-39.html index 7a110de8..0975989e 100644 --- a/daily-notes/issue-39.html +++ b/daily-notes/issue-39.html @@ -55,7 +55,7 @@ await new Promise((r) => writeStream.on('finish', r)) } })

相关 issues

- + \ No newline at end of file diff --git a/daily-notes/issue-4.html b/daily-notes/issue-4.html index 4fb4e2bb..194cdd0c 100644 --- a/daily-notes/issue-4.html +++ b/daily-notes/issue-4.html @@ -87,7 +87,7 @@ </svg> </body> </html>

animate 相关语法介绍

只介绍用到的,其他的可以看下文的相关链接

相关资料

超级强大的 SVG SMIL animation 动画详解SVG 元素参考 | MDN

- + \ No newline at end of file diff --git a/daily-notes/issue-41.html b/daily-notes/issue-41.html index c31da4a3..ea949b5f 100644 --- a/daily-notes/issue-41.html +++ b/daily-notes/issue-41.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

获取软件内置浏览器的 User-Agent

有的时候我们需要获取软件内置浏览器的 User-Agent,以便于我们做一些特殊的处理

User-Agent

User-Agent(用户代理)是一个用于识别客户端(通常是网络浏览器)类型和版本的字符串。它是由客户端在向服务器发送请求时自动包含的头部信息之一

User-Agent 字符串提供了关于客户端应用程序、操作系统、设备和版本的信息,以便服务器可以根据这些信息提供适合客户端的响应内容。服务器可以根据 User-Agent 字符串来确定如何呈现网页、提供适当的样式和功能,或者根据客户端的能力做出其他定制化的处理

User-Agent - HTTP | MDN

获取 User-Agent

js
const userAgent = navigator.userAgent

解析 User-Agent

访问以下网站,在线解析 User-Agent

通过以下库,解析 User-Agent

以钉钉为例获取其内置浏览器的 User-Agent

AndroidiOS 版钉钉打开外部链接时,会调用钉钉内置浏览器打开,可以获取到钉钉内置浏览器的 User-Agent

但在 PC 版钉钉打开外部链接时,会调用默认浏览器打开,导致无法获取钉钉内置浏览器的 User-Agent 信息,这时我们可以通过钉钉的跳转协议去打开外部链接,这样就可以获取到钉钉内置浏览器的 User-Agent

在浏览器中打开以下链接,即可获取钉钉内置浏览器的 User-Agent

使用 User Agent String.Com 解析

sh
dingtalk://dingtalkclient/page/link?url=https%3A%2F%2Fwww.useragentstring.com&pc_slide=true

使用 UserAgentInfo 解析

sh
dingtalk://dingtalkclient/page/link?url=https%3A%2F%2Fwww.useragentinfo.com&pc_slide=true

钉钉内置浏览器的 User-Agent

sh
Mozilla/5.0 (Macintosh; Intel Mac OS X 12_6_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 DingTalk(7.0.10-macOS-28453097) nw Channel/201200 Architecture/x86_64

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/daily-notes/issue-42.html b/daily-notes/issue-42.html index 7508fd08..886ee751 100644 --- a/daily-notes/issue-42.html +++ b/daily-notes/issue-42.html @@ -41,7 +41,7 @@ # 4. 生成补丁 <pkg name> 是上一步修改的依赖包名称 npx patch-package <pkg name>

参考

- + \ No newline at end of file diff --git a/daily-notes/issue-43.html b/daily-notes/issue-43.html index 714fd585..f27607d3 100644 --- a/daily-notes/issue-43.html +++ b/daily-notes/issue-43.html @@ -131,7 +131,7 @@ }) ] })

也可以使用 rollup-plugin-userscript

其他说明

- + \ No newline at end of file diff --git a/daily-notes/issue-44.html b/daily-notes/issue-44.html index 70280539..a9b8e3e9 100644 --- a/daily-notes/issue-44.html +++ b/daily-notes/issue-44.html @@ -50,7 +50,7 @@ echo "\033[33m当前目录不存在 .git 配置\033[0m" fi }

使用效果

使用效果

如果只关心将项目名和分支名复制到剪贴板,可直接使用配置别名版本

- + \ No newline at end of file diff --git a/daily-notes/issue-45.html b/daily-notes/issue-45.html index 71cb1cd4..47286174 100644 --- a/daily-notes/issue-45.html +++ b/daily-notes/issue-45.html @@ -30,7 +30,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

浏览器的自动播放策略

最近有个项目被坑到了,正好记录一下

自动播放即网页加载完成后能否立即播放音视频

以 Chrome 为例(以下为自动播放策略)

  • 始终允许静音自动播放
  • 在以下情况下,允许带声音的自动播放
    • 用户已经在当前域进行了交互操作(点击触摸滑动等)
    • 用户将当前网站添加到移动设备上的主屏幕或在桌面上安装了 PWA
    • 在桌面设备上:用户的媒体互动指数超过一定阈值(意味着用户之前播放过有声视频)
  • iframe 会继承父级页面的自动播放策略(需要父窗口满足自动播放条件)

媒体互动指数

媒体互动指数 (MEI Media Engagement Index) 衡量的是个人在网站上观看媒体的倾向

Chrome 的方法是统计每个来源的访问次数与重要媒体播放事件的比率

  • 媒体(音频/视频)的用时必须超过 7 秒
  • 音频必须存在且已取消静音
  • 包含该视频的标签页处于有效状态
  • 视频的尺寸(以像素为单位)必须大于 200x140

MEI 是一个数字,可以在 about://media-engagement 中进行查看;其值越高,表示用户对该站点的媒体参与度越高

  • 媒体互动指数的计算规则不透明

  • 媒体互动指数的计算规则在不同的浏览器版本上可能会有差异

最佳实践

交互后播放

  1. 先尝试自动播放
  2. 自动播放失败后,引导用户进行交互
  3. 用户交互后再进行播放

一般会在视频区添加一个全局按钮,用户点击后触发交互操作,并自动播放

交互后播放声音

先静音播放,然后根据能否自动播放判断是否取消静音

  1. 能自动播放,取消静音
  2. 不能自动播放,引导用户进行交互操作后取消静音

关键点:通过 AudioContext 判断其上下文的状态

js
const ctx = new AudioContext();
 const canAutoPlay = ctx.state === 'running';
 ctx.close();

相关资料

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/daily-notes/issue-46.html b/daily-notes/issue-46.html index 0f824c6b..61d8dd30 100644 --- a/daily-notes/issue-46.html +++ b/daily-notes/issue-46.html @@ -66,7 +66,7 @@ }

判断是否支持触摸事件

maxTouchPoints 返回当前设备支持的最大同时触摸接触点数

js
function isTouchDevice() {
   return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
 }
- + \ No newline at end of file diff --git a/daily-notes/issue-47.html b/daily-notes/issue-47.html index 264e42da..396cdce6 100644 --- a/daily-notes/issue-47.html +++ b/daily-notes/issue-47.html @@ -57,7 +57,7 @@ - name: Checkout uses: actions/checkout@v3 # 添加其他步骤,如安装依赖、构建等

按照以上步骤配置后,每当源仓库满足触发条件时,目标仓库的构建和部署流程将自动启动

- + \ No newline at end of file diff --git a/daily-notes/issue-48.html b/daily-notes/issue-48.html index 34b048f5..7badc064 100644 --- a/daily-notes/issue-48.html +++ b/daily-notes/issue-48.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

漫画 APP 资源汇总

记录一些漫画 APP 和相关的图源插件

安卓漫画 APP

APK 版本说明

以 tachiyomiJ2K 举 🌰

  • tachiyomij2k-arm64-v8a-v1.7.4.apk: 64-bit ARM 架构的新版本安卓和平板设备
  • tachiyomij2k-armeabi-v7a-v1.7.4.apk: 32-bit ARM 架构的老版本安卓和平板设备
  • tachiyomij2k-v1.7.4.apk: 通用版本
  • tachiyomij2k-x86-v1.7.4.apk: 32 位 x86 架构的安卓平板电脑和模拟器
  • tachiyomij2k-x86_64-v1.7.4.apk: 64 位 x86 架构的安卓平板电脑和模拟器

推荐图源仓库

下载上面的 APK 安装后添加插件仓库即可使用(插件安装后需要信任才可使用)

相关项目

Yealico

Yealico 是 iOS 端看漫画、动漫和影视剧的神器

邀请码:66de08788bfc99a5ca6870b0533d8ac8

相关资料

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/daily-notes/issue-5.html b/daily-notes/issue-5.html index 3e74aad0..f7195b54 100644 --- a/daily-notes/issue-5.html +++ b/daily-notes/issue-5.html @@ -48,7 +48,7 @@ const get = 'get' api[get + '1']()

再次打包分析,发现 tree-shaking 失效了,get1 get2 get3 都还在代码里面

在线 Demo

结论

相关知识点

Tree-Shaking 相关学习资料

- + \ No newline at end of file diff --git a/daily-notes/issue-6.html b/daily-notes/issue-6.html index 0c589cde..1f077e0e 100644 --- a/daily-notes/issue-6.html +++ b/daily-notes/issue-6.html @@ -74,7 +74,7 @@ ] }
  1. .prettierignore

配置 Prettier 忽略文件

sh
package.json
 tsconfig.json

添加脚本命令

package.jsonscripts 配置项中写入 "fix": "prettier --write ./src"

相关资料

ESLint RulesPrettier Options

其他

使用 husky、lint-staged、commitlint 构建前端工作流

- + \ No newline at end of file diff --git a/daily-notes/issue-7.html b/daily-notes/issue-7.html index 20ca1e1e..af62bbd3 100644 --- a/daily-notes/issue-7.html +++ b/daily-notes/issue-7.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

使用 jsdelivr 加速 Github 仓库资源

当我们使用 Github 仓库资源时,会因为一些奇怪的原因而掉链子,但我们可以通过 jsdelivr 做 CDN 加速

jsdelivr 是一个免费的开源 CDN

使用方式

https://cdn.jsdelivr.net/gh/ Github 用户名/仓库名/资源路径

默认会访问 master 分支下的资源,可以通过 仓库名拼接 @ + release / commit / branch 来访问特定版本下的资源

例子

https://raw.githubusercontent.com/maomao1996/Vue-mmPlayer/master/screenshots/1.jpg

https://cdn.jsdelivr.net/gh/maomao1996/Vue-mmPlayer/screenshots/1.jpg

github 转 jsdelivr 链接 | 在线工具

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/daily-notes/issue-8.html b/daily-notes/issue-8.html index c85db6f1..1237b4e2 100644 --- a/daily-notes/issue-8.html +++ b/daily-notes/issue-8.html @@ -49,7 +49,7 @@ }
js
module.exports = {
   extends: ['@commitlint/config-conventional']
 }

@commitlint/config-conventional type 说明

type含义
feat新功能
fix修复 bug
docs修改文档
style代码格式修改
refactor重构(即不是新增功能,也不是修复 bug)
perf更改代码以提高性能
test增加测试
build构建过程或辅助工具的变动
ci修改项目持续集成流程
chore其他类型的提交
revert恢复上一次提交
- + \ No newline at end of file diff --git a/daily-notes/issue-9.html b/daily-notes/issue-9.html index 93334246..68be6f44 100644 --- a/daily-notes/issue-9.html +++ b/daily-notes/issue-9.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

package.json 相关知识

版本说明

字段说明
^1.0.0会匹配所有 1.x.x版本,保持一致 major version (大于等于当前版本,小于 2.0.0)
~1.0.0会匹配所有 1.0.x版本,保持一致 minor version (大于等于当前版本,小于 1.1.0)
1.x会根据 x 的位置来匹配对应规则

npm 包入口文件定义

字段说明

字段说明支持环境
main用于指定 npm 包的入口文件browser / node
module用于指定 es modules 规范的入口文件browser / node
browser用于指定 npm 包在 browser 环境下的入口文件browser

优先级说明

详细资料 - package.json 中 你还不清楚的 browser,module,main 字段优先级

流程图

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/efficiency/bookmark-scripts.html b/efficiency/bookmark-scripts.html index 20b36e70..6e49c8f6 100644 --- a/efficiency/bookmark-scripts.html +++ b/efficiency/bookmark-scripts.html @@ -37,7 +37,7 @@ document.querySelector('#column-left').style.display = document.querySelector('#column-left').style.display === 'none' ? 'block' : 'none' })()

切换 Telegram 侧边栏显隐

- + \ No newline at end of file diff --git a/efficiency/online-tools.html b/efficiency/online-tools.html index 49f73e61..ebb57727 100644 --- a/efficiency/online-tools.html +++ b/efficiency/online-tools.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

在线工具

开发常用

沙箱

正则

代码编译

JS 相关

Vue

CSS 预处理器

代码生成

CSS 相关

SVG 相关

CDN

图片处理

在线抠图

图片压缩

图片生成

作图工具

文件处理

  • 在线格式转换
    • CloudConvert 在线文件转换器,支持 200+ 种格式、支持自定义设置、图片可在线预览(英文界面)
    • Convertio 在线转换文件的简单工具,支持 300+ 种格式、支持自定义设置(最大 100M)
  • PDF Editor Free 在线编辑 PDF 文件

休闲娱乐

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/efficiency/software/browser.html b/efficiency/software/browser.html index a565d4a7..f1ac5ca9 100644 --- a/efficiency/software/browser.html +++ b/efficiency/software/browser.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

浏览器设置与扩展

扩展商店

体验优化

翻译

  • Relingo 识别网站中的生词并翻译(可根据自己的情况设置英语等级)、YouTube 支持双语字幕,生词高亮字幕
  • 沉浸式翻译 免费的又好用的沉浸式双语对照翻译
  • Saladict 沙拉查词 一款专业划词翻译扩展,为交叉阅读而生。涵盖中英日韩法德西语,支持复杂的划词操作、网页翻译、生词本与 PDF 浏览
  • 彩云小译 全文翻译(中英对照)
  • 划词翻译 划词翻译

开发常用

  • Vue.js devtools 用于调试 Vue.js 应用程序
  • React Developer Tools 用于调试 React 应用程序
  • Redux DevTools 用于调试应用程序 Redux 状态更改
  • WEB 前端助手(FeHelper) 包括字符串编解码、图片 base64 编码、代码压缩、美化、JSON 格式化、正则表达式、时间转换工具、二维码生成器、编码规范检测、页面性能检测、栅格检测、JS 运行效率分析
  • Lighthouse 网站性能测评工具
  • JSON Formatter JSON 格式化
  • 掘金 在新标签页展示聚合内容,包含前端、Android、iOS、后端、产品、设计六大频道,每个频道内都有一到多个内容源

GitHub 相关

油猴

油猴脚本推荐

其他工具

技巧

打开不安全网页

在当前页面任意地方点击,直接输入 thisisunsafe 后回车就能访问

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/efficiency/software/cross-platform.html b/efficiency/software/cross-platform.html index 4be0dec2..faa3a1c8 100644 --- a/efficiency/software/cross-platform.html +++ b/efficiency/software/cross-platform.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

多平台软件

效率神器 uTools

  1. 强大的插件化
  2. 多功能输入框,支持文本、截图、图片、文件、文件夹
  3. 自动识别 / 粘贴
  4. 全局快捷键
  5. 云端数据同步
  6. 支持 Windows、Mac、Linux

软件官网

下载神器 Motrix

  1. 界面清爽简洁
  2. 支持 BT 和磁力链任务
  3. 支持选择性下载 BT 部分文件
  4. 基于 Aria2
  5. 自动更新 Tracker 服务器列表

brew 安装

sh
brew install motrix

SwitchHosts

Hosts 管理工具

  1. Hosts 文件语法高亮
  2. 快速切换 Hosts
  3. 在线 Hosts 方案
  4. 系统托盘图标快速切换

brew 安装

sh
brew install --cask switchhosts

SwitchHosts | Github

QtScrcpy

通过 USB 或 TCP/IP 连接 Android 设备,并进行显示和控制

  1. 不需要 root 权限
  2. 最多支持 16 个安卓设备同时连接
  3. 支持自定义按键映射
  4. 可同时控制所有连接设备

QtScrcpy | Github

图床工具 PicGo

一个用于快速上传图片并获取图片 URL 链接的工具

  1. 支持 GitHub、七牛云、腾讯云、又拍云、阿里云 OSS、SM.MS V2、Imgur
  2. 支持拖拽图片上传
  3. 支持快捷键上传剪贴板里第一张图片
  4. 支持右键图片文件通过菜单上传
  5. 支持自定义复制到剪贴板的链接格式、
  6. 丰富的插件系统

Sourcetree

  1. 界面简洁、美观
  2. 简化 Git 日常操作,对新人友好易上手
  3. 支持 Git 工作流,规范开发流程
  4. 支持 Git 和 Mercurial 两种 VCS
  5. 支持自定义脚本执行

性能优化设置

  1. 打开 设置 => Diff
  2. 忽略文件模式 中添加 package-lock.json, yarn.lock

brew 安装

sh
brew install --cask sourcetree

软件官网

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/efficiency/software/mac.html b/efficiency/software/mac.html index ff9abec2..26457754 100644 --- a/efficiency/software/mac.html +++ b/efficiency/software/mac.html @@ -140,7 +140,7 @@ # 卸载 sudo wechattweak-cli --uninstall

WeChatTweak-macOS | Github

IINA

视频播放器

  1. 界面简洁、美观,契合 macOS 设计风格
  2. 功能强大,设置以播放体验为中心
  3. 支持鼠标和触控板手势
  4. 在线字幕、缩略图预览、画中画等

brew 安装

sh
brew install --cask iina

MacZip

专为 macOS 而设计的压缩软件

  1. 界面简洁、美观,完美兼容 Mojave
  2. 支持超过 20 种压缩格式
  3. 批量文件加密

软件官网

腾讯柠檬清理

  1. 界面简洁清新
  2. 支持垃圾清理、文件查重、软件卸载
  3. 支持微信、QQ、XCode、Sketch 深度扫描清理

软件官网

截图神器 IShot

  1. 区域截图、窗口截图、多窗口截图、延时截图、长截图、滚动截图
  2. 快速标注(矩形、圆形、横线、箭头、画笔、马赛克、文字标记、序号标签、局部高亮)
  3. 支持截图导圆角、阴影调节
  4. 贴图、取色

超级右键 iRightMouse

  1. 多种格式的右键新建文件
  2. 快速移动文件
  3. 常用目录设置
  4. 快速打开终端、vscode 等

翻译软件 Bob

  1. 支持划词、截图、输入翻译
  2. 支持翻译多开
  3. 自动识别语种
  4. 可自定义插件

菜单栏图标管理 Hidden Bar

  1. 简单易用、支持全局快捷键
  2. 免费开源、支持中文

brew 安装

sh
brew install --cask hiddenbar

音量管理 BackgroundMusic

  1. 背景音乐管理
  2. 设置各个应用程序的音量
  3. 录制系统音频

brew 安装

sh
brew install --cask background-music

BackgroundMusic | Github

窗口管理神器 Rectangle

比系统分屏更强大,支持快捷键分屏、支持三个及以上分屏

brew 安装

sh
brew install --cask rectangle

应用快捷启动神器 Thor Launcher

通过设定快捷键,快速在应用之间切换

快捷键提示 CheatSheet

长按 Command 即可查看当前应用的快捷键提示

显示器控制 MonitorControl

  1. 控制外接显示器的亮度和音量
  2. 支持键盘控制亮度和音量

brew 安装

sh
brew install --cask monitorcontrol

MonitorControl | Github

显示器设置 BetterDisplay

主要用于解决外接显示器不清晰问题(4k 以下),部分功能与 MonitorControl 重叠

  1. 解锁 HiDPI (Retina 显示)
  2. 自定义分辨率
  3. 创建虚拟显示器
  4. 创建显示器的画中画窗口
  5. 控制显示器的亮度和音量

brew 安装

sh
brew install --cask betterdisplay

操作方法 - 以 BetterDisplay v1.4.15 为例

  1. 下载 - 安装 - 打开
  2. 点击导航栏小图标
  3. 点击面板最下面的设置按钮
    1. 点击『Display
    2. 选择扩展显示器
    3. 勾选『Edit the system configuration of this display
    4. 添加自定义分辨率(可选)
      1. 勾选『『Add custom scaled resolutions
      2. 设置自己需要的分辨率(如 1600x900
    5. 修改 Default resolution 选项
      1. 勾选『Edit default resolution
      2. 设置自己需要的分辨率(如 1920x1080@60
  4. 保存并应用设置(设置完以后可关闭软件,不需要一直开着)

BetterDisplay | Github

剪贴板管理器 Maccy

  1. 免费开源、支持中文
  2. 简单易用、支持复制图片和文件
  3. 快速唤起(SHIFT (⇧) + COMMAND (⌘) + C
  4. 强大的历史记录管理(最多 999 条)
  5. 丰富的个性化配置(可以忽略指定应用)

brew 安装

sh
brew install --cask maccy

录屏神器 Kap

  1. 免费开源
  2. 支持全屏录制、自定义录制区域、只录某个窗口
  3. 支持显示鼠标点击位置
  4. 支持导出为 GIF、MP4、WebM 或 APNG
  5. 支持插件扩展

brew 安装

sh
brew install --cask kap

视频转 GIF Gifski

将视频转换为高质量的 GIF

  1. 免费开源
  2. 操作简单
  3. 支持视频剪辑
  4. 支持调整分辨率、FPS、质量、倍速、播放次数等参数

其他版本 —— 聚合官网

命令行版本可通过 brew 安装

sh
brew install gifski
- + \ No newline at end of file diff --git a/efficiency/software/vscode.html b/efficiency/software/vscode.html index 0f39f6f8..b0283e95 100644 --- a/efficiency/software/vscode.html +++ b/efficiency/software/vscode.html @@ -366,7 +366,7 @@ "description": "markdown 行内代码" } }

其他

扩展插件开发

- + \ No newline at end of file diff --git a/efficiency/software/webstorm.html b/efficiency/software/webstorm.html index 16aebfd4..2554f29a 100644 --- a/efficiency/software/webstorm.html +++ b/efficiency/software/webstorm.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

WebStorm 配置

获取许可证

使用开源项目免费申请 JetBrains 全家桶开源许可证

常用插件

  1. 进入「设置 - Plugins/插件 - Marketplace
  2. 复制插件名后进行搜索安装
  • Chinese ​(Simplified)​ Language Pack / 中文语言包 编辑器汉化
  • GitHub Copilot 代码智能提示
  • GitToolBox 增强内置的 Git 功能(猪哥推荐)
  • .env files support .env 文件键值字符串高亮
  • .ignore .env 提示哪些文件可以被 ignore
  • CodeGlance Pro 在侧边栏显示代码缩略图(猪哥推荐)
  • WakaTime 统计代码编写时间 (WakaTime 官网)

插件市场

主题美化

主题插件

  • Atom Material Icons 图标美化
  • Atom OneDark Theme Atom OneDark 主题
  • Material Theme UI Material Design 主题
  • One Dark theme 暗黑风格主题

配色方案

自定义背景图

  1. 进入 设置 - 外观和行为 - Appearance
  2. 点击 BACKGROUND IMAGE

汉化

老版本

  • 方案一
    • 进入 文件 - 设置 - Plugins - Marketplace
    • 搜索 Chinese ​(Simplified)​ Language Pack EAP 下载安装
  • 方案二
  • 方案三
    • 查看本地 WebStorm 版本
      • 进入 帮助 - 关于
      • 找到 Build #WS- 后面的数字
    • 打开 Chinese ​(Simplified)​ Language Pack EAP
    • 点击 Versions 选择对应编辑器再搜索对应版本下载(当找不到一样的版本时,可以看列表的第二栏版本范围,找包含你编辑器的版本下载就行)
    • 通过磁盘安装刚下载的文件

磁盘安装

配置 Prettier 保存格式化

新版本

  1. 进入 WebStorm - Settings - 框架和语言 - JavaScript - Prettier
  2. 勾选 执行“重新格式化代码”操作时(R)保存时(S)
  3. 进入 WebStorm - Settings - 工具 - 保存时的操作
  4. 勾选 重新格式化代码运行 Prettier

老版本可使用 File Watchers 方案

  1. 进入 文件 - 设置 - 工具 - File Watchers
  2. 点击 + 选择 Prettier
  3. File type 修改为你需要的文件类型,通用可选 Any

webpack 项目识别 alias

  1. 进入 文件 - 设置 - 框架和语言 - JavaScript - Webpack
  2. webpack 配置文件地址修改为对应地址
    1. vue-cli2.x: 项目地址 + \build\webpack.base.conf.js
    2. vue-cli3.x 及以上: 项目地址 + \node_modules\@vue\cli-service\webpack.config.js

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/efficiency/software/windows.html b/efficiency/software/windows.html index f7b1d3c7..089ef91a 100644 --- a/efficiency/software/windows.html +++ b/efficiency/software/windows.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

Windows 平台

激活工具

激活神器 Microsoft-Activation-Scripts

使用 HWID / Ohook / KMS38 / Online KMS 激活方法的 Windows 和 Office 激活器

使用方法

  1. 右键单击 Windows 开始菜单,然后选择 PowerShell
  2. 复制并粘贴下面的代码,然后按 Enter
sh
irm https://get.activated.win | iex

Office Tool Plus

一个用于部署、激活 Office、Visio、Project 的强大工具

终端神器 Cmder

  1. 便携,解压即可用
  2. 支持子窗口
  3. 自带 gitls 等命令
  4. 自定义配置项

搜索神器 Everything

  1. Windows 平台最快的文件搜索软件
  2. 支持整词、路经匹配搜索
  3. 支持正则表达式搜索

软件官网

效率神器 Wox

  1. 可以搜索安装的程序,支持中文拼音模糊搜索
  2. 搜索浏览器书签
  3. 可以调用 Everything 进行快速全局搜索
  4. 网页搜索功能
  5. 支持插件扩展
  6. 支持自定义主题

视频播放神器 PotPlayer

  1. 界面简洁,可自定义皮肤
  2. 功能强大,设置以播放体验为中心
  3. 纯粹的本地播放器
  4. 视频/音频格式支持非常全面

压缩/解压神器 bandizip

  1. 界面简洁、清新
  2. 集 压缩/解压/浏览/编辑 为一体
  3. 支持处理乱码
  4. 支持通过对文件完整性的检查来判断压缩包是否受损
  • 最新版存在广告,需要无广告的可下载 6.x 版本

软件官网

音量管理神器 EarTrumpet

  1. 基于 Microsoft Store 托管的 UWP 应用程序,可自动更新,性能影响小
  2. 默认播放设备管理
  3. 支持明 / 暗模式和所有强调色
  4. 支持快捷键设置
  5. 在播放设备之间移动应用

看图神器 Honeyview

  1. 支持众多图片格式,如 PSD 文件预览
  2. 对图像格式进行批量转换和调整
  3. 可以显示包括 GPS 信息在内的 JPEG 格式的 EXIF 信息

软件官网

壁纸神器 Wallpaper Engine

  1. 内存占用低
  2. 支持视频、网页、2D、3D、GIF 等类型壁纸
  3. 强大的创意工坊拥有海量壁纸可供选择

系统优化工具 Dism++

  1. 基于 Windows 系统原生功能 Dism 开发的增强工具
  2. 体积小,解压即用,方便快捷
  3. 集成空间清理、系统管理/优化、热备份还原等功能于一体

隐私优化 WPD

  1. 隐私管理
  2. 预装应用卸载
  3. 绿色免费、支持中文

软件官网

微信/QQ/TIM 防撤回补丁

  1. 支持微信/QQ/TIM 防撤回
  2. 支持微信多开

微信/QQ/TIM 防撤回补丁 | Github

微信清理工具 CleanMyWechat

  1. 自动识别微信账号,支持用户选择自定义路径
  2. 同时管理多个账号,保留配置参数,打开即用
  3. 自由设置想要删除的文件类型,包括图片类缓存、文件、图片、视频
  4. 自由设置需要删除的文件的距离时间,默认 365 天
  5. 删除后的文件放置在回收站中,检查后自行清空,防止删错需要的文件

CleanMyWechat | Github

任务栏透明 TranslucentTB

  1. 支持亚克力、模糊、透明、主题色、不透明效果
  2. 支持自定义颜色
  3. 只支持 Windows 10

查重神器 Duplicate Cleaner

  1. 快速查找重复文件、支持多目录
  2. 灵活的搜索设置
  3. 在详细列表中查看所有文件信息
  4. 删除重复文件至回收站
  5. 移动重复文件到新位置

电子书格式转换器 NeatConverter

  1. 完全免费,简单易用
  2. 支持 ePub、Azw3、Mobi、Doc、PDF、TXT 文件的互转

软件官网

系统增强工具 PowerToys

  • Color Picker 颜色选择器

    • 默认启动快捷键: Win + Shift + C
  • FancyZones 窗口管理器

    • 自定义窗口布局
    • 默认启动快捷键: Win + ~
  • File Explorer Add-ons 文件资源管理器

    • 快速预览 SVG 和 Markdown 文件
  • Image Resizer 图像大小调整器

    • 修改图片大小、旋转方向、图片格式
    • 支持批量修改
  • Keyboard Manager 键盘管理器

    • 修改键位映射
  • PowerRename 批量重命名工具

    • 添加文件名前缀、后缀
    • 支持搜索、替换、正则表达式匹配
    • 排除指定的文件、文件夹
    • 预览重命名结果
  • PowerToys Run 快速启动程序

    • 搜索应用程序、文件夹或文件
    • 使用计算器执行简单计算
    • 默认启动快捷键: Alt + Space
  • PowerToys | Github

  • 安装文档

网速监控悬浮窗 TrafficMonitor

  1. 显示当前实现网络传输速率、CPU 和内存占用率
  2. 支持嵌入到任务栏显示
  3. 支持更换皮肤和自定义皮肤
  4. 历史流量统计

TrafficMonitor | Github

GIF 录制神器 ScreenToGif

  1. 支持屏幕、摄像头、画板录制
  2. 可对 Gif 进行压缩、裁剪、涂鸦、模糊、添加字幕、添加水印、添加进度条等操作
  3. 免费无广告支持免安装使用

按键精灵 KeymouseGo

录制鼠标键盘操作进行自动化操作

KeymouseGo | Github

截图神器 Snipaste

  1. 免费、无广告
  2. 自动检测界面元素区域、像素级的鼠标移动控制、截图范围控制、截图历史记录回放
  3. 标注(矩形、椭圆、线条、箭头、铅笔、马克笔、文字、马赛克、高斯模糊等)
  4. 支持剪贴板中的图像、纯文本、HTML 文本、颜色信息、图像文件转化成图片
  5. 贴图、取色
  6. 支持自定义设置

卸载神器 HiBit Uninstaller

  1. 强制卸载、批量卸载
  2. 安全的清理注册表和垃圾文件
  3. 快捷方式修复
  4. 空文件夹删除
  5. 系统更新补丁管理

软件官网

硬盘分析工具 WizTree

  1. 分析速度极快
  2. 可视化显示空间占用
  3. 支持数据导出
  4. 免费无广告支持免安装使用

软件官网

抢票神器 12306Bypass

  1. 免费可用
  2. 全程自动抢票、自动抢候补、自动识别验证码
  3. 支持多账号

软件官网

文字识别神器 Umi-OCR

  1. 免费开源
  2. 解压即用,离线运行,无需网络
  3. 自带高效率离线 OCR 引擎
  4. 支持命令行、HTTP 接口等多种调用方式
  5. 截图 OCR / 批量 OCR / 二维码 / 数学公式识别

Umi-OCR | Github

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/fe/browser/index.html b/fe/browser/index.html index 206052e4..bb2dcf68 100644 --- a/fe/browser/index.html +++ b/fe/browser/index.html @@ -130,7 +130,7 @@ objectStoreRequest.onsuccess = function () { console.log('删除成功') }

在日常开发中可以使用如下类库简化代码量

- + \ No newline at end of file diff --git a/fe/coding/index.html b/fe/coding/index.html index ec238916..131e961f 100644 --- a/fe/coding/index.html +++ b/fe/coding/index.html @@ -299,7 +299,7 @@ } } } - + \ No newline at end of file diff --git a/fe/concept/module.html b/fe/concept/module.html index e23dc1af..37acd003 100644 --- a/fe/concept/module.html +++ b/fe/concept/module.html @@ -89,7 +89,7 @@ log, } })

相关资料

深入 CommonJs 与 ES6 Module

- + \ No newline at end of file diff --git a/fe/concept/page-rendering.html b/fe/concept/page-rendering.html index 9af193dc..afaa6efe 100644 --- a/fe/concept/page-rendering.html +++ b/fe/concept/page-rendering.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

前端页面渲染方式

CSR 客户端渲染

CSR 客户端渲染(Client Side Rendering)

客户端渲染是指浏览器在请求页面 URL 后,服务端直接返回一个空的静态 HTML 文件,这个 HTML 文件需要再加载 JavaScript 脚本和 CSS 样式表,浏览器加载和执行这些文件去动态改变 DOM 树的结构,使页面渲染成用户所需要的界面,这种动态渲染的方式就是客户端渲染 (CSR)

优点

  • 局部刷新:无需每次都进行完整页面请求
  • 懒加载:首次加载时可以只加载可视区域内的数据
  • 丰富的站点交互
  • 减轻服务器压力
  • 前后端分离

缺点

  • 不利于 SEO
  • 首屏渲染慢:需要等待 JavaScript 脚本文件加载完毕后才开始渲染页面

SEO

SEO(Search Engine Optimization):搜索引擎优化,利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。目的是让其在行业内占据领先地位,获得品牌收益。

SSR 服务端渲染

SSR 服务端渲染(Server Side Rendering)

服务端渲染是指浏览器在请求页面 URL 时,服务端将我们需要的 HTML 文本组装好,并返回给浏览器,这个 HTML 文本被浏览器解析之后,不需要经过 JavaScript 脚本的下载过程,就能直接构建出我们所希望的 DOM 树并展示到页面中。这个服务端组装 HTML 的过程就叫做服务端渲染(SSR)

优点

  • 有利于 SEO
  • 首屏渲染快

缺点

  • 占用服务器资源
  • 用户体验不好:新页面都需要在服务端重新渲染整个页面,不能局部渲染
  • 模板维护成本高

同构渲染

同构渲染是一种现代化服务端渲染方案,实际上是将 CSR 客户端渲染和 SSR 服务端渲染的优势结合起来实现互补;
其流程是先在 Node.js 中进行服务端渲染生成 HTML,然后通过客户端渲染接管页面交互

  • 同构:是指同一套代码可以同时运行在服务端和客户端
    • 路由同构
    • 数据同构
    • 渲染同构
  • 脱水(dehydrate):在服务端渲染直出 HTML 前将预取的数据注入到 window
  • 注水(hydrate):在客户端进行渲染前将 window 上绑定的数据传入到对应组件中

同构渲染流程

为什么需要数据的脱水和注水?

保证服务端和客户端端渲染的组件具有相同的 propsDOM 结构

优点

  • 有利于 SEO
  • 首屏渲染快
  • 局部刷新:无需每次都进行完整页面请求

缺点

  • Node 服务的性能压力
  • 服务端和浏览器环境的差异

开箱即用的 SSR 框架

SSG 静态站点生成

SSG 静态网站生成(Static Site Generation)

静态站点生成是指在构建时就会为每个页面生成包含内容的 HTML 文件,当浏览器在请求页面 URL 时,服务端直接返回 HTML 即可。

优点

  • 有利于 SEO
  • 首屏渲染快
  • 减轻服务器压力

缺点

  • 每次更改内容时都需要重新构建和部署应用程序
  • 无法生成用户相关内容

SSG 应用场景

SSG 适合应用在页面内容在构建时就能确定的场景

  • 静态官网
  • 文档网站

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/fe/css/index.html b/fe/css/index.html index 5c4865c8..b1623b93 100644 --- a/fe/css/index.html +++ b/fe/css/index.html @@ -112,7 +112,7 @@ 关于 @import 的加载顺序 </body> </html>

然后打开浏览器 network 面板去查看具体资源的加载时间

import.css 排队时间

import

link.css 排队时间

link

所以 @import 的加载顺序要看其写在哪里,而不能一概而论

- + \ No newline at end of file diff --git a/fe/es6/index.html b/fe/es6/index.html index 82545bef..6e4eb530 100644 --- a/fe/es6/index.html +++ b/fe/es6/index.html @@ -575,7 +575,7 @@ }), ) }

Promise 静态方法

Promise 实现 简易实现、A+ 规范实现、原型方法、静态方法实现

- + \ No newline at end of file diff --git a/fe/html/index.html b/fe/html/index.html index 1c3c1750..79495f68 100644 --- a/fe/html/index.html +++ b/fe/html/index.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

HTML 理论知识点

HTML 语义化

HTML 语义化是指根据内容的结构化(内容语义化)来选择合适的标签(代码语义化),即用正确的标签做正确的事情

语义化的优点

HTML 语义化增强文档的可识别性

  • 可以使页面在没有 CSS 样式表的情况下也能呈现出很好的内容结构
  • 有利于 SEO 优化(爬虫依赖 HTML 的标签来确定渲染关键字的权重)
  • 方便其他设备解析(屏幕阅读器、盲人阅读器)提升了用户体验
  • 增强了代码的可读性和可维护性

常用的语义化标签

  • <article>:表示文章主体部分
  • <aside>:表示跟文章主体不那么相关的部分,一般包含导航、广告等工具性质的内容
  • <details> 和 <summary>:表示可以查看或隐藏的其他详细信息
  • <figure> 和 <figcaption>:表示与文章相关的图像、照片等流内容
  • <footer>:通常出现在尾部,包含作者信息、相关链接、版权信息等
  • <header>:表示导航或者介绍性的内容
  • <h1> ~ <h6>:表示文章中不同层级的标题
  • <p>:表示文章的段落
  • <main>:表示文章的主要内容
  • <nav>:表示导航
    • header 中大多表示文章目录
    • aside 中大多是关联页面或者是整站地图
  • <section>:表示文章中的“节”或“段”
  • <time>:表示日期或时间

HTML5 标签选择流程图

HTML5 标签选择流程图

HTML 中的语义 —— MDN

HTML 的元素嵌套规则

HTML 元素嵌套规则是指 HTML 标签在嵌套时的合法性,即标签嵌套的顺序和层级

HTML 元素的嵌套合法性

HTML 元素嵌套是否合法由标签的语义决定,即标签的语义决定了标签的嵌套规则

举个 🌰

<h1> 中不能再嵌套 <p>,因为 <p> 是一个段落,而 <h1> 是一个标题,段落不能嵌套在标题中

HTML5 的新特性

HTML5 引入了许多新特性和改进,使得 Web 开发变得更加强大和灵活。HTML5 的新特性主要包括:

  • 语义化标签:引入新的语义化标签,如<header><footer><article><section>等,用于更清晰地表示文档的结构和内容
  • 多媒体支持:提供了<audio><video>元素
  • Canvas 画布: 提供了 <canvas> 元素,允许通过 JavaScript 绘制图形、图表和动画
  • 表单增强:如 <input>type 属性中的 dateemailurl
  • 本地存储:提供了 Web Storage(localStorage 和 sessionStorage)和 IndexedDB,使得浏览器可以在客户端存储数据,以提高性能和离线应用的能力
  • 地理位置 API:提供了 Geolocation API,使得网页可以获取用户设备的地理位置信息
  • Web Workers:允许在后台运行脚本,提高网页的性能和响应性

HTML5 和 H5

  • HTML5 是 HTML 的第五个版本,是 HTML 的最新标准
  • H5 不是一个技术名词,泛指一些富有创意、具有炫酷效果的移动端网页,其通常使用 HTML5、CSS3、JavaScript 等技术来实现丰富的交互和动画效果(这个名词常出现于以下场景)
    • 产品业务:我们有个需求,要做一个 H5 页面来承载 XXX
    • 销售宣传:给客户吹牛逼说我们的 H5 页面很炫酷

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/fe/javascript/clone.html b/fe/javascript/clone.html index 0aa406c9..27386ed4 100644 --- a/fe/javascript/clone.html +++ b/fe/javascript/clone.html @@ -148,7 +148,7 @@ const obj2 = $.extend(true, {}, obj1)

lodash.cloneDeep

js
import { cloneDeep } from 'lodash-es'
 
 const obj2 = cloneDeep(obj1)
- + \ No newline at end of file diff --git a/fe/javascript/conversions.html b/fe/javascript/conversions.html index ae59af72..8b264f1b 100644 --- a/fe/javascript/conversions.html +++ b/fe/javascript/conversions.html @@ -62,7 +62,7 @@ 'str: ' + obj1 // valueOf => 'str: 2021' 'str: ' + obj2 // valueOf toString => 'str: maomao'

ToString

ToString 用来处理非字符串到字符串的类型转换

ToString 转换规则

ToBoolean

ToBoolean 用来处理非布尔值到布尔值的类型转换,在 JavaScript 中,布尔类型分为真值(true)和假值(false)

ToBoolean 转换规则

ToNumber

ToNumber 用来处理非数字值到数字值的类型转换

ToNumber 转换规则

显式类型转换

显式类型转换是指显式的去调用类型转换方法

注意点

隐式类型转换

隐式类型转换是指在执行过程中,当实际操作的值与 JavaScript 内部期望得到的值不同时,就会对其做隐式类型转换(即不易察觉的类型转换)
JavaScript 中有以下场景会发生隐式类型转换

相等运算符运算规则(重点)

为什么 0 == nullfalse

js
0 == null // false

ECMA-262 规范 7.2.12 小节对相等运算符的描述

  1. 如果 x 不是正常值(比如抛出一个错误),中断执行;
  2. 如果 y 不是正常值,中断执行;
  3. 如果 Type(x)Type(y) 相同,执行严格相等运算 x === y
  4. 如果 xnullyundefined,返回 true
  5. 如果 xundefinedynull,返回 true
  6. 如果 Type(x) 是数值,Type(y) 是字符串,返回 x == ToNumber(y) 的结果;
  7. 如果 Type(x) 是字符串,Type(y) 是数值,返回 ToNumber(x) == y 的结果;
  8. 如果 Type(x) 是布尔值,返回 ToNumber(x) == y 的结果;
  9. 如果 Type(y) 是布尔值,返回 x == ToNumber(y) 的结果;
  10. 如果 Type(x) 是字符串或数值或 Symbol 值,Type(y) 是对象,返回 x == ToPrimitive(y) 的结果;
  11. 如果 Type(x) 是对象,Type(y) 是字符串或数值或 Symbol 值,返回 ToPrimitive(x) == y 的结果;
  12. 返回 false

Type(x)the type of x 的简写,其中的 type 是 ECMA-262 规范中定义的 ECMAScript 语言和规范类型

所以在计算 0 == null 时,由于 0 的类型是数值,null 的类型是 Null(这是规格 4.3.13 小节的规定,是内部 Type 运算的结果,跟 typeof 运算符无关);
因此上面的前 11 步都得不到结果,要到第 12 步才能得到 false

相等运算符 —— ECMAScript 6 入门

相等运算符运算规则总结

四则运算符运算规则

四则运算符运算规则

关系、逻辑、条件运算符运算规则

关系运算符运算规则

逻辑操作符与条件判断语句

逻辑操作符条件判断语句中都是做 ToBoolean 处理

- + \ No newline at end of file diff --git a/fe/javascript/inherit.html b/fe/javascript/inherit.html index 0f56468b..8d9a12a5 100644 --- a/fe/javascript/inherit.html +++ b/fe/javascript/inherit.html @@ -247,7 +247,7 @@ return ColorPoint })(Point)

总结


相关资料

- + \ No newline at end of file diff --git a/fe/javascript/prototype.html b/fe/javascript/prototype.html index 33520fe2..a26cdfed 100644 --- a/fe/javascript/prototype.html +++ b/fe/javascript/prototype.html @@ -81,7 +81,7 @@ Function instanceof Function // true // 实际如下 Function.__proto__ === Function.prototype // true

经典图

prototypes

总结


相关资料

- + \ No newline at end of file diff --git a/fe/javascript/this.html b/fe/javascript/this.html index e9d196d9..cc3f40a7 100644 --- a/fe/javascript/this.html +++ b/fe/javascript/this.html @@ -56,7 +56,7 @@ console.log('obj1.method.call(obj2) :', obj1.method.call(obj2)) // new 创建的对象 console.log('new Method().method() :', new Method().method())

打印结果如下

在浏览器环境中 this 指向 window 对象

函数调用 this — 浏览器环境

在 Node.js 环境 CommonJS 中 this 指向 global 对象

函数调用 this — CommonJS

在 Node.js 环境 ESModule 中 this 指向 undefined

函数调用 this — ESModule

- + \ No newline at end of file diff --git a/fe/javascript/types.html b/fe/javascript/types.html index 62063cf8..fc90da44 100644 --- a/fe/javascript/types.html +++ b/fe/javascript/types.html @@ -112,7 +112,7 @@ toString.call(new WeakSet()) // '[object WeakSet]' toString.call(new Map()) // '[object Map]' toString.call(new WeakMap()) // '[object WeakMap]'

toString 方法的在 ECMAScript 5 下的大致执行过程

  1. 如果 thisundefined 返回 [object Undefined]
  2. 如果 thisnull 返回 [object Null]
  3. O 成为 ToObject(this) 的结果
  4. class 成为 O 的内部属性 [[Class]] 的值
  5. 返回由 "[object " class "]" 三个部分组成的字符串

注意点

不同 ECMAScript 版本对 toString 方法的规范都有所不同

Object.prototype.toString 方法的原理

- + \ No newline at end of file diff --git a/fe/monorepo/index.html b/fe/monorepo/index.html index ab90f8b5..471fc233 100644 --- a/fe/monorepo/index.html +++ b/fe/monorepo/index.html @@ -12,7 +12,7 @@ - + @@ -50,7 +50,7 @@ ├── .git ├── src └── index.js - └── package.json

Multi-Repo 的优缺点

优点

缺点


如何选择

在选择时主要取决于项目需求、团队结构和偏好,没有哪种方式是绝对正确的,都要根据实际需求结合其优缺点来进行选择,下面是一些常见的考虑因素:

搭建 Monorepo 项目

常见的 Monorepo 实现

  1. 使用 pnpm/npm/yarnworkspace 功能
  2. 再搭配 Monorepo 管理工具
    1. pnpm
    2. lerna
    3. nx
    4. bazel
    5. rushstack

目前主流的方式是使用 pnpm 来做 Monorepo,其无须使用第三方工具就可以进行管理

安装 pnpm

sh
curl -fsSL https://get.pnpm.io/install.sh | sh -
sh
brew install pnpm
sh
npm install -g pnpm

相关资料

安装 | pnpm

创建项目

sh
# 创建并进入 my-monorepo 文件夹
+    └── package.json

Multi-Repo 的优缺点

优点

缺点


如何选择

在选择时主要取决于项目需求、团队结构和偏好,没有哪种方式是绝对正确的,都要根据实际需求结合其优缺点来进行选择,下面是一些常见的考虑因素:

搭建 Monorepo 项目

常见的 Monorepo 实现

  1. 使用 pnpm/npm/yarnworkspace 功能
  2. 再搭配 Monorepo 管理工具
    1. pnpm
    2. lerna
    3. nx
    4. bazel
    5. rushstack

目前主流的方式是使用 pnpm 来做 Monorepo,其无须使用第三方工具就可以进行管理

安装 pnpm

sh
curl -fsSL https://get.pnpm.io/install.sh | sh -
sh
brew install pnpm
sh
npm install -g pnpm

相关资料

安装 | pnpm

创建项目

sh
# 创建并进入 my-monorepo 文件夹
 mkdir my-monorepo
 cd my-monorepo
 
@@ -112,7 +112,7 @@
 
 # 发布到 npm
 pnpm publish -r

相关资料

在 pnpm 中使用 Changesets | pnpm

- + \ No newline at end of file diff --git a/fe/network/http.html b/fe/network/http.html index 6719b268..1b826f6e 100644 --- a/fe/network/http.html +++ b/fe/network/http.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

HTTP

HTTP 全称为 HyperText Transfer Protocol,即超文本传输协议,是一个用于传输超媒体文档(例如 HTML)的应用层协议

HTTP 协议的主要特点

  • 是一个应用层协议
  • 遵循经典的“客户端-服务端”模型(客户端发送请求,服务器返回响应)
  • 灵活可扩展
    • 语义上的自由,只规定了报文的基本格式,报文里的各个组成部分可以由开发者任意定制
    • 传输格式的多样性
  • 无连接: 每完成一个请求就断开连接(HTTP/1.1 后默认开启长连接)
  • 无状态: HTTP 协议对于事务处理没有记忆能力(每个请求之间、浏览器和服务器之间都是相互独立毫无关联的)
  • 可靠传输: HTTP 协议是一个可靠的传输协议(基于 TCP/IP 协议)
  • 明文传输: 协议里的报文直接使用文本形式传输(HTTP/2.0 后改为二进制传输)

HTTP 协议的演变

HTTP 协议演进与各版本特性

HTTP/0.9

1990 年问世

功能简陋,只有一个 GET 方法,且只支持纯文本内容

HTTP/1.0

1996 年 5 月正式发布

  • 任何格式的内容都可以发送
  • 请求和响应增加了头信息
  • 新增方法:POST HEAD
  • 添加了状态码、多字符集支持、权限、缓存、内容编码等功能

HTTP/1.1

1997 年 1 月发布,是目前主流的 HTTP 协议版本

  • 长连接:TCP 连接默认不关闭可以被多个请求复用
  • 管道机制:在同一个 TCP 链接里面,客户端可以同时发送多个请求
  • 分块传输编码
  • 缓存处理:Cache-ControlEtag/If-None-Match
  • 断点续传
  • 增加了 TLS 支持:支持 HTTPS 传输
  • 新增方法:PUT PATCH OPTIONS DELETE

HTTP/1.1 缺点

  • 单路连接请求低效:每个 TCP 连接只能对应一个 HTTP 请求
  • 队头阻塞:当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。
  • 头信息冗余
  • 只允许由客户端主动发起请求
  • 明文传输

HTTP/2.0

2015 年发布,主要基于 SPDY 协议(2009 年谷歌公开了自行研发的 SPDY 协议,主要解决 HTTP/1.1 效率不高的问题)

  • 二进制传输:头信息和数据体都是二进制
  • 多路复用/二进制分帧:在一个 TCP 连接中可以同时发送多个请求
  • 头部压缩(使用 HPACK 算法进行压缩)
  • 服务器推送:允许服务器未经请求主动向客户端发送资源
  • 请求优先级

HTTP/2.0 缺点

  • 建立连接时间长(本质上是 TCP 的问题)
  • 没有彻底解决队头阻塞问题
  • 弱网环境表现不佳

HTTP/3.0

HTTP/3.0 又称为 HTTP Over QUIC,其弃用 TCP 协议,改为使用基于 UDP 协议的 QUIC 协议来实现

  • 实现了类似 TCP 的流量控制、传输可靠性的功能
  • 实现了快速握手功能
  • 集成了 TLS 加密功能
  • 多路复用,彻底解决 TCP 中队头阻塞的问题

HTTP 状态码

HTTP 状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。

主要有以下 5 响应类别的状态码

  • 1XX 是信息性状态码,表示接收的请求正在处理
  • 2XX 是成功状态码,表示请求正常处理完毕
  • 3XX 是重定向状态码,表示需要进行附加操作以完成请求
  • 4XX 是客户端错误状态码,表示服务器无法处理请求
  • 5XX 是服务器错误状态码,表示服务器处理请求出错

2XX 成功

  • 200 OK 表示从客户端发来的请求在服务器端被正常处理
  • 204 No Content 表示请求成功但在返回的响应报文中不含实体的主体部分
  • 206 Partial Content 表示客户端进行了范围请求

3XX 重定向

  • 301 Moved Permanently 永久性重定向,表示资源已被分配了新的 URL
  • 302 Found 临时性重定向,表示资源临时被分配了新的 URL
  • 303 See Other 表示资源存在着另一个 URL,应使用 GET 方法定向获取请求的资源
  • 304 Not Modified 表示客户端发送附带条件的请求时,服务器端允许请求访问资源但未满足条件的情况
  • 307 Temporary Redirect 临时重定向,和 302 Found 有着相同的含义

4XX 客户端错误

  • 400 Bad Request 表示请求报文中存在语法错误
  • 401 Unauthorized 表示发送的请求需要有通过 HTTP 认证的认证信息
  • 403 Forbidden 表示对请求资源的访问被服务器拒绝
  • 404 Not Found 表示服务器上无法找到请求的资源

5XX 服务器错误

  • 500 Internal Server Error 表示服务器端在执行请求时发生了错误
  • 503 Service Unavailable 表示服务器暂时处于超负载或正在进行停机维护,现在无法处理请求

GET 和 POST 的区别

安全是指请求方法不会破坏服务器上的资源

幂等是指多次执行相同的操作,其结果都是相同的

  • 语义上(最本质的区别)
    • GET 是从服务器获取指定的资源,GET 方法是安全、幂等、可被缓存的
    • POST 是根据请求负荷(报文 body)对指定的资源做出处理,具体的处理方式视资源类型而不同。POST 不安全、不幂等、(大部分实现)不可缓存。

在实际过程中开发者不一定会按照 RFC 规范定义的语义来实现 GETPOST 方法

  • 可以用 GET 方法实现新增或删除数据的请求,这样实现的 GET 方法自然就不是安全和幂等;
  • 可以用 POST 方法实现查询数据的请求,这样实现的 POST 方法自然就是安全和幂等

GET 请求可以带 body 吗?

RFC 规范并没有规定 GET 请求不能带 body。只是因为 RFC 规范定义的 GET 请求是获取资源,所以根据这个语义不需要用到 body。
理论上任何 HTTP 请求都可以带 body,任何 HTTP 请求的 URL 也可以携带查询参数

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/fe/network/tcp.html b/fe/network/tcp.html index e6dd3963..bddb85bc 100644 --- a/fe/network/tcp.html +++ b/fe/network/tcp.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

TCP

TCP(Transmission Control Protocol 传输控制协议)是一个面向连接的可靠的基于字节流的传输层通信协议

TCP 连接

TCP 连接是用于保证可靠性和流量控制维护的某些状态信息的组合,这些信息包括 Socket、序列号和窗口大小

  • Socket:由 IP 地址和端口号组成
  • 序列号:用来解决乱序问题等
  • 窗口大小:用来做流量控制

TCP 四元组

  • 源地址
  • 源端口
  • 目的地址
  • 目的端口

TCP 四元组可以唯一的确定一个连接

三次握手

TCP 连接建立

三次握手是指在建立一个 TCP 连接时客户端和服务器总共要发送 3 个数据包以确认连接的建立

三次握手的过程如下图所示:

TCP 三次握手

最开始时客户端和服务器都处于 CLOSED 状态。然后服务器主动监听某个端口(此时处于 LISTEN 状态)

第一次握手

由客户端发起

客户端会随机初始化一个序列号(client_isn)然后发送一个带有 SYN seq = client_isn 信息的数据包。发送完成后客户端进入 SYN_SEND 状态(连接发送状态)

  • SYN 是一个标志位,为 1 时表示希望建立连接
  • seq = client_isn 是客户端随机初始化的序列号(一个 32 位的无符号数)

第二次握手

由服务器发起

服务器收到客户端的 SYN 报文后,首先会随机初始化自己的序列号(server_isn)然后发送一个带有 SYN ACK seq = server_isn ack = client_isn + 1 信息的数据包。发送完成后服务器进入 SYN_RCVD 状态(连接收到状态)

  • ACK 是一个标志位,表示收到了请求
  • seq = server_isn 是服务器随机初始化的序列号(一个 32 位的无符号数)
  • ack = client_isn + 1 是一个确认应答号,值为客户端序列号 + 1

第三次握手

由客户端发起

客户端收到服务器报文后,会再发送一个带有 ACK ack = server_isn + 1 信息的数据包。发送完成后客户端进入 ESTABLISHED 状态(连接成功状态)服务器收到客户端发送的应答报文包后也会进入 ESTABLISHED 状态

  • ack = server_isn + 1 是一个确认应答号,值为服务器序列号 + 1

三次握手可以保证客户端和服务器能够确认双方的接收和发送能力是否正常

  • 第一次握手:客户端发送 SYN 报文给服务器,服务器接收该报文
    • 客户端什么都不能确认
    • 服务器确认:自己接收正常,对方发送正常
  • 第二次握手:服务器发送 SYN + ACK 报文给客户端,客户端接收该报文
    • 客户端确认:自己发送正常、接收正常,对方发送正常、接收正常
    • 服务器确认:自己接收正常,对方发送正常
  • 第三次握手:客户端发送 ACK 报文给服务器
    • 客户端在第二次握手时已经完成确认
    • 服务器确认:自己发送正常,接收正常,对方发送正常、接收正常

三次握手的作用?

  1. 防止旧的重复连接初始化造成混乱
  2. 同步双方初始序列号(序列号能够保证数据包不重复、不丢弃和按序传输)
  3. 避免资源浪费

为什么不是两次握手?

两次握手无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号

为什么不是四次握手?

因为通过前三次已经可以建立一个可靠的连接,如果再发送第四次确认消息会浪费资源,所以不需要使用更多的通信次数

三次握手过程中,可以携带数据吗?

第一次、第二次握手不可以携带数据,第三次握手可以携带数据,因为在第三次握手时客户端已经处于连接状态,已经知道服务器的接收、发送能力是正常的

四次挥手

TCP 连接断开

四次挥手是指断开一个 TCP 连接时客户端和服务器总共发送 4 个包以确认连接的断开
客户端和服务器双方都可以主动断开连接

四次挥手的过程如下图所示:

TCP 四次挥手

最开始时客户端和服务器都处于 ESTABLISHED 状态

第一次挥手

客户端先发送一个带有 FIN=1 信息的数据包,然后客户端进入 FIN_WAIT_1 状态

第二次挥手

服务器收到客户端的 FIN 报文后,就向客户端发送 ACK 应答报文,然后服务器进入 CLOSED_WAIT 状态
当客户端收到服务器的 ACK 应答报文后会进入 FIN_WAIT_2 状态

第三次挥手

当服务器处理完数据后,会向客户端发送 FIN 报文,之后服务器进入 LAST_ACK 状态

第四次挥手

服务器收到服务器的 FIN 报文后,会回复一个 ACK 应答报文,之后进入 TIME_WAIT 状态
服务器收到了 ACK 应答报文后,就进入了 CLOSED 状态(服务器完成连接的关闭
客户端在经过 2MSL 一段时间后会自动进入 CLOSED 状态(客户端完成连接的关闭

什么是 MSL

MSL 是 Maximum Segment Lifetime(报文最大生存时间)是任何报文在网络上存在的最长时间,超过这个时间报文将会被丢弃

2MSL 的时间是从客户端接收到 FIN 后发送 ACK 开始计时的。如果在 TIME-WAIT 时间内,因为客户端的 ACK 没有传输到服务器,客户端又接收到了服务器重发的 FIN 报文,那么 2MSL 时间将重新计时

为什么挥手需要四次?

  • 在关闭连接时客户端向服务器发送 FIN 时,仅表示客户端不再发送数据了但是还能接收数据;
  • 当服务器在收到客户端的 FIN 报文时,会先回一个 ACK 应答报文,而服务器可能还有数据需要处理和发送,等服务器不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。

为什么需要 TIME_WAIT 状态?

主动发起关闭连接的一方才有 TIME-WAIT 状态

  1. 防止历史连接中的数据,被后面相同四元组的连接错误的接收;
  2. 保证被动关闭连接的一方,能被正确的关闭;

为什么 TIME_WAIT 等待的时间是 2MSL?

  1. 保证服务器能收到最后的 ACK 应答报文
  2. 让此次 TCP 连接中的所有报文在网络中消失,从而避免前后两个使用相同四元组的连接中的前一个连接的报文干扰后一个连接

假如客户端在送 ACK 后,这个 ACK1MSL 时到达服务器,此时服务器在收到这个 ACK 的前一刹那,一直在重传 FIN,这个 FIN 最坏会在 1MSL 时间内消失。因此从客户端发送 ACK 的那一刹那开始,等待 2MSL 可以保证客户端发送的最后一个 ACK 和服务器发送的最后一个 FIN 都在网络中消失

TCP 和 UDP

TCP 和 UDP 的区别

    1. 连接
    • TCP 是面向连接的传输层协议,传输数据前先要建立连接;
    • UDP 是不需要连接,即刻传输数据。
    1. 服务对象
    • TCP 是一对一的两点服务,即一条连接只有两个端点;
    • UDP 支持一对一、一对多、多对多的交互通信。
    1. 可靠性
    • TCP 是可靠交付数据的,数据可以无差错、不丢失、不重复、按需到达;
    • UDP 是尽最大努力交付,不保证可靠交付数据。
    1. 拥塞控制、流量控制
    • TCP 有拥塞控制和流量控制机制,保证数据传输的安全性;
    • UDP 没有拥塞控制、流量控制,即使网络非常拥堵了,也不会影响 UDP 的发送速率。
    1. 首部开销
    • TCP 首部长度较长会有一定的开销,首部在没有使用“选项”字段时是 20 个字节,如果使用了“选项”字段则会变长的;
    • UDP 首部只有 8 个字节,并且是固定不变的,开销较小。
    1. 传输方式
    • TCP 是流式传输,没有边界,但保证顺序和可靠;
    • UDP 是一个包一个包的发送,是有边界的,但可能会丢包和乱序。
    1. 分片不同
    • TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片。
    • UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层。

MSS(Maximum Segment Siz)最大分段大小:一个网络包中除去 IP 和 TCP 头部之后所能容纳的 TCP 数据的最大长度 MTU(Maximum Transmission Unit)最大传输单元:一个网络包的最大长度(以太网中一般为 1500 字节)

TCP 和 UDP 的应用场景

  • TCP 面向连接,能保证数据的可靠性交付,因此经常用于:
    • FTP 文件传输
    • HTTP / HTTPS
  • UDP 面向无连接,可随时发送数据,其本身的处理既简单又高效,因此经常用于:
    • 包总量较少的通信,如 DNS 、SNMP 等
    • 视频、音频等多媒体通信
    • 广播通信

TCP 和 UDP 可以同时绑定相同的端口吗?

传输层的端口号是用于识别同一计算机中同时通信的不同应用程序,而 TCP 和 UDP 是两个不同的传输层协议,其在内核中是两个完全独立的软件模块。
当主机收到数据包后,可以在 IP 包头的协议号字段知道该数据包是 TCP 还是 UDP,所以可以根据这个信息确定送给哪个模块 (TCP/UDP) 处理,送给 TCP/UDP 模块的报文根据端口号确定送给哪个应用程序处理。
因此 TCP 和 UDP 各自的端口号是相互独立的,如 TCP 有一个 80 号端口,UDP 也可以有一个 80 号端口,二者并不冲突。

TCP 相关学习文章

TCP 三次握手与四次挥手面试题 —— 小林 coding

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/fe/node/pkg.html b/fe/node/pkg.html index 6e9e8efc..08f8553a 100644 --- a/fe/node/pkg.html +++ b/fe/node/pkg.html @@ -12,7 +12,7 @@ - + @@ -66,7 +66,7 @@ // recommend { "licenses": "MIT" -}

文件配置

type

'commonjs' | 'module' 表明包使用的模块语法( Node@14 以上版本支持 ES Module

bin

string | { ${binName}: ${binFilePath} } 声明包的脚本文件

脚本文件一般在文件头以 SheBang 声明运行脚本的语言

sh
npm install demo -g
+}

文件配置

type

'commonjs' | 'module' 表明包使用的模块语法( Node@14 以上版本支持 ES Module

  • 默认为 commonjs, 对于 mjs 后缀名文件采用 ESM 语法解析

  • 设置为 module 时,对于 cjs 后缀名文件采用 commonjs 语法解析

bin

string | { ${binName}: ${binFilePath} } 声明包的脚本文件

脚本文件一般在文件头以 SheBang 声明运行脚本的语言

sh
npm install demo -g
 
 d
 # log: Npm is COOL
js
#!/usr/bin/env node
@@ -79,7 +79,7 @@
 }
sh
.
 ├── bin
    └── demo.js
-└── package.json

files

Array<string> 指明将此项目作为依赖包安装时包含的文件,默认为排除以下文件的全部内容:

  • .git
  • CVS
  • .svn
  • .hg
  • .lock-wscript
  • .wafpickle-N
  • .*.swp
  • .DS_Store
  • ._*
  • npm-debug.log
  • .npmrc
  • node_modules
  • config.gypi
  • *.orig
  • package.json / npm-shrinkwrap.json

TIP

files 字段作用类似的还有 .npmignore.gitignore

files 类似于白名单,往往产物内容更少更方便。而 ignore 文件类似于黑名单,需要开发者持续维护

types

string => filePath 声明此项目的 TypeScript 类型文件

TIP

  • typestypings 意义完全相同,可替换使用
  • 当主声明文件命名为 index.d.ts,并且位于包的根目录与 index.js 同级,则可以省略 types 字段,但建议保持良好的声明式习惯

参阅 TypeScript | Docs

main

string 标准化的工具包主入口

默认为 index.js ,主要用于 Node.jscjs 模块

js
const foo = require('foo') // => from "main" field
+└── package.json

files

Array<string> 指明将此项目作为依赖包安装时包含的文件,默认为排除以下文件的全部内容:

  • .git
  • CVS
  • .svn
  • .hg
  • .lock-wscript
  • .wafpickle-N
  • .*.swp
  • .DS_Store
  • ._*
  • npm-debug.log
  • .npmrc
  • node_modules
  • config.gypi
  • *.orig
  • package.json / npm-shrinkwrap.json

TIP

files 字段作用类似的还有 .npmignore.gitignore

files 类似于白名单,往往产物内容更少更方便。而 ignore 文件类似于黑名单,需要开发者持续维护

types

string => filePath 声明此项目的 TypeScript 类型文件

TIP

  • typestypings 意义完全相同,可替换使用
  • 当主声明文件命名为 index.d.ts,并且位于包的根目录与 index.js 同级,则可以省略 types 字段,但建议保持良好的声明式习惯

参阅 TypeScript | Docs

main

string 标准化的工具包主入口

默认为 index.js ,主要用于 Node.jscjs 模块

js
const foo = require('foo') // => from "main" field
 // foo => { value: 1 }
js
// foo.cjs
 module.exports = {
   value: 1,
@@ -144,7 +144,7 @@
       }
     }
   }
-}

脚本配置

scripts

Record<string, string> 带有以下默认生命周期的脚本命令: <pre> | <post>

  • install
  • uninstall
  • start
  • restart
  • stop
  • test
  • pack
  • publish
  • 自定义脚本命令

特殊的 prepareprepublishOnlyscripts 文档

TIP

在 pnpm@6 与 yarn2 中, preinstall 将在 install 后执行,而不是在 install 之前

为此 pnpm 提供了 pnpm:devPreinstall 钩子以兼容开发者的使用习惯

config

Record<string, string> process.env 配置命令行的环境变量

js
#!/usr/bin/env node
+}

脚本配置

scripts

Record<string, string> 带有以下默认生命周期的脚本命令: <pre> | <post>

  • install
  • uninstall
  • start
  • restart
  • stop
  • test
  • pack
  • publish
  • 自定义脚本命令

特殊的 prepareprepublishOnlyscripts 文档

TIP

在 pnpm@6 与 yarn2 中, preinstall 将在 install 后执行,而不是在 install 之前

为此 pnpm 提供了 pnpm:devPreinstall 钩子以兼容开发者的使用习惯

config

Record<string, string> process.env 配置命令行的环境变量

js
#!/usr/bin/env node
 
 console.log(process.env.npm_package_config_port) // 8732
 console.log(process.env.npm_package_config_foo) // bar
json
{
@@ -180,7 +180,7 @@
     "cpu": ["!arm"]
   }
 }

第三方配置

sideEffects

boolean | Array<string => filePath> 声明存在副作用的模块,用于 Webpack 等打包工具的导出优化

对于模块是否有副作用的定义,基本是指开发者在设计时是否产生了副作用,而不必关心经过打包工具处理后的最终产物。

unpkg

string => filePath 在发布到 npm 后,可以使用此字段为项目对应的文件开启 CDN 服务,默认为 main

TIP

参阅 unpkg | docs

jsdelivr

string => filePath 类似于 unpkg

cosmiconfig

基于 cosmiconfig 实现的相关配置仅在此简单罗列常用工具

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/fe/rollup/index.html b/fe/rollup/index.html index b5319327..3d217253 100644 --- a/fe/rollup/index.html +++ b/fe/rollup/index.html @@ -172,7 +172,7 @@ "private": true, "types": "./index.d.ts" }

WARNING

子包的 name 必须要以 @types/ 开头,否则 TypeScript 无法自动加载

编写 index.d.ts

ts
declare const unsafeWindow: Window

在主包中安装 types 子包

sh
pnpm add -Dw @types/shared-types

相关资料

参考了 tsconfig/bases | GitHub 的相关代码

- + \ No newline at end of file diff --git a/fe/typescript/base.html b/fe/typescript/base.html index 8f0f08a9..4e306d1a 100644 --- a/fe/typescript/base.html +++ b/fe/typescript/base.html @@ -583,7 +583,7 @@ type Result = ReturnType<typeof add> // Result: number

相关资料

- + \ No newline at end of file diff --git a/fe/typescript/challenges.html b/fe/typescript/challenges.html index dc60099d..30fae3e1 100644 --- a/fe/typescript/challenges.html +++ b/fe/typescript/challenges.html @@ -419,7 +419,7 @@ type PercentageParser<A extends string> = A extends `${CheckPrefix<infer L>}${infer R}` ? [L, ...CheckSuffix<R>] : ['', ...CheckSuffix<A>] - + \ No newline at end of file diff --git a/fe/typescript/tsconfig.html b/fe/typescript/tsconfig.html index 8dd4be3e..91864af4 100644 --- a/fe/typescript/tsconfig.html +++ b/fe/typescript/tsconfig.html @@ -159,7 +159,7 @@ }, "references": [{ "path": "./tsconfig.base.json" }] } - + \ No newline at end of file diff --git a/fe/typescript/utility-types.html b/fe/typescript/utility-types.html index 76b65fe2..a5dcf73b 100644 --- a/fe/typescript/utility-types.html +++ b/fe/typescript/utility-types.html @@ -111,7 +111,7 @@ // 结果:'maomao'

Capitalize<StringType> 将字符串首字母转换为大写

Capitalize<StringType> 将字符串首字母转换为大写

举 🌰

ts
type result = Uncapitalize<'maomao'>
 // 结果:'Maomao'

Uncapitalize<StringType> 将字符串首字母转换为小写

Uncapitalize<StringType> 将字符串首字母转换为小写

举 🌰

ts
type result = Uncapitalize<'Maomao'>
 // 结果:'maomao'

相关资料

Utility Types | TypeScript

- + \ No newline at end of file diff --git a/fe/webpack/index.html b/fe/webpack/index.html index 060a33c5..a7e66317 100644 --- a/fe/webpack/index.html +++ b/fe/webpack/index.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

Webpack

Webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具

核心概念

  • entry 编译的入口文件
  • output 如何输出以及在哪里输出
  • module Webpack 一切皆模块,一个模块对应一个文件
  • chunk 代码块,由多个 module 组成
  • loader Webpack 通过不同的 loader 对模块的源代码进行转换
  • plugin 插件 Webpack 在打包构建的生命周期中提供了不同的 hooks 允许调用方能够对打包的资源注入自己的逻辑处理
  • compiler 编译器,把控整个 Webpack 打包的构建流程
  • compilation 每一次构建的上下文对象包含了当次构建的所有信息
  • dependence 记录模块间依赖关系

构建流程

Init 初始化阶段

  1. 解析命令行与 webpack.config.js 配置的参数,合并生成最后的配置
  2. 创建 compiler 对象并开始启动插件
    1. 调用 createCompiler 函数创建 compiler 对象
    2. 遍历注册的 Plugins 并执行其 apply 方法
    3. 调用 new WebpackOptionsApply().process 方法,根据配置内容动态注入相应插件
      1. 调用 EntryOptionPlugin 插件,该插件根据 entry 值注入 DynamicEntryPluginEntryPlugin 插件
      2. 根据 devtool 值注入 Sourcemap 插件
        1. SourceMapDevToolPlugin
        2. EvalSourceMapDevToolPlugin
        3. EvalDevToolModulePlugin
      3. 注入 RuntimePlugin 用于根据代码内容动态注入 webpack 运行时
    4. 调用 compiler.compile 方法开始执行构建

Make 构建阶段

  1. 读入文件内容
  2. 调用 Loader 将模块转译为标准的 JS 内容
  3. 调用 acorn 生成 AST 语法树
  4. 分析 AST 确定模块依赖列表
  5. 解析模块依赖(对每一个依赖模块重新执行上述流程,直到生成完整的模块依赖图 —— ModuleGraph 对象)

Seal 生成阶段

  1. 遍历模块依赖图并执行操作
    1. 代码转译,如 import 转换为 require 调用
    2. 分析运行时依赖
  2. 合并模块代码与运行时代码并生成 chunk
  3. 执行产物优化操作
    1. Tree-shaking
    2. 压缩
    3. Code Split
  4. 输出结果(根据配置确定输出的路径和文件名,把文件内容写入到文件系统)

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/hashmap.json b/hashmap.json index d837108a..1b6ace33 100644 --- a/hashmap.json +++ b/hashmap.json @@ -1 +1 @@ -{"analysis_react_18.2.0_base_idea.md":"ClyBRI7q","analysis_react_18.2.0_base_jsx.md":"Bi5sHt5-","analysis_react_18.2.0_base_mode-process.md":"C_g-sCyH","analysis_react_18.2.0_base_virtual-dom.md":"2ds0Rmgm","analysis_react_18.2.0_process_begin-work.md":"BsSNwgWF","analysis_react_18.2.0_process_commit-mutation-effects.md":"BI1iN-yq","fe_typescript_utility-types.md":"6J7_YCnj","analysis_react_18.md":"oLIx2yVK","efficiency_software_vscode.md":"DH7dIokV","efficiency_software_webstorm.md":"D0SiikLc","efficiency_software_windows.md":"D2GBjOnL","fe_browser_index.md":"DkaFC_4Y","fe_coding_index.md":"BH-pW_DF","fe_concept_module.md":"BPAZluFO","fe_concept_page-rendering.md":"CBHfzMg3","fe_css_index.md":"BvRdFv2y","fe_html_index.md":"DTAvcJwF","fe_javascript_conversions.md":"BLe1Y6dF","analysis_react_18.2.0_process_complete-work.md":"C9iwZGqY","fe_javascript_prototype.md":"B0pDNdCn","fe_javascript_this.md":"BvxZBwkm","fe_javascript_types.md":"CTTHjRFI","fe_monorepo_index.md":"BIhnHzT9","fe_network_http.md":"hhGt8ZHC","fe_network_tcp.md":"DPR5jta_","fe_node_pkg.md":"DTBhy2rk","efficiency_software_mac.md":"r23aQFZ-","analysis_react_18.2.0_process_init.md":"B_Du6oOj","analysis_react_18.2.0_process_commit-before-mutation-effects.md":"prb93075","fe_typescript_base.md":"C8m9UN-Q","analysis_react_18.2.0_process_schedule-update-on-fiber.md":"tva920Gk","analysis_utils_clsx.md":"B5oPp8u8","analysis_utils_only-allow.md":"B_Fz7C4g","daily-notes_index.md":"31tgPClD","daily-notes_issue-1.md":"DJ-uH5jA","daily-notes_issue-10.md":"CKKxscwm","daily-notes_issue-11.md":"CtxID2qE","daily-notes_issue-15.md":"D_JFP9aX","daily-notes_issue-16.md":"DtWoRKXu","daily-notes_issue-17.md":"BiKLI-m3","daily-notes_issue-18.md":"CCyJXx1y","daily-notes_issue-21.md":"B9AZeZUz","daily-notes_issue-25.md":"CDhEt26q","daily-notes_issue-26.md":"EyeM7h4A","daily-notes_issue-27.md":"CjdGBvik","daily-notes_issue-28.md":"Dq42MS-o","daily-notes_issue-29.md":"BQ2DYXS_","fe_typescript_challenges.md":"BG6mnBKC","fe_typescript_tsconfig.md":"Dn6McTMX","fe_es6_index.md":"DuncB98d","pit_library.md":"D9U2GbZI","daily-notes_issue-34.md":"D3wAzzFx","daily-notes_issue-30.md":"CqFvKA9W","daily-notes_issue-31.md":"BP-bIqKc","daily-notes_issue-33.md":"SYGBo6v9","daily-notes_issue-36.md":"Dmtau4_w","daily-notes_issue-37.md":"DMzrmzWV","daily-notes_issue-38.md":"B61N9WVt","daily-notes_issue-39.md":"DOFFopxA","daily-notes_issue-4.md":"CLcp1gM8","daily-notes_issue-41.md":"NiK6c_I7","analysis_react_18.2.0_base_fiber.md":"eBZ_bPGK","daily-notes_issue-42.md":"1_cQaCh7","daily-notes_issue-43.md":"2oJHvmRr","daily-notes_issue-44.md":"CEnmnUhS","daily-notes_issue-45.md":"C7RKlaO-","daily-notes_issue-46.md":"C5Nr5uft","daily-notes_issue-47.md":"DYaEnvhK","daily-notes_issue-48.md":"Cvp1rtne","daily-notes_issue-5.md":"CNSD--3r","daily-notes_issue-6.md":"CJqDxZpF","daily-notes_issue-7.md":"5qiljnp5","daily-notes_issue-8.md":"CSyrr2UB","daily-notes_issue-9.md":"D3V8_3ir","efficiency_bookmark-scripts.md":"BpUaRoS0","efficiency_online-tools.md":"ihHz4IoS","efficiency_software_browser.md":"D5MQPI8H","efficiency_software_cross-platform.md":"DR9GGbfd","analysis_react_18.2.0_base_file.md":"u_a-sLbI","analysis_react_18.2.0_process_commit-layout-effects.md":"DYPGPb7e","analysis_utils_await-to-js.md":"ePOcKuMa","analysis_react_interview.md":"CAT1MfOv","analysis_react_18.2.0_process_commit-root.md":"CF7MO6T8","daily-notes_issue-12.md":"DtBxOM7A","daily-notes_issue-35.md":"BFwuFpGO","fe_webpack_index.md":"IojVx6fi","index.md":"D0ui0t_y","mao.md":"cKgwFsEr","nav.md":"p_XuvLqH","pit_browser.md":"Cu9hsuhl","pit_css.md":"DWmXGLhK","pit_editor.md":"B3A8EYgt","pit_h5.md":"DqnDkuue","pit_javascript.md":"xOeLjCok","pit_npm.md":"BN7DQf2F","pit_pc.md":"BrEa_Ire","pit_typescript.md":"DLYNdk08","pit_wechat.md":"BLYPna3X","workflow_git_command.md":"Mm6I3kH3","workflow_git_index.md":"CI6J1xft","workflow_library_dayjs.md":"DQfFzX36","daily-notes_issue-20.md":"BorslPq1","workflow_node_npm.md":"CVMTI3gr","workflow_sass_index.md":"Coa6KOlc","workflow_style-guide.md":"BpAO4XkR","workflow_terminal_shell.md":"CjOKpa6w","workflow_terminal_toolkit.md":"CFYYg0Dy","workflow_terminal_zsh.md":"a2lFEvdG","workflow_vue_index.md":"tmq2Fk7R","daily-notes_issue-13.md":"h1QD9keG","workflow_html_tricks.md":"BjS1AM8Y","workflow_library_gsap.md":"CVdvM5aE","daily-notes_issue-14.md":"C6A8l7n9","daily-notes_issue-3.md":"DZf7RFRn","daily-notes_issue-22.md":"8uT9wkdS","daily-notes_issue-23.md":"KdfjHcBu","daily-notes_issue-24.md":"6WWRWfX4","workflow_library_tailwindcss.md":"ByP1KMnE","daily-notes_issue-2.md":"dU5T5avG","daily-notes_issue-19.md":"F2zpXaW9","fe_javascript_clone.md":"Dh0q2jfT","workflow_utils_library.md":"CJCibOwx","workflow_utils_regexp.md":"B9__C0me","workflow_utils_snippets.md":"BcerJAdS","fe_javascript_inherit.md":"LhnYPZs6","workflow_layouts_border_index.md":"mi3OcR-a","workflow_layouts_effects_text.md":"BOnnR9Lt","workflow_layouts_progress_index.md":"CmHCh9aX","workflow_library_csv.md":"C51esZzd","fe_rollup_index.md":"o6nomO2X","analysis_cli_create-vue.md":"CV3nkJKy","workflow_css_spec.md":"qSCD41KI","workflow_css_tricks.md":"CSgzq6z9"} +{"efficiency_online-tools.md":"ihHz4IoS","daily-notes_issue-13.md":"h1QD9keG","daily-notes_issue-14.md":"C6A8l7n9","daily-notes_issue-15.md":"D_JFP9aX","daily-notes_issue-16.md":"DtWoRKXu","daily-notes_issue-17.md":"BiKLI-m3","daily-notes_issue-18.md":"CCyJXx1y","daily-notes_issue-19.md":"F2zpXaW9","daily-notes_issue-35.md":"BFwuFpGO","daily-notes_issue-2.md":"dU5T5avG","efficiency_software_webstorm.md":"D0SiikLc","daily-notes_issue-24.md":"6WWRWfX4","daily-notes_issue-12.md":"DtBxOM7A","efficiency_software_cross-platform.md":"DR9GGbfd","daily-notes_issue-27.md":"CjdGBvik","daily-notes_issue-5.md":"CNSD--3r","daily-notes_issue-25.md":"CDhEt26q","daily-notes_issue-26.md":"EyeM7h4A","fe_typescript_base.md":"C8m9UN-Q","fe_typescript_tsconfig.md":"Dn6McTMX","fe_rollup_index.md":"o6nomO2X","fe_typescript_utility-types.md":"6J7_YCnj","fe_webpack_index.md":"IojVx6fi","index.md":"D0ui0t_y","mao.md":"cKgwFsEr","nav.md":"p_XuvLqH","pit_browser.md":"Cu9hsuhl","pit_css.md":"DWmXGLhK","pit_editor.md":"D7PRr_VP","pit_h5.md":"DqnDkuue","pit_javascript.md":"xOeLjCok","pit_npm.md":"BN7DQf2F","pit_pc.md":"BrEa_Ire","pit_typescript.md":"DLYNdk08","pit_library.md":"D9U2GbZI","pit_wechat.md":"BLYPna3X","workflow_css_spec.md":"qSCD41KI","daily-notes_issue-31.md":"BP-bIqKc","workflow_css_tricks.md":"CSgzq6z9","daily-notes_issue-23.md":"KdfjHcBu","analysis_cli_create-vue.md":"CV3nkJKy","analysis_react_18.2.0_base_virtual-dom.md":"2ds0Rmgm","daily-notes_issue-3.md":"DZf7RFRn","daily-notes_issue-29.md":"BQ2DYXS_","analysis_react_18.2.0_base_mode-process.md":"C_g-sCyH","analysis_react_18.2.0_process_commit-mutation-effects.md":"BI1iN-yq","daily-notes_issue-36.md":"Dmtau4_w","analysis_react_18.2.0_process_commit-before-mutation-effects.md":"prb93075","analysis_react_18.2.0_base_fiber.md":"eBZ_bPGK","analysis_react_18.2.0_base_file.md":"u_a-sLbI","analysis_react_18.2.0_process_complete-work.md":"C9iwZGqY","analysis_react_18.2.0_base_jsx.md":"Bi5sHt5-","analysis_react_18.2.0_process_init.md":"B_Du6oOj","analysis_react_18.2.0_process_begin-work.md":"BsSNwgWF","analysis_react_18.2.0_process_commit-root.md":"CF7MO6T8","daily-notes_index.md":"31tgPClD","daily-notes_issue-1.md":"DJ-uH5jA","daily-notes_issue-6.md":"CJqDxZpF","analysis_utils_only-allow.md":"B_Fz7C4g","daily-notes_issue-11.md":"CtxID2qE","daily-notes_issue-8.md":"CSyrr2UB","daily-notes_issue-34.md":"D3wAzzFx","daily-notes_issue-21.md":"B9AZeZUz","analysis_utils_clsx.md":"B5oPp8u8","daily-notes_issue-22.md":"8uT9wkdS","daily-notes_issue-10.md":"CKKxscwm","daily-notes_issue-20.md":"BorslPq1","daily-notes_issue-37.md":"DMzrmzWV","workflow_git_index.md":"CI6J1xft","workflow_layouts_effects_text.md":"BOnnR9Lt","fe_typescript_challenges.md":"BG6mnBKC","workflow_git_command.md":"Mm6I3kH3","workflow_html_tricks.md":"BjS1AM8Y","workflow_layouts_progress_index.md":"CmHCh9aX","workflow_layouts_border_index.md":"mi3OcR-a","workflow_library_csv.md":"C51esZzd","workflow_library_gsap.md":"CVdvM5aE","workflow_sass_index.md":"Coa6KOlc","workflow_terminal_shell.md":"CjOKpa6w","workflow_library_tailwindcss.md":"ByP1KMnE","workflow_node_npm.md":"CVMTI3gr","workflow_utils_library.md":"CJCibOwx","workflow_terminal_zsh.md":"DtxqY7k0","efficiency_software_mac.md":"r23aQFZ-","workflow_utils_regexp.md":"B9__C0me","workflow_style-guide.md":"BpAO4XkR","efficiency_software_windows.md":"D2GBjOnL","fe_coding_index.md":"BH-pW_DF","daily-notes_issue-33.md":"SYGBo6v9","fe_concept_module.md":"BPAZluFO","workflow_vue_index.md":"tmq2Fk7R","fe_concept_page-rendering.md":"CBHfzMg3","workflow_utils_snippets.md":"BcerJAdS","workflow_terminal_toolkit.md":"CFYYg0Dy","fe_css_index.md":"BvRdFv2y","fe_html_index.md":"DTAvcJwF","fe_javascript_conversions.md":"BLe1Y6dF","fe_javascript_clone.md":"Dh0q2jfT","fe_javascript_prototype.md":"B0pDNdCn","fe_javascript_inherit.md":"LhnYPZs6","fe_javascript_this.md":"BvxZBwkm","daily-notes_issue-39.md":"DOFFopxA","daily-notes_issue-38.md":"B61N9WVt","fe_node_pkg.md":"q2jkodkv","efficiency_software_browser.md":"D5MQPI8H","efficiency_software_vscode.md":"DH7dIokV","fe_es6_index.md":"DuncB98d","analysis_utils_await-to-js.md":"ePOcKuMa","daily-notes_issue-41.md":"NiK6c_I7","daily-notes_issue-4.md":"CLcp1gM8","analysis_react_18.2.0_process_commit-layout-effects.md":"DYPGPb7e","fe_javascript_types.md":"CTTHjRFI","daily-notes_issue-43.md":"2oJHvmRr","daily-notes_issue-42.md":"1_cQaCh7","efficiency_bookmark-scripts.md":"BpUaRoS0","daily-notes_issue-47.md":"DYaEnvhK","daily-notes_issue-45.md":"C7RKlaO-","daily-notes_issue-44.md":"CEnmnUhS","daily-notes_issue-46.md":"C5Nr5uft","analysis_react_18.2.0_process_schedule-update-on-fiber.md":"tva920Gk","analysis_react_18.md":"oLIx2yVK","daily-notes_issue-30.md":"CqFvKA9W","daily-notes_issue-9.md":"D3V8_3ir","analysis_react_interview.md":"CAT1MfOv","fe_browser_index.md":"DkaFC_4Y","workflow_library_dayjs.md":"D5iAKsy5","fe_monorepo_index.md":"LxRgU25L","daily-notes_issue-28.md":"Dq42MS-o","fe_network_http.md":"hhGt8ZHC","fe_network_tcp.md":"DPR5jta_","analysis_react_18.2.0_base_idea.md":"ClyBRI7q","daily-notes_issue-48.md":"Cvp1rtne","daily-notes_issue-7.md":"5qiljnp5"} diff --git a/index.html b/index.html index 84265ff4..2b8ad8a9 100644 --- a/index.html +++ b/index.html @@ -33,7 +33,7 @@ "link": "https://notes.fe-mm.com", "icon": "https://notes.fe-mm.com/logo.png" } - + \ No newline at end of file diff --git a/mao.html b/mao.html index 04f0dc89..12986e0a 100644 --- a/mao.html +++ b/mao.html @@ -29,7 +29,7 @@
Skip to content

茂茂 maoamo maoamo1996

sh
吾志所向,一往无前。
                                 -- 一个想躺平的小开发

About:

Contact me:

添加好友时请添加备注,谢谢!

WechatQQEmail

Languages:

HTML5CSS3JavaScriptTypeScriptShell Script

Frameworks, Platforms and Libraries:

WebPackRollupViteReactNext.jsAnt DesignVue.jsExpressJestLodashSassLessTailwind CSSSwiper

Editors and Tools:

Visual Studio CodeWebStormGitIterm2ZshHomebrewNode.jsPnpmYarnPrettierESLintVercelNetlify

最后更新于:

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/nav.html b/nav.html index 13b8c6c8..bddf2051 100644 --- a/nav.html +++ b/nav.html @@ -29,7 +29,7 @@
- + \ No newline at end of file diff --git a/pit/browser.html b/pit/browser.html index 90484f8b..34de5dc0 100644 --- a/pit/browser.html +++ b/pit/browser.html @@ -109,7 +109,7 @@ 6697, // IRC + TLS 10080, // Amanda };

kRestrictedPorts | Chromium

解决方法

  1. 修改项目启动端口为其他可访问的端口(推荐)
  2. 修改浏览器启动参数放开端口限制
    1. MacOS 系统:通过终端命令 open -a "Google Chrome" --args --explicitly-allowed-ports=6000,6666 启动浏览器
    2. Windows 系统:在桌面快捷方式上右键,选择 属性,在 目标 后面添加 --explicitly-allowed-ports=6000,6666 后保存,再通过快捷方式启动浏览器
- + \ No newline at end of file diff --git a/pit/css.html b/pit/css.html index 1383104b..004122f8 100644 --- a/pit/css.html +++ b/pit/css.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

CSS 踩坑记录

记录个人遇到过或他人分享的 CSS 相关踩坑记录

flex 项目上设置 width 无效

在使用 flex 布局时,给项目设置 width 无效

解决方法

  1. 使用 flex-basis 代替 width
  2. 使用 min-width 代替 width
  3. 设置 flex-shrink: 0 禁止项目缩小,再设置 width

:visited 不支持 animation

在本博客站点中,整了花里胡哨的颜色动画,但是发现 :visited 伪类不支持 animation,导致无法实现效果(各种访问过的链接颜色错乱)

:visited 选择器知识点

:visited 伪类表示用户已访问过的链接,它只支持下列 CSS 属性,其他属性无效

  • color
  • background-color
  • border-color
  • outline-color
  • fillstroke 属性的颜色部分

相关资料

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/pit/editor.html b/pit/editor.html index fea8df2e..bcc850d6 100644 --- a/pit/editor.html +++ b/pit/editor.html @@ -12,7 +12,7 @@ - + @@ -27,8 +27,8 @@ -
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

编辑器踩坑记录

在 VSCode 使用 GUI 时提示 xxx: command not found

husky 为例

在 VSCode 中使用 GUI(源代码管理 - 输入框)进行 git commit 时,提示 Git: .husky/commit-msg: line 4: npx: command not found

原因

  1. 使用了 fnmnvm 存在了多个版本的 Node.js
  2. 在终端外部启动的 GUI 不会初始化 Node.js,导致 $PATH 中没有 Node.js
  3. 当使用 VSCode GUI 时,就会导致 Node.js 相关的命令丢失

解决方法

一共有如下几种方案

  1. 通过 VSCode 的 code 命令打开编辑器(使用命令行进入到项目目录 code .
  2. 添加 ~/.config/husky/init.sh~/.huskyrc 文件(内容如下)

~/.huskyrc 高版本已弃用

bash
eval "$(fnm env --use-on-cd)"
bash
export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

shell 启动文件快速且轻量级时可直接在 ~/.config/husky/init.sh~/.huskyrc 配置如下

Oh My ZSH: 你们针对我?

sh
. ~/.zshrc

如有转载或 CV 的请标注本站原文地址

- +
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

编辑器踩坑记录

在 VSCode 使用 GUI 时提示 xxx: command not found

husky 为例

在 VSCode 中使用 GUI(源代码管理 - 输入框)进行 git commit 时,提示 Git: .husky/commit-msg: line 4: npx: command not found

原因

  1. 使用了 fnmnvm 存在了多个版本的 Node.js
  2. 在终端外部启动的 GUI 不会初始化 Node.js,导致 $PATH 中没有 Node.js
  3. 当使用 VSCode GUI 时,就会导致 Node.js 相关的命令丢失

解决方法

一共有如下几种方案

  1. 通过 VSCode 的 code 命令打开编辑器(使用命令行进入到项目目录 code .
  2. 添加 ~/.config/husky/init.sh~/.huskyrc 文件(内容如下)

~/.huskyrc 高版本已弃用

bash
eval "$(fnm env --use-on-cd)"
bash
export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

shell 启动文件快速且轻量级时可直接在 ~/.config/husky/init.sh~/.huskyrc 配置如下

Oh My ZSH: 你们针对我?

sh
. ~/.zshrc

如有转载或 CV 的请标注本站原文地址

+ \ No newline at end of file diff --git a/pit/h5.html b/pit/h5.html index 64db199c..9ce78c59 100644 --- a/pit/h5.html +++ b/pit/h5.html @@ -37,7 +37,7 @@ } document.querySelector('body').addEventListener('touchmove', onTouchMove) - + \ No newline at end of file diff --git a/pit/javascript.html b/pit/javascript.html index bf69cc46..3e8910bf 100644 --- a/pit/javascript.html +++ b/pit/javascript.html @@ -40,7 +40,7 @@ size('𠮷') // 1 size('😀') // 1 size('👩‍👩‍👧‍👧') // 1

相关资料

- + \ No newline at end of file diff --git a/pit/library.html b/pit/library.html index 82dc66a8..4cca07b5 100644 --- a/pit/library.html +++ b/pit/library.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

第三方库踩坑记录

记录个人遇到或他人分享的第三方库相关踩坑记录

moment 迁移到 dayjs

在做 webpack 构建优化时,会使用 antd-dayjs-webpack-plugin 插件将 moment 替换为 dayjs

在迁移时需要注意这些方法的部分参数不一致

  • add 增加时间
  • subtract 减少时间
  • startOf 开始时间
  • endOf 结束时间
描述moment 支持的参数dayjs 支持的参数
years year Y yyears year y
months month Mmonths month M
weeks week wweeks week w
days day ddays day d
hours hour H hhours hour h
minutes minute mminutes minute m
seconds second sseconds second s
毫秒milliseconds millisecond msmilliseconds millisecond ms

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/pit/npm.html b/pit/npm.html index db7be1cd..fa452906 100644 --- a/pit/npm.html +++ b/pit/npm.html @@ -47,7 +47,7 @@ electron_mirror=https://npmmirror.com/mirrors/electron profiler_binary_host_mirror=https://npmmirror.com/mirrors/node-inspector chromedriver_cdnurl=https://npmmirror.com/mirrors/chromedriver

npm 包中的文件丢失

最近在发布自己的 npm 包时,发现包中的文件未完全上传,导致安装后缺少文件

npm 上传时默认会忽略这些文件

npm ignored | GitHub

解决方法

  1. 将需要上传的文件添加到 package.jsonfiles 字段中
  2. 修改文件名
- + \ No newline at end of file diff --git a/pit/pc.html b/pit/pc.html index 908909f4..a6907820 100644 --- a/pit/pc.html +++ b/pit/pc.html @@ -54,7 +54,7 @@ ) }) } - + \ No newline at end of file diff --git a/pit/typescript.html b/pit/typescript.html index 0db09f47..48996829 100644 --- a/pit/typescript.html +++ b/pit/typescript.html @@ -39,7 +39,7 @@ } } } - + \ No newline at end of file diff --git a/pit/wechat.html b/pit/wechat.html index 2726a3d5..b01832a8 100644 --- a/pit/wechat.html +++ b/pit/wechat.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

微信开发踩坑记录

记录个人遇到或他人分享的微信开发踩坑记录相关踩坑记录

微信 H5 页面分享出去是明文链接不是卡片

在微信开发者工具中,点击右上角的分享按钮,选择转发给朋友,可以分享出去的是卡片,但在手机上进行分享操作时,分享出去的是明文链接

原因

微信开放全域名访问后出现的限制,在聊天窗口直接通过点击链接进入页面进行转发时会被微信拦截,导致分享出去的是明文链接

关于《微信外部链接内容管理规范》的更新说明

解决方法

不直接通过点击群聊单聊里面的明文链接进入页面,而是通过其他方式进入页面

  1. 将链接配置在公众号菜单中,通过菜单进入页面
  2. 将链接通过聊天发送给公众号,再点击链接进入页面
  3. 生成二维码,通过扫描二维码进入页面
  4. 将链接添加到收藏夹,通过收藏夹进入页面

公众号分享出去不是卡片而是链接 | 微信开放社区

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/workflow/css/spec.html b/workflow/css/spec.html index db27334d..d454040d 100644 --- a/workflow/css/spec.html +++ b/workflow/css/spec.html @@ -99,7 +99,7 @@ ::-webkit-resizer { display: none; }

::-webkit-scrollbar | MDN

- + \ No newline at end of file diff --git a/workflow/css/tricks.html b/workflow/css/tricks.html index 56617efd..09fe1608 100644 --- a/workflow/css/tricks.html +++ b/workflow/css/tricks.html @@ -98,7 +98,7 @@ text-overflow: ellipsis; } </style>

相关资料

- + \ No newline at end of file diff --git a/workflow/git/command.html b/workflow/git/command.html index ced529ba..228049ff 100644 --- a/workflow/git/command.html +++ b/workflow/git/command.html @@ -225,7 +225,7 @@ # 查看所有分支的所有操作记录(包括被删除的 commit 记录和 reset 操作) git reflog

相关资料

常用 Git 命令清单 | 阮一峰

- + \ No newline at end of file diff --git a/workflow/git/index.html b/workflow/git/index.html index 467f01e8..7c47f7aa 100644 --- a/workflow/git/index.html +++ b/workflow/git/index.html @@ -212,7 +212,7 @@ # 推送到远程仓库 git push

使用 git-filter-repo 重写 Git 历史

git-filter-repo 是一个用于重写 Git 历史的工具,相较于 git filter-branch 其执行速度更快且功能更为全面

安装

sh
# macOS
 brew install git-filter-repo

修正提交时间为作者提交时间

在使用 git rebase 并将其推送到远程仓库后,GitHub 上显示的是提交时间而非作者提交时间,导致提交记录无法准确查看

在使用前,建议先备份仓库到本地,以防出现意外情况

  1. 检查远程仓库关联

确保在运行 git filter-branch 之后重新关联远程仓库。运行以下命令检查:

sh
git remote -v
  1. 执行修改
sh
git filter-branch --env-filter 'export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"'
  1. 重新关联远程仓库
sh
git remote add origin <之前的远程仓库地>
  1. 推送到远程仓库

master 分支为例,使用以下命令推送修改:

sh
git push -u origin master --force
- + \ No newline at end of file diff --git a/workflow/html/tricks.html b/workflow/html/tricks.html index bff29c28..dd054fc7 100644 --- a/workflow/html/tricks.html +++ b/workflow/html/tricks.html @@ -32,7 +32,7 @@ <div>手&ensp;&ensp;号: 15912341234</div> <div>电子邮箱: maomao@1996.com</div> </div>
姓  名: 茂茂
手 机 号: 15912341234
电子邮箱: maomao@1996.com
- + \ No newline at end of file diff --git a/workflow/layouts/border/index.html b/workflow/layouts/border/index.html index 8eda7dfd..fd4e3c7a 100644 --- a/workflow/layouts/border/index.html +++ b/workflow/layouts/border/index.html @@ -58,7 +58,7 @@ -webkit-mask-position: -20px -20px; } </style>

相关资料

- + \ No newline at end of file diff --git a/workflow/layouts/effects/text.html b/workflow/layouts/effects/text.html index aa27475f..dbd8d051 100644 --- a/workflow/layouts/effects/text.html +++ b/workflow/layouts/effects/text.html @@ -73,7 +73,7 @@ } } </style> - + \ No newline at end of file diff --git a/workflow/layouts/progress/index.html b/workflow/layouts/progress/index.html index 7bd5c8b3..0079653a 100644 --- a/workflow/layouts/progress/index.html +++ b/workflow/layouts/progress/index.html @@ -83,7 +83,7 @@ -webkit-mask-composite: source-out; } </style>

相关资料

- + \ No newline at end of file diff --git a/workflow/library/csv.html b/workflow/library/csv.html index cebf24d5..06281ff5 100644 --- a/workflow/library/csv.html +++ b/workflow/library/csv.html @@ -44,7 +44,7 @@ const csvData = stringify(data) fs.writeFile('./file.csv', csvData) - + \ No newline at end of file diff --git a/workflow/library/dayjs.html b/workflow/library/dayjs.html index 8afc06f1..041a32b8 100644 --- a/workflow/library/dayjs.html +++ b/workflow/library/dayjs.html @@ -13,7 +13,7 @@ - + @@ -110,7 +110,7 @@ <span>{{ count.milliseconds() }}</span> </div> </div> -</template>

优点

缺点

当需求场景超出 Day.js 对象的 format 方法的能力时(即不是标准的年月日时分秒格式)需要自己实现格式化函数

常用预设范围

常用于 antdRangePicker 组件

js
import dayjs from 'dayjs'
+</template>

优点

缺点

当需求场景超出 Day.js 对象的 format 方法的能力时(即不是标准的年月日时分秒格式)需要自己实现格式化函数

常用预设范围

常用于 antdRangePicker 组件

js
import dayjs from 'dayjs'
 
 // 获取当前的时间
 const now = dayjs()
@@ -183,7 +183,7 @@
   近180天: [now.subtract(180, 'day'), now],
   近一年: [now.subtract(1, 'year'), now],
 }

注意点

- + \ No newline at end of file diff --git a/workflow/library/gsap.html b/workflow/library/gsap.html index 988dd9c1..43378cbc 100644 --- a/workflow/library/gsap.html +++ b/workflow/library/gsap.html @@ -42,7 +42,7 @@ }) gsap.ticker.lagSmoothing(0) - + \ No newline at end of file diff --git a/workflow/library/tailwindcss.html b/workflow/library/tailwindcss.html index 900e43ec..9b9ee210 100644 --- a/workflow/library/tailwindcss.html +++ b/workflow/library/tailwindcss.html @@ -117,7 +117,7 @@ expect(css).toBe(expected.trim()) }) })

运行测试

sh
pnpm test
- + \ No newline at end of file diff --git a/workflow/node/npm.html b/workflow/node/npm.html index cd0f3a16..733eba66 100644 --- a/workflow/node/npm.html +++ b/workflow/node/npm.html @@ -81,7 +81,7 @@ # 在浏览器中打开指定 npm 包的 GitHub issues npm bugs [package-name]

脚本命令相关

执行顺序:并行执行 &,继发执行 &&

例 1:npm run script1.js & npm run script2.js

例 2:npm run script1.js && npm run script2.js

获取当前正在运行的脚本名称 process.env.npm_lifecycle_event

- + \ No newline at end of file diff --git a/workflow/sass/index.html b/workflow/sass/index.html index 2bfbcf83..b9768fb4 100644 --- a/workflow/sass/index.html +++ b/workflow/sass/index.html @@ -129,7 +129,7 @@ } @return $result; } - + \ No newline at end of file diff --git a/workflow/style-guide.html b/workflow/style-guide.html index 2c5e7088..58e5a566 100644 --- a/workflow/style-guide.html +++ b/workflow/style-guide.html @@ -117,7 +117,7 @@ npm pkg set prettier='@femm/prettier' # OR echo "module.exports = require('@femm/prettier')" > .prettierrc.cjs - + \ No newline at end of file diff --git a/workflow/terminal/shell.html b/workflow/terminal/shell.html index fd59a293..5d16ec0f 100644 --- a/workflow/terminal/shell.html +++ b/workflow/terminal/shell.html @@ -78,7 +78,7 @@ # 移动目录到指定目录 mv ./test ./test1

TIP

常用参数说明

- + \ No newline at end of file diff --git a/workflow/terminal/toolkit.html b/workflow/terminal/toolkit.html index 91d28ee6..7865d26d 100644 --- a/workflow/terminal/toolkit.html +++ b/workflow/terminal/toolkit.html @@ -292,7 +292,7 @@ # 查看进程状态 pm2 monit

pm2 | Github

- + \ No newline at end of file diff --git a/workflow/terminal/zsh.html b/workflow/terminal/zsh.html index d785c286..adb7df11 100644 --- a/workflow/terminal/zsh.html +++ b/workflow/terminal/zsh.html @@ -12,7 +12,7 @@ - + @@ -60,7 +60,7 @@ plugins=(其他插件 z) # 使配置生效 -source ~/.zshrc

z | Github

fast-syntax-highlighting

终端语法高亮显示

安装

sh
# 在 ~/.zshrc 中配置
+source ~/.zshrc

z | Github

fast-syntax-highlighting

终端语法高亮显示

安装

sh
# 在 ~/.zshrc 中配置
 zinit light zdharma-continuum/fast-syntax-highlighting
 
 # 使配置生效
@@ -71,7 +71,7 @@
 plugins=(其他插件 fast-syntax-highlighting)
 
 # 使配置生效
-source ~/.zshrc

Fast Syntax Highlighting | Github

zsh-autosuggestions

根据您的历史记录和完成情况建议您键入的命令

安装

sh
# 在 ~/.zshrc 中配置
+source ~/.zshrc

Fast Syntax Highlighting | Github

zsh-autosuggestions

根据您的历史记录和完成情况建议您键入的命令

安装

sh
# 在 ~/.zshrc 中配置
 zinit ice lucid wait="0" atload="_zsh_autosuggest_start"
 zinit light zsh-users/zsh-autosuggestions
 
@@ -83,7 +83,7 @@
 plugins=(其他插件 zsh-autosuggestions)
 
 # 使配置生效
-source ~/.zshrc

zsh-autosuggestions | Github

zsh 主题

powerlevel10k

安装

sh
# 在 ~/.zshrc 中配置
+source ~/.zshrc

zsh-autosuggestions | Github

zsh 主题

powerlevel10k

安装

sh
# 在 ~/.zshrc 中配置
 zinit ice depth=1
 zinit light romkatv/powerlevel10k
 
@@ -101,7 +101,7 @@
 # 比如显示当前使用的 node 版本
 
 # 使配置生效
-source ~/.zshrc

常用配置

具体可参考 —— 茂茂的 zsh 配置文件

sh
#--------------------------------------------------#
+source ~/.zshrc

常用配置

具体可参考 —— 茂茂的 zsh 配置文件

sh
#--------------------------------------------------#
 # 加载 p10k 主题
 #--------------------------------------------------#
 zinit ice depth=1
@@ -236,7 +236,7 @@
     fi
   fi
 fi

代理相关说明

同时设置大小写的环境变量来保证兼容性(因为有的应用读取的是大写的环境变量,而有的应用读取的是小写的环境变量)

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/workflow/utils/library.html b/workflow/utils/library.html index d04e1291..d00e08be 100644 --- a/workflow/utils/library.html +++ b/workflow/utils/library.html @@ -28,7 +28,7 @@
Skip to content

鼓励作者:欢迎 star 或打赏犒劳

常用工具库整理

收集个人使用过或遇到的类库,按照类别进行分类,方便查找(不定期更新)

工具库

时间处理

请求处理

精度处理

字符串文本处理

动画

特效

本地存储

滚动处理

事件处理

媒体处理

音视频处理

文件处理

版本号处理

数据校验

编辑器

Markdown

代码高亮

轮播

表单处理

表格

拖放

用户体验

评论系统

开发调试

编译&构建&打包

Webpack 相关

解析相关

自动化工具

lint / 格式化相关

相关辅助工具

CLI 工具

命令行输出美化

站点生成器

如有转载或 CV 的请标注本站原文地址

- + \ No newline at end of file diff --git a/workflow/utils/regexp.html b/workflow/utils/regexp.html index a55428e2..ed66439a 100644 --- a/workflow/utils/regexp.html +++ b/workflow/utils/regexp.html @@ -49,7 +49,7 @@ /* 以非单词边界匹配 */ '5201314 5201314'.replace(/\B(?=(\d{3})+\b)/g, ',') // '5,201,314 5,201,314' - + \ No newline at end of file diff --git a/workflow/utils/snippets.html b/workflow/utils/snippets.html index fe0e1047..8deb000e 100644 --- a/workflow/utils/snippets.html +++ b/workflow/utils/snippets.html @@ -175,7 +175,7 @@ gender, } } - + \ No newline at end of file diff --git a/workflow/vue/index.html b/workflow/vue/index.html index d648628b..97c12a17 100644 --- a/workflow/vue/index.html +++ b/workflow/vue/index.html @@ -48,7 +48,7 @@ } } </script>

替换 debounce 过滤器 | Vue.js 官方文档

- + \ No newline at end of file