diff --git a/404.html b/404.html index 8b00d70d38..cb20b19bb1 100644 --- a/404.html +++ b/404.html @@ -33,14 +33,14 @@ - +
- + \ No newline at end of file diff --git a/assets/cn_index.md.DRjzDfRD.js b/assets/cn_index.md.C-Prq36L.js similarity index 93% rename from assets/cn_index.md.DRjzDfRD.js rename to assets/cn_index.md.C-Prq36L.js index 6d1c71601e..fff2cfc399 100644 --- a/assets/cn_index.md.DRjzDfRD.js +++ b/assets/cn_index.md.C-Prq36L.js @@ -1 +1 @@ -import{_ as t,o as e,c as a}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Home","description":"","frontmatter":{"layout":"home","title":"Home","hero":{"name":"ran","text":"风起于青萍之末","tagline":"A ship in harbor is safe, but that is not what ships are built for.","image":{"src":"/home.svg","alt":"logo"},"actions":[{"theme":"alt","text":"更多详情","link":"https://github.com/chaxus/ran"},{"theme":"alt","text":"访问我的 GitHub","link":"https://github.com/chaxus/ran"}]},"features":[{"icon":"⚡️","title":"记录","details":"每段旅程都有终点"},{"icon":"🛠️","title":"解决","details":"无法衡量,无法改进"},{"icon":"🖖","title":"分享","details":"一个人可以走得很快,一群人可以走的很远"}]},"headers":[],"relativePath":"cn/index.md","filePath":"cn/index.md","lastUpdated":1728828157000}'),i={name:"cn/index.md"};function n(o,s,r,c,l,h){return e(),a("div")}const p=t(i,[["render",n]]);export{m as __pageData,p as default}; +import{_ as t,o as e,c as a}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Home","description":"","frontmatter":{"layout":"home","title":"Home","hero":{"name":"ran","text":"风起于青萍之末","tagline":"A ship in harbor is safe, but that is not what ships are built for.","image":{"src":"/home.svg","alt":"logo"},"actions":[{"theme":"alt","text":"更多详情","link":"https://github.com/chaxus/ran"},{"theme":"alt","text":"访问我的 GitHub","link":"https://github.com/chaxus/ran"}]},"features":[{"icon":"⚡️","title":"记录","details":"每段旅程都有终点"},{"icon":"🛠️","title":"解决","details":"无法衡量,无法改进"},{"icon":"🖖","title":"分享","details":"一个人可以走得很快,一群人可以走的很远"}]},"headers":[],"relativePath":"cn/index.md","filePath":"cn/index.md","lastUpdated":1728921295000}'),i={name:"cn/index.md"};function n(o,s,r,c,l,h){return e(),a("div")}const p=t(i,[["render",n]]);export{m as __pageData,p as default}; diff --git a/assets/cn_index.md.DRjzDfRD.lean.js b/assets/cn_index.md.C-Prq36L.lean.js similarity index 93% rename from assets/cn_index.md.DRjzDfRD.lean.js rename to assets/cn_index.md.C-Prq36L.lean.js index 6d1c71601e..fff2cfc399 100644 --- a/assets/cn_index.md.DRjzDfRD.lean.js +++ b/assets/cn_index.md.C-Prq36L.lean.js @@ -1 +1 @@ -import{_ as t,o as e,c as a}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Home","description":"","frontmatter":{"layout":"home","title":"Home","hero":{"name":"ran","text":"风起于青萍之末","tagline":"A ship in harbor is safe, but that is not what ships are built for.","image":{"src":"/home.svg","alt":"logo"},"actions":[{"theme":"alt","text":"更多详情","link":"https://github.com/chaxus/ran"},{"theme":"alt","text":"访问我的 GitHub","link":"https://github.com/chaxus/ran"}]},"features":[{"icon":"⚡️","title":"记录","details":"每段旅程都有终点"},{"icon":"🛠️","title":"解决","details":"无法衡量,无法改进"},{"icon":"🖖","title":"分享","details":"一个人可以走得很快,一群人可以走的很远"}]},"headers":[],"relativePath":"cn/index.md","filePath":"cn/index.md","lastUpdated":1728828157000}'),i={name:"cn/index.md"};function n(o,s,r,c,l,h){return e(),a("div")}const p=t(i,[["render",n]]);export{m as __pageData,p as default}; +import{_ as t,o as e,c as a}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Home","description":"","frontmatter":{"layout":"home","title":"Home","hero":{"name":"ran","text":"风起于青萍之末","tagline":"A ship in harbor is safe, but that is not what ships are built for.","image":{"src":"/home.svg","alt":"logo"},"actions":[{"theme":"alt","text":"更多详情","link":"https://github.com/chaxus/ran"},{"theme":"alt","text":"访问我的 GitHub","link":"https://github.com/chaxus/ran"}]},"features":[{"icon":"⚡️","title":"记录","details":"每段旅程都有终点"},{"icon":"🛠️","title":"解决","details":"无法衡量,无法改进"},{"icon":"🖖","title":"分享","details":"一个人可以走得很快,一群人可以走的很远"}]},"headers":[],"relativePath":"cn/index.md","filePath":"cn/index.md","lastUpdated":1728921295000}'),i={name:"cn/index.md"};function n(o,s,r,c,l,h){return e(),a("div")}const p=t(i,[["render",n]]);export{m as __pageData,p as default}; diff --git a/assets/cn_src_article_astParse_tokenizer.md._qy1-yRL.js b/assets/cn_src_article_astParse_tokenizer.md.X9WaN6nP.js similarity index 99% rename from assets/cn_src_article_astParse_tokenizer.md._qy1-yRL.js rename to assets/cn_src_article_astParse_tokenizer.md.X9WaN6nP.js index 62d9ab7a15..a88a8003e8 100644 --- a/assets/cn_src_article_astParse_tokenizer.md._qy1-yRL.js +++ b/assets/cn_src_article_astParse_tokenizer.md.X9WaN6nP.js @@ -1,4 +1,4 @@ -import{_ as a,a as n,b as h,c as p,d as k,e as t,f as l,g as e,h as d,i as E,j as r,k as g,l as c,m as i,n as y}from"./chunks/extra.Cu56q3CZ.js";import{_ as o,o as F,c as C,a3 as A}from"./chunks/framework.BYE6xntm.js";const S=JSON.parse('{"title":"Abstract Syntax Tree","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/astParse/tokenizer.md","filePath":"cn/src/article/astParse/tokenizer.md","lastUpdated":1728828157000}'),u={name:"cn/src/article/astParse/tokenizer.md"};function D(B,s,m,b,v,T){return F(),C("div",{"data-pagefind-body":!0},s[0]||(s[0]=[A('

Abstract Syntax Tree

一.(abstract syntax tree)抽象语法树的作用

源码是一串按照语法格式来组织的字符串,人能够认识,但是计算机并不认识,想让计算机认识就要转成一种数据结构,通过不同的对象来保存不同的数据,并且按照依赖关系组织起来,这种数据结构就是抽象语法树(abstract syntax tree)。

之所以叫“抽象”语法树是因为数据结构中省略掉了一些无具体意义的分隔符比如 ; { } 等。

有了 AST,计算机就能理解源码字符串的意思,而理解是能够转换的前提,所以编译的第一步需要把源码 parseAST

转成 AST 之后就可以通过修改 AST ,分析 AST 的方式来修改和分析代码,比如 babel 就通过这种方式进行代码的转换,比如 rollupTree Shaking ,就是通过分析 AST的 导入导出语法,从而分析出没有使用的代码,进行去除。

二。常见的 AST 节点

常见的 AST 节点 AST 是对源码的抽象,字面量、标识符、表达式、语句、模块语法、class 语法都有各自的 AST。

我们分别来了解一下:

Literal

Literal 是字面量的意思,比如 let name = 'value'中,'value'就是一个字符串字面量 StringLiteral,相应的还有数字字面量 NumericLiteral,布尔字面量 BooleanLiteral,字符串字面量 StringLiteral,正则表达式字面量 RegExpLiteral 等。

下面这些字面量都有对应的 Literal 节点:

代码中的字面量很多,babel 就是通过 xxLiteral 来抽象这部分内容的。

Identifier

Identifer 是标识符的意思,变量名、属性名、参数名等各种声明和引用的名字,都是Identifer

我们知道, JS 中的标识符只能包含字母或数字或下划线 (“_”) 或美元符号 (“$”) ,且不能以数字开头。这是 Identifier 的词法特点。

尝试分析一下,下面这一段代码里面有多少 Identifier 呢?

js
const name = 'value';
+import{_ as a,a as n,b as h,c as p,d as k,e as t,f as l,g as e,h as d,i as E,j as r,k as g,l as c,m as i,n as y}from"./chunks/extra.Cu56q3CZ.js";import{_ as o,o as F,c as C,a3 as A}from"./chunks/framework.BYE6xntm.js";const S=JSON.parse('{"title":"Abstract Syntax Tree","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/astParse/tokenizer.md","filePath":"cn/src/article/astParse/tokenizer.md","lastUpdated":1728921295000}'),u={name:"cn/src/article/astParse/tokenizer.md"};function D(B,s,m,b,v,T){return F(),C("div",{"data-pagefind-body":!0},s[0]||(s[0]=[A('

Abstract Syntax Tree

一.(abstract syntax tree)抽象语法树的作用

源码是一串按照语法格式来组织的字符串,人能够认识,但是计算机并不认识,想让计算机认识就要转成一种数据结构,通过不同的对象来保存不同的数据,并且按照依赖关系组织起来,这种数据结构就是抽象语法树(abstract syntax tree)。

之所以叫“抽象”语法树是因为数据结构中省略掉了一些无具体意义的分隔符比如 ; { } 等。

有了 AST,计算机就能理解源码字符串的意思,而理解是能够转换的前提,所以编译的第一步需要把源码 parseAST

转成 AST 之后就可以通过修改 AST ,分析 AST 的方式来修改和分析代码,比如 babel 就通过这种方式进行代码的转换,比如 rollupTree Shaking ,就是通过分析 AST的 导入导出语法,从而分析出没有使用的代码,进行去除。

二。常见的 AST 节点

常见的 AST 节点 AST 是对源码的抽象,字面量、标识符、表达式、语句、模块语法、class 语法都有各自的 AST。

我们分别来了解一下:

Literal

Literal 是字面量的意思,比如 let name = 'value'中,'value'就是一个字符串字面量 StringLiteral,相应的还有数字字面量 NumericLiteral,布尔字面量 BooleanLiteral,字符串字面量 StringLiteral,正则表达式字面量 RegExpLiteral 等。

下面这些字面量都有对应的 Literal 节点:

代码中的字面量很多,babel 就是通过 xxLiteral 来抽象这部分内容的。

Identifier

Identifer 是标识符的意思,变量名、属性名、参数名等各种声明和引用的名字,都是Identifer

我们知道, JS 中的标识符只能包含字母或数字或下划线 (“_”) 或美元符号 (“$”) ,且不能以数字开头。这是 Identifier 的词法特点。

尝试分析一下,下面这一段代码里面有多少 Identifier 呢?

js
const name = 'value';
 
 function say(name) {
   console.log(name);
diff --git a/assets/cn_src_article_astParse_tokenizer.md._qy1-yRL.lean.js b/assets/cn_src_article_astParse_tokenizer.md.X9WaN6nP.lean.js
similarity index 99%
rename from assets/cn_src_article_astParse_tokenizer.md._qy1-yRL.lean.js
rename to assets/cn_src_article_astParse_tokenizer.md.X9WaN6nP.lean.js
index 62d9ab7a15..a88a8003e8 100644
--- a/assets/cn_src_article_astParse_tokenizer.md._qy1-yRL.lean.js
+++ b/assets/cn_src_article_astParse_tokenizer.md.X9WaN6nP.lean.js
@@ -1,4 +1,4 @@
-import{_ as a,a as n,b as h,c as p,d as k,e as t,f as l,g as e,h as d,i as E,j as r,k as g,l as c,m as i,n as y}from"./chunks/extra.Cu56q3CZ.js";import{_ as o,o as F,c as C,a3 as A}from"./chunks/framework.BYE6xntm.js";const S=JSON.parse('{"title":"Abstract Syntax Tree","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/astParse/tokenizer.md","filePath":"cn/src/article/astParse/tokenizer.md","lastUpdated":1728828157000}'),u={name:"cn/src/article/astParse/tokenizer.md"};function D(B,s,m,b,v,T){return F(),C("div",{"data-pagefind-body":!0},s[0]||(s[0]=[A('

Abstract Syntax Tree

一.(abstract syntax tree)抽象语法树的作用

源码是一串按照语法格式来组织的字符串,人能够认识,但是计算机并不认识,想让计算机认识就要转成一种数据结构,通过不同的对象来保存不同的数据,并且按照依赖关系组织起来,这种数据结构就是抽象语法树(abstract syntax tree)。

之所以叫“抽象”语法树是因为数据结构中省略掉了一些无具体意义的分隔符比如 ; { } 等。

有了 AST,计算机就能理解源码字符串的意思,而理解是能够转换的前提,所以编译的第一步需要把源码 parseAST

转成 AST 之后就可以通过修改 AST ,分析 AST 的方式来修改和分析代码,比如 babel 就通过这种方式进行代码的转换,比如 rollupTree Shaking ,就是通过分析 AST的 导入导出语法,从而分析出没有使用的代码,进行去除。

二。常见的 AST 节点

常见的 AST 节点 AST 是对源码的抽象,字面量、标识符、表达式、语句、模块语法、class 语法都有各自的 AST。

我们分别来了解一下:

Literal

Literal 是字面量的意思,比如 let name = 'value'中,'value'就是一个字符串字面量 StringLiteral,相应的还有数字字面量 NumericLiteral,布尔字面量 BooleanLiteral,字符串字面量 StringLiteral,正则表达式字面量 RegExpLiteral 等。

下面这些字面量都有对应的 Literal 节点:

代码中的字面量很多,babel 就是通过 xxLiteral 来抽象这部分内容的。

Identifier

Identifer 是标识符的意思,变量名、属性名、参数名等各种声明和引用的名字,都是Identifer

我们知道, JS 中的标识符只能包含字母或数字或下划线 (“_”) 或美元符号 (“$”) ,且不能以数字开头。这是 Identifier 的词法特点。

尝试分析一下,下面这一段代码里面有多少 Identifier 呢?

js
const name = 'value';
+import{_ as a,a as n,b as h,c as p,d as k,e as t,f as l,g as e,h as d,i as E,j as r,k as g,l as c,m as i,n as y}from"./chunks/extra.Cu56q3CZ.js";import{_ as o,o as F,c as C,a3 as A}from"./chunks/framework.BYE6xntm.js";const S=JSON.parse('{"title":"Abstract Syntax Tree","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/astParse/tokenizer.md","filePath":"cn/src/article/astParse/tokenizer.md","lastUpdated":1728921295000}'),u={name:"cn/src/article/astParse/tokenizer.md"};function D(B,s,m,b,v,T){return F(),C("div",{"data-pagefind-body":!0},s[0]||(s[0]=[A('

Abstract Syntax Tree

一.(abstract syntax tree)抽象语法树的作用

源码是一串按照语法格式来组织的字符串,人能够认识,但是计算机并不认识,想让计算机认识就要转成一种数据结构,通过不同的对象来保存不同的数据,并且按照依赖关系组织起来,这种数据结构就是抽象语法树(abstract syntax tree)。

之所以叫“抽象”语法树是因为数据结构中省略掉了一些无具体意义的分隔符比如 ; { } 等。

有了 AST,计算机就能理解源码字符串的意思,而理解是能够转换的前提,所以编译的第一步需要把源码 parseAST

转成 AST 之后就可以通过修改 AST ,分析 AST 的方式来修改和分析代码,比如 babel 就通过这种方式进行代码的转换,比如 rollupTree Shaking ,就是通过分析 AST的 导入导出语法,从而分析出没有使用的代码,进行去除。

二。常见的 AST 节点

常见的 AST 节点 AST 是对源码的抽象,字面量、标识符、表达式、语句、模块语法、class 语法都有各自的 AST。

我们分别来了解一下:

Literal

Literal 是字面量的意思,比如 let name = 'value'中,'value'就是一个字符串字面量 StringLiteral,相应的还有数字字面量 NumericLiteral,布尔字面量 BooleanLiteral,字符串字面量 StringLiteral,正则表达式字面量 RegExpLiteral 等。

下面这些字面量都有对应的 Literal 节点:

代码中的字面量很多,babel 就是通过 xxLiteral 来抽象这部分内容的。

Identifier

Identifer 是标识符的意思,变量名、属性名、参数名等各种声明和引用的名字,都是Identifer

我们知道, JS 中的标识符只能包含字母或数字或下划线 (“_”) 或美元符号 (“$”) ,且不能以数字开头。这是 Identifier 的词法特点。

尝试分析一下,下面这一段代码里面有多少 Identifier 呢?

js
const name = 'value';
 
 function say(name) {
   console.log(name);
diff --git a/assets/cn_src_article_babel.md.e4GAuw5X.js b/assets/cn_src_article_babel.md.BRRU23MO.js
similarity index 91%
rename from assets/cn_src_article_babel.md.e4GAuw5X.js
rename to assets/cn_src_article_babel.md.BRRU23MO.js
index c122c7adbc..fa8599994e 100644
--- a/assets/cn_src_article_babel.md.e4GAuw5X.js
+++ b/assets/cn_src_article_babel.md.BRRU23MO.js
@@ -1 +1 @@
-import{_ as a,o as t,c as l,a3 as r}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Babel","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/babel.md","filePath":"cn/src/article/babel.md","lastUpdated":1728828157000}'),i={name:"cn/src/article/babel.md"};function s(b,e,o,c,p,n){return t(),l("div",{"data-pagefind-body":!0},e[0]||(e[0]=[r('

Babel

babel 核心库主要是:

  • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
  • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
  • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
  • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
  • @babel/code-frame 可以创建友好的报错信息
  • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
  • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。
',3)]))}const u=a(i,[["render",s]]);export{m as __pageData,u as default}; +import{_ as a,o as t,c as l,a3 as r}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Babel","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/babel.md","filePath":"cn/src/article/babel.md","lastUpdated":1728921295000}'),i={name:"cn/src/article/babel.md"};function s(b,e,o,c,p,n){return t(),l("div",{"data-pagefind-body":!0},e[0]||(e[0]=[r('

Babel

babel 核心库主要是:

  • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
  • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
  • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
  • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
  • @babel/code-frame 可以创建友好的报错信息
  • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
  • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。
',3)]))}const u=a(i,[["render",s]]);export{m as __pageData,u as default}; diff --git a/assets/cn_src_article_babel.md.e4GAuw5X.lean.js b/assets/cn_src_article_babel.md.BRRU23MO.lean.js similarity index 91% rename from assets/cn_src_article_babel.md.e4GAuw5X.lean.js rename to assets/cn_src_article_babel.md.BRRU23MO.lean.js index c122c7adbc..fa8599994e 100644 --- a/assets/cn_src_article_babel.md.e4GAuw5X.lean.js +++ b/assets/cn_src_article_babel.md.BRRU23MO.lean.js @@ -1 +1 @@ -import{_ as a,o as t,c as l,a3 as r}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Babel","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/babel.md","filePath":"cn/src/article/babel.md","lastUpdated":1728828157000}'),i={name:"cn/src/article/babel.md"};function s(b,e,o,c,p,n){return t(),l("div",{"data-pagefind-body":!0},e[0]||(e[0]=[r('

Babel

babel 核心库主要是:

  • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
  • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
  • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
  • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
  • @babel/code-frame 可以创建友好的报错信息
  • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
  • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。
',3)]))}const u=a(i,[["render",s]]);export{m as __pageData,u as default}; +import{_ as a,o as t,c as l,a3 as r}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Babel","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/babel.md","filePath":"cn/src/article/babel.md","lastUpdated":1728921295000}'),i={name:"cn/src/article/babel.md"};function s(b,e,o,c,p,n){return t(),l("div",{"data-pagefind-body":!0},e[0]||(e[0]=[r('

Babel

babel 核心库主要是:

  • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
  • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
  • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
  • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
  • @babel/code-frame 可以创建友好的报错信息
  • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
  • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。
',3)]))}const u=a(i,[["render",s]]);export{m as __pageData,u as default}; diff --git a/assets/cn_src_article_bundle.md.CXbozmz-.js b/assets/cn_src_article_bundle.md.OaaTEdt2.js similarity index 94% rename from assets/cn_src_article_bundle.md.CXbozmz-.js rename to assets/cn_src_article_bundle.md.OaaTEdt2.js index a112457ed7..2482d8c773 100644 --- a/assets/cn_src_article_bundle.md.CXbozmz-.js +++ b/assets/cn_src_article_bundle.md.OaaTEdt2.js @@ -1 +1 @@ -import{_ as a,o as n,c as t,j as e,a as r}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"Bundle","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/bundle.md","filePath":"cn/src/article/bundle.md","lastUpdated":1728828157000}'),d={name:"cn/src/article/bundle.md"};function c(s,l,i,o,u,p){return n(),t("div",{"data-pagefind-body":!0},l[0]||(l[0]=[e("h1",{id:"bundle",tabindex:"-1"},[r("Bundle "),e("a",{class:"header-anchor",href:"#bundle","aria-label":'Permalink to "Bundle"'},"​")],-1),e("p",null,"Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:",-1),e("ul",null,[e("li",null,"编译能力"),e("li",null,"插件机制"),e("li",null,"HMR"),e("li",null,"cli 和命令行能力")],-1)]))}const m=a(d,[["render",c]]);export{f as __pageData,m as default}; +import{_ as a,o as n,c as t,j as e,a as r}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"Bundle","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/bundle.md","filePath":"cn/src/article/bundle.md","lastUpdated":1728921295000}'),d={name:"cn/src/article/bundle.md"};function c(s,l,i,o,u,p){return n(),t("div",{"data-pagefind-body":!0},l[0]||(l[0]=[e("h1",{id:"bundle",tabindex:"-1"},[r("Bundle "),e("a",{class:"header-anchor",href:"#bundle","aria-label":'Permalink to "Bundle"'},"​")],-1),e("p",null,"Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:",-1),e("ul",null,[e("li",null,"编译能力"),e("li",null,"插件机制"),e("li",null,"HMR"),e("li",null,"cli 和命令行能力")],-1)]))}const m=a(d,[["render",c]]);export{f as __pageData,m as default}; diff --git a/assets/cn_src_article_bundle.md.CXbozmz-.lean.js b/assets/cn_src_article_bundle.md.OaaTEdt2.lean.js similarity index 94% rename from assets/cn_src_article_bundle.md.CXbozmz-.lean.js rename to assets/cn_src_article_bundle.md.OaaTEdt2.lean.js index a112457ed7..2482d8c773 100644 --- a/assets/cn_src_article_bundle.md.CXbozmz-.lean.js +++ b/assets/cn_src_article_bundle.md.OaaTEdt2.lean.js @@ -1 +1 @@ -import{_ as a,o as n,c as t,j as e,a as r}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"Bundle","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/bundle.md","filePath":"cn/src/article/bundle.md","lastUpdated":1728828157000}'),d={name:"cn/src/article/bundle.md"};function c(s,l,i,o,u,p){return n(),t("div",{"data-pagefind-body":!0},l[0]||(l[0]=[e("h1",{id:"bundle",tabindex:"-1"},[r("Bundle "),e("a",{class:"header-anchor",href:"#bundle","aria-label":'Permalink to "Bundle"'},"​")],-1),e("p",null,"Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:",-1),e("ul",null,[e("li",null,"编译能力"),e("li",null,"插件机制"),e("li",null,"HMR"),e("li",null,"cli 和命令行能力")],-1)]))}const m=a(d,[["render",c]]);export{f as __pageData,m as default}; +import{_ as a,o as n,c as t,j as e,a as r}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"Bundle","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/bundle.md","filePath":"cn/src/article/bundle.md","lastUpdated":1728921295000}'),d={name:"cn/src/article/bundle.md"};function c(s,l,i,o,u,p){return n(),t("div",{"data-pagefind-body":!0},l[0]||(l[0]=[e("h1",{id:"bundle",tabindex:"-1"},[r("Bundle "),e("a",{class:"header-anchor",href:"#bundle","aria-label":'Permalink to "Bundle"'},"​")],-1),e("p",null,"Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:",-1),e("ul",null,[e("li",null,"编译能力"),e("li",null,"插件机制"),e("li",null,"HMR"),e("li",null,"cli 和命令行能力")],-1)]))}const m=a(d,[["render",c]]);export{f as __pageData,m as default}; diff --git a/assets/cn_src_article_designMode.md.DZ98r33q.js b/assets/cn_src_article_designMode.md.DOHuh5Vx.js similarity index 99% rename from assets/cn_src_article_designMode.md.DZ98r33q.js rename to assets/cn_src_article_designMode.md.DOHuh5Vx.js index 591ee734f1..c9a1a5277b 100644 --- a/assets/cn_src_article_designMode.md.DZ98r33q.js +++ b/assets/cn_src_article_designMode.md.DOHuh5Vx.js @@ -1,4 +1,4 @@ -import{_ as i,a,b as n,c as h,d as l,e as k,f as p,g as t,h as e,i as E,j as r,k as d,l as g,m as y,n as F,o as c,p as o,q as C,r as B,s as A,t as D,u,v as b,w as m,x as v,y as f,z as x,A as _,B as q}from"./chunks/访问者._0swtoJg.js";import{_ as P,o as w,c as j,a3 as M}from"./chunks/framework.BYE6xntm.js";const W=JSON.parse('{"title":"23 种经典设计模式","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/designMode.md","filePath":"cn/src/article/designMode.md","lastUpdated":1728828157000}'),S={name:"cn/src/article/designMode.md"};function T(L,s,V,I,N,O){return w(),j("div",{"data-pagefind-body":!0},s[0]||(s[0]=[M(`

23 种经典设计模式

设计模式 Design Pattern 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。。

在《设计模式:可复用面向对象软件的基础》一书中所介绍的 23 种经典设计模式,不过设计模式并不仅仅只有这 23 种,随着软件开发行业的发展,越来越多的新模式不断诞生并得以应用。有经验的开发者在学习设计模式可以和过往的经验互相印证,更容易理解这些设计模式。

设计模式一般包含模式名称、问题、目的、解决方案、效果等组成要素。问题描述了应该在何时使用模式,它包含了设计中存在的问题以及问题存在的原因。解决方案描述了一个设计模式的组成成分,以及这些组成成分之间的相互关系,各自的职责和协作方式,通常解决方案通过 UML 类图和核心代码来进行描述。效果描述了模式的优缺点以及在使用模式时应权衡的问题。

为什么要学习设计模式:

  • 设计模式来源众多专家的经验和智慧,它们是从许多优秀的软件系统中总结出的成功的、能够实现可维护性复用的设计方案,使用这些方案将可以让我们避免做一些重复性的工作

  • 设计模式提供了一套通用的设计词汇和一种通用的形式来方便开发人员之间沟通和交流,使得设计方案更加通俗易懂

  • 大部分设计模式都兼顾了系统的可重用性和可扩展性,这使得我们可以更好地重用一些已有的设计方案、功能模块甚至一个完整的软件系统,避免我们经常做一些重复的设计、编写一些重复的代码

  • 合理使用设计模式并对设计模式的使用情况进行文档化,将有助于别人更快地理解系统

  • 学习设计模式将有助于初学者更加深入地理解面向对象思想

储备知识

  • 抽象类:一般抽象类都是作为基类,比如说「电脑」就可以作为一个抽象类,根据抽象类派生出「台式电脑」和「笔记本电脑」2 种具体类。一般不对抽象类进行实例化。

  • 组合优于继承:不能滥用继承来拓展功能,配合组合会更灵活。同样拿「电脑」抽象类来举例,如果使用继承,区分不同类型的「电脑」我们可以派生出「台式电脑」和「笔记本电脑」,如果再增加一个维度,根据品牌又能继续细分出「联想台式电脑」、「联想笔记本电脑」、「苹果台式电脑」和「苹果笔记本电脑」等等,如果再增加一个维度继续细分下去,显然继承是无法胜任的。这个时候可以使用继承加组合方式,组合的对象也可以进行抽象化设计:

    ts
    // 品牌
    +import{_ as i,a,b as n,c as h,d as l,e as k,f as p,g as t,h as e,i as E,j as r,k as d,l as g,m as y,n as F,o as c,p as o,q as C,r as B,s as A,t as D,u,v as b,w as m,x as v,y as f,z as x,A as _,B as q}from"./chunks/访问者._0swtoJg.js";import{_ as P,o as w,c as j,a3 as M}from"./chunks/framework.BYE6xntm.js";const W=JSON.parse('{"title":"23 种经典设计模式","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/designMode.md","filePath":"cn/src/article/designMode.md","lastUpdated":1728921295000}'),S={name:"cn/src/article/designMode.md"};function T(L,s,V,I,N,O){return w(),j("div",{"data-pagefind-body":!0},s[0]||(s[0]=[M(`

    23 种经典设计模式

    设计模式 Design Pattern 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。。

    在《设计模式:可复用面向对象软件的基础》一书中所介绍的 23 种经典设计模式,不过设计模式并不仅仅只有这 23 种,随着软件开发行业的发展,越来越多的新模式不断诞生并得以应用。有经验的开发者在学习设计模式可以和过往的经验互相印证,更容易理解这些设计模式。

    设计模式一般包含模式名称、问题、目的、解决方案、效果等组成要素。问题描述了应该在何时使用模式,它包含了设计中存在的问题以及问题存在的原因。解决方案描述了一个设计模式的组成成分,以及这些组成成分之间的相互关系,各自的职责和协作方式,通常解决方案通过 UML 类图和核心代码来进行描述。效果描述了模式的优缺点以及在使用模式时应权衡的问题。

    为什么要学习设计模式:

    • 设计模式来源众多专家的经验和智慧,它们是从许多优秀的软件系统中总结出的成功的、能够实现可维护性复用的设计方案,使用这些方案将可以让我们避免做一些重复性的工作

    • 设计模式提供了一套通用的设计词汇和一种通用的形式来方便开发人员之间沟通和交流,使得设计方案更加通俗易懂

    • 大部分设计模式都兼顾了系统的可重用性和可扩展性,这使得我们可以更好地重用一些已有的设计方案、功能模块甚至一个完整的软件系统,避免我们经常做一些重复的设计、编写一些重复的代码

    • 合理使用设计模式并对设计模式的使用情况进行文档化,将有助于别人更快地理解系统

    • 学习设计模式将有助于初学者更加深入地理解面向对象思想

    储备知识

    • 抽象类:一般抽象类都是作为基类,比如说「电脑」就可以作为一个抽象类,根据抽象类派生出「台式电脑」和「笔记本电脑」2 种具体类。一般不对抽象类进行实例化。

    • 组合优于继承:不能滥用继承来拓展功能,配合组合会更灵活。同样拿「电脑」抽象类来举例,如果使用继承,区分不同类型的「电脑」我们可以派生出「台式电脑」和「笔记本电脑」,如果再增加一个维度,根据品牌又能继续细分出「联想台式电脑」、「联想笔记本电脑」、「苹果台式电脑」和「苹果笔记本电脑」等等,如果再增加一个维度继续细分下去,显然继承是无法胜任的。这个时候可以使用继承加组合方式,组合的对象也可以进行抽象化设计:

      ts
      // 品牌
       interface Brand {
         // ...
       }
      diff --git a/assets/cn_src_article_designMode.md.DZ98r33q.lean.js b/assets/cn_src_article_designMode.md.DOHuh5Vx.lean.js
      similarity index 99%
      rename from assets/cn_src_article_designMode.md.DZ98r33q.lean.js
      rename to assets/cn_src_article_designMode.md.DOHuh5Vx.lean.js
      index 591ee734f1..c9a1a5277b 100644
      --- a/assets/cn_src_article_designMode.md.DZ98r33q.lean.js
      +++ b/assets/cn_src_article_designMode.md.DOHuh5Vx.lean.js
      @@ -1,4 +1,4 @@
      -import{_ as i,a,b as n,c as h,d as l,e as k,f as p,g as t,h as e,i as E,j as r,k as d,l as g,m as y,n as F,o as c,p as o,q as C,r as B,s as A,t as D,u,v as b,w as m,x as v,y as f,z as x,A as _,B as q}from"./chunks/访问者._0swtoJg.js";import{_ as P,o as w,c as j,a3 as M}from"./chunks/framework.BYE6xntm.js";const W=JSON.parse('{"title":"23 种经典设计模式","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/designMode.md","filePath":"cn/src/article/designMode.md","lastUpdated":1728828157000}'),S={name:"cn/src/article/designMode.md"};function T(L,s,V,I,N,O){return w(),j("div",{"data-pagefind-body":!0},s[0]||(s[0]=[M(`

      23 种经典设计模式

      设计模式 Design Pattern 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。。

      在《设计模式:可复用面向对象软件的基础》一书中所介绍的 23 种经典设计模式,不过设计模式并不仅仅只有这 23 种,随着软件开发行业的发展,越来越多的新模式不断诞生并得以应用。有经验的开发者在学习设计模式可以和过往的经验互相印证,更容易理解这些设计模式。

      设计模式一般包含模式名称、问题、目的、解决方案、效果等组成要素。问题描述了应该在何时使用模式,它包含了设计中存在的问题以及问题存在的原因。解决方案描述了一个设计模式的组成成分,以及这些组成成分之间的相互关系,各自的职责和协作方式,通常解决方案通过 UML 类图和核心代码来进行描述。效果描述了模式的优缺点以及在使用模式时应权衡的问题。

      为什么要学习设计模式:

      • 设计模式来源众多专家的经验和智慧,它们是从许多优秀的软件系统中总结出的成功的、能够实现可维护性复用的设计方案,使用这些方案将可以让我们避免做一些重复性的工作

      • 设计模式提供了一套通用的设计词汇和一种通用的形式来方便开发人员之间沟通和交流,使得设计方案更加通俗易懂

      • 大部分设计模式都兼顾了系统的可重用性和可扩展性,这使得我们可以更好地重用一些已有的设计方案、功能模块甚至一个完整的软件系统,避免我们经常做一些重复的设计、编写一些重复的代码

      • 合理使用设计模式并对设计模式的使用情况进行文档化,将有助于别人更快地理解系统

      • 学习设计模式将有助于初学者更加深入地理解面向对象思想

      储备知识

      • 抽象类:一般抽象类都是作为基类,比如说「电脑」就可以作为一个抽象类,根据抽象类派生出「台式电脑」和「笔记本电脑」2 种具体类。一般不对抽象类进行实例化。

      • 组合优于继承:不能滥用继承来拓展功能,配合组合会更灵活。同样拿「电脑」抽象类来举例,如果使用继承,区分不同类型的「电脑」我们可以派生出「台式电脑」和「笔记本电脑」,如果再增加一个维度,根据品牌又能继续细分出「联想台式电脑」、「联想笔记本电脑」、「苹果台式电脑」和「苹果笔记本电脑」等等,如果再增加一个维度继续细分下去,显然继承是无法胜任的。这个时候可以使用继承加组合方式,组合的对象也可以进行抽象化设计:

        ts
        // 品牌
        +import{_ as i,a,b as n,c as h,d as l,e as k,f as p,g as t,h as e,i as E,j as r,k as d,l as g,m as y,n as F,o as c,p as o,q as C,r as B,s as A,t as D,u,v as b,w as m,x as v,y as f,z as x,A as _,B as q}from"./chunks/访问者._0swtoJg.js";import{_ as P,o as w,c as j,a3 as M}from"./chunks/framework.BYE6xntm.js";const W=JSON.parse('{"title":"23 种经典设计模式","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/designMode.md","filePath":"cn/src/article/designMode.md","lastUpdated":1728921295000}'),S={name:"cn/src/article/designMode.md"};function T(L,s,V,I,N,O){return w(),j("div",{"data-pagefind-body":!0},s[0]||(s[0]=[M(`

        23 种经典设计模式

        设计模式 Design Pattern 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。。

        在《设计模式:可复用面向对象软件的基础》一书中所介绍的 23 种经典设计模式,不过设计模式并不仅仅只有这 23 种,随着软件开发行业的发展,越来越多的新模式不断诞生并得以应用。有经验的开发者在学习设计模式可以和过往的经验互相印证,更容易理解这些设计模式。

        设计模式一般包含模式名称、问题、目的、解决方案、效果等组成要素。问题描述了应该在何时使用模式,它包含了设计中存在的问题以及问题存在的原因。解决方案描述了一个设计模式的组成成分,以及这些组成成分之间的相互关系,各自的职责和协作方式,通常解决方案通过 UML 类图和核心代码来进行描述。效果描述了模式的优缺点以及在使用模式时应权衡的问题。

        为什么要学习设计模式:

        • 设计模式来源众多专家的经验和智慧,它们是从许多优秀的软件系统中总结出的成功的、能够实现可维护性复用的设计方案,使用这些方案将可以让我们避免做一些重复性的工作

        • 设计模式提供了一套通用的设计词汇和一种通用的形式来方便开发人员之间沟通和交流,使得设计方案更加通俗易懂

        • 大部分设计模式都兼顾了系统的可重用性和可扩展性,这使得我们可以更好地重用一些已有的设计方案、功能模块甚至一个完整的软件系统,避免我们经常做一些重复的设计、编写一些重复的代码

        • 合理使用设计模式并对设计模式的使用情况进行文档化,将有助于别人更快地理解系统

        • 学习设计模式将有助于初学者更加深入地理解面向对象思想

        储备知识

        • 抽象类:一般抽象类都是作为基类,比如说「电脑」就可以作为一个抽象类,根据抽象类派生出「台式电脑」和「笔记本电脑」2 种具体类。一般不对抽象类进行实例化。

        • 组合优于继承:不能滥用继承来拓展功能,配合组合会更灵活。同样拿「电脑」抽象类来举例,如果使用继承,区分不同类型的「电脑」我们可以派生出「台式电脑」和「笔记本电脑」,如果再增加一个维度,根据品牌又能继续细分出「联想台式电脑」、「联想笔记本电脑」、「苹果台式电脑」和「苹果笔记本电脑」等等,如果再增加一个维度继续细分下去,显然继承是无法胜任的。这个时候可以使用继承加组合方式,组合的对象也可以进行抽象化设计:

          ts
          // 品牌
           interface Brand {
             // ...
           }
          diff --git a/assets/cn_src_article_docPreview.md.to4R_V9b.js b/assets/cn_src_article_docPreview.md.BriOMnC6.js
          similarity index 99%
          rename from assets/cn_src_article_docPreview.md.to4R_V9b.js
          rename to assets/cn_src_article_docPreview.md.BriOMnC6.js
          index c88d7acb68..724129a8dc 100644
          --- a/assets/cn_src_article_docPreview.md.to4R_V9b.js
          +++ b/assets/cn_src_article_docPreview.md.BriOMnC6.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const t="/ran/assets/ms_ppt.C2zYd_IC.webp",p="/ran/assets/ms_excel.CJXFi2bf.webp",l="/ran/assets/ms_word.3k-0mjp0.webp",k="/ran/assets/ms_file_not.DgOrkG3n.webp",e="/ran/assets/ms_answer.Cgv6ylFF.webp",r="/ran/assets/ms_answer_2.D-D9H1v0.webp",E="/ran/assets/google_doc_view.BknjnOKw.webp",d="/ran/assets/ali_doc.CYo30EHy.webp",g="/ran/assets/xdoc.CeowcMPq.webp",o="/ran/assets/ow365.CXWyYekS.webp",y="/ran/assets/wps_office.DiET-U8x.webp",c="/ran/assets/wps_office_price.ler9htjh.webp",F="/ran/assets/xml.NyzOyhr4.webp",C="/ran/assets/firefox_pdf.BWQR-ogn.webp",f="/ran/assets/mdn_pdf.DbNmeC8H.webp",u="/ran/assets/kkfile_des.CENUMtpY.webp",A="/ran/assets/kkfile.X1tAqvNa.webp",m="/ran/assets/kkfile_output.DD8iZdbo.webp",B="/ran/assets/kkfile_doc.CPfEUxoD.webp",O=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/docPreview.md","filePath":"cn/src/article/docPreview.md","lastUpdated":1728828157000}'),D={name:"cn/src/article/docPreview.md"};function b(x,s,v,w,_,P){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          最全的 docx,pptx,xlsx(excel),pdf 文件预览方案总结

          最近遇到了文件预览的需求,但一搜索发现,这还不是一个简单的功能。于是又去查询了很多资料,调研了一些方案,也踩了好多坑。最后总结方案如下

          1. 花钱解决 (使用市面上现有的文件预览服务)
            1. 微软
            2. google
            3. 阿里云 IMM
            4. XDOC
            5. Office Web 365
            6. wps 开放平台
          2. 前端方案
            1. pptx 的预览方案
            2. pdf 的预览方案
            3. docx 的预览方案
            4. xlsx(excel) 的预览方案
            5. 前端预览方案总结
          3. 服务端方案
            1. openOffice
            2. kkFileView
            3. onlyOffice

          如果有其他人也遇到了同样的问题,有了这篇文章,希望能更方便的解决。

          基本涵盖了所有解决方案。因此,标题写上 最全 的文件预览方案调研总结,应该不为过吧。

          一:市面上现有的文件预览服务

          1.微软

          docx,pptx,xlsx可以说是office三件套,那自然得看一下 微软官方 提供的文件预览服务。使用方法特别简单,只需要将文件链接,拼接到参数后面即可。

          记得encodeURL

          js
          https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}

          (1).PPTX 预览效果:

          image.png

          • 优点:还原度很高,功能很丰富,可以选择翻页,甚至支持点击播放动画。
          • 缺点:不知道是不是墙的原因,加载稍慢。

          (2).Excel 预览效果:

          image.png

          (3).Doxc 预览效果

          image.png

          (4).PDF 预览效果

          这个我测试没有成功,返回了一个错误,其他人可以试试。

          image.png

          (5).总的来说

          对于docx,pptx,xlsx都有较好的支持,pdf不行。

          还有一个坑点是:这个服务是否稳定,有什么限制,是否收费,都查不到一个定论。在office官方网站上甚至找不到介绍这个东西的地方。

          目前只能找到一个Q&A:https://answers.microsoft.com/en-us/msoffice/forum/all/what-is-the-status-of-viewofficeappslivecom/830fd75c-9b47-43f9-89c9-4303703fd7f6

          微软官方人员回答表示:

          image.png

          翻译翻译,就是:几乎永久使用,没有收费计划,不会存储预览的文件数据,限制文件10MB,建议用于 查看互联网上公开的文件

          但经过某些用户测试发现:

          image.png

          使用了微软的文件预览服务,然后删除了文件地址,仍然可访问,但过一段时间会失效。

          2.Google Drive 查看器

          接入简单,同 Office Web Viewer,只需要把 src 改为https://drive.google.com/viewer?url=${encodeURIComponent(url)}即可。

          限制25MB,支持以下格式:

          image.png

          测试效果,支持docx,pptx,xlsx,pdf预览,但pptx预览的效果不如微软,没有动画效果,样式有小部分会错乱。

          由于某些众所周知的原因,不可用

          3.阿里云 IMM

          官方文档如下:https://help.aliyun.com/document_detail/63273.html

          image.png

          付费使用

          4.XDOC 文档预览

          说了一些大厂的,在介绍一些其他的,需要自行分辨

          官网地址:https://view.xdocin.com/view-xdocin-com_6x5f4x.htm

          image.png

          5.Office Web 365

          需要注意的是,虽然名字很像office,但我们看网页的Copyright可以发现,其实是一个西安的公司,不是微软

          但毕竟也提供了文件预览的服务

          官网地址:https://www.officeweb365.com/

          image.png

          6.WPS 开放平台

          官方地址:https://solution.wps.cn/

          image.png

          付费使用,价格如下:

          image.png

          二:前端处理方案

          1.pptx 的预览方案

          先查一下有没有现成的轮子,目前pptx的开源预览方案能找到的只有这个:https://github.com/g21589/PPTX2HTML。但已经六七年没有更新,也没有维护,笔者使用的时候发现有很多兼容性问题。

          简单来说就是,没有。对于这种情况,我们可以自行解析,主要步骤如下:

          1. 查询pptx的国际标准
          2. 解析pptx文件
          3. 渲染成html或者canvas进行展示

          我们先去找一下pptx的国际标准,官方地址:officeopenxml

          先解释下什么是officeopenxml:

          Office OpenXML,也称为 OpenXML 或 OOXML,是一种基于 XML 的办公文档格式,包括文字处理文档、电子表格、演示文稿以及图表、图表、形状和其他图形材料。该规范由微软开发,并于 2006 年被 ECMA 国际采用为 ECMA-376。第二个版本于 2008 年 12 月发布,第三个版本于 2011 年 6 月发布。该规范已被 ISO 和 IEC 采用为 ISO/IEC 29500。

          虽然 Microsoft 继续支持较旧的二进制格式 (.doc、.xls 和.ppt),但 OOXML 现在是所有 Microsoft Office 文档 (.docx、.xlsx 和.pptx) 的默认格式。

          由此可见,Office OpenXML由微软开发,目前已经是国际标准。接下来我们看一下pptx里面有哪些内容,具体可以看pptx的官方标准:officeopenxml-pptx

          PresentationML 或.pptx 文件是一个zip 文件,其中包含许多“部分”(通常是 UTF-8 或 UTF-16 编码)或 XML 文件。该包还可能包含其他媒体文件,例如图像。该结构根据 OOXML 标准 ECMA-376 第 2 部分中概述的开放打包约定进行组织。

          image.png

          根据国际标准,我们知道,pptx文件本质就是一个zip文件,其中包含许多部分:

          部件的数量和类型将根据演示文稿中的内容而有所不同,但始终会有一个 [Content_Types].xml、一个或多个关系(.rels)部件和一个演示文稿部件(演示文稿.xml),它位于 ppt 文件夹中,用于 Microsoft Powerpoint 文件。通常,还将至少有一个幻灯片部件,以及一张母版幻灯片和一张版式幻灯片,从中形成幻灯片。

          那么js如何读取zip呢?

          找到一个工具:https://www.npmjs.com/package/jszip

          于是我们可以开始尝试解析pptx了。

          ts
          import JSZip from 'jszip';
          +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const t="/ran/assets/ms_ppt.C2zYd_IC.webp",p="/ran/assets/ms_excel.CJXFi2bf.webp",l="/ran/assets/ms_word.3k-0mjp0.webp",k="/ran/assets/ms_file_not.DgOrkG3n.webp",e="/ran/assets/ms_answer.Cgv6ylFF.webp",r="/ran/assets/ms_answer_2.D-D9H1v0.webp",E="/ran/assets/google_doc_view.BknjnOKw.webp",d="/ran/assets/ali_doc.CYo30EHy.webp",g="/ran/assets/xdoc.CeowcMPq.webp",o="/ran/assets/ow365.CXWyYekS.webp",y="/ran/assets/wps_office.DiET-U8x.webp",c="/ran/assets/wps_office_price.ler9htjh.webp",F="/ran/assets/xml.NyzOyhr4.webp",C="/ran/assets/firefox_pdf.BWQR-ogn.webp",f="/ran/assets/mdn_pdf.DbNmeC8H.webp",u="/ran/assets/kkfile_des.CENUMtpY.webp",A="/ran/assets/kkfile.X1tAqvNa.webp",m="/ran/assets/kkfile_output.DD8iZdbo.webp",B="/ran/assets/kkfile_doc.CPfEUxoD.webp",O=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/docPreview.md","filePath":"cn/src/article/docPreview.md","lastUpdated":1728921295000}'),D={name:"cn/src/article/docPreview.md"};function b(x,s,v,w,_,P){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          最全的 docx,pptx,xlsx(excel),pdf 文件预览方案总结

          最近遇到了文件预览的需求,但一搜索发现,这还不是一个简单的功能。于是又去查询了很多资料,调研了一些方案,也踩了好多坑。最后总结方案如下

          1. 花钱解决 (使用市面上现有的文件预览服务)
            1. 微软
            2. google
            3. 阿里云 IMM
            4. XDOC
            5. Office Web 365
            6. wps 开放平台
          2. 前端方案
            1. pptx 的预览方案
            2. pdf 的预览方案
            3. docx 的预览方案
            4. xlsx(excel) 的预览方案
            5. 前端预览方案总结
          3. 服务端方案
            1. openOffice
            2. kkFileView
            3. onlyOffice

          如果有其他人也遇到了同样的问题,有了这篇文章,希望能更方便的解决。

          基本涵盖了所有解决方案。因此,标题写上 最全 的文件预览方案调研总结,应该不为过吧。

          一:市面上现有的文件预览服务

          1.微软

          docx,pptx,xlsx可以说是office三件套,那自然得看一下 微软官方 提供的文件预览服务。使用方法特别简单,只需要将文件链接,拼接到参数后面即可。

          记得encodeURL

          js
          https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}

          (1).PPTX 预览效果:

          image.png

          • 优点:还原度很高,功能很丰富,可以选择翻页,甚至支持点击播放动画。
          • 缺点:不知道是不是墙的原因,加载稍慢。

          (2).Excel 预览效果:

          image.png

          (3).Doxc 预览效果

          image.png

          (4).PDF 预览效果

          这个我测试没有成功,返回了一个错误,其他人可以试试。

          image.png

          (5).总的来说

          对于docx,pptx,xlsx都有较好的支持,pdf不行。

          还有一个坑点是:这个服务是否稳定,有什么限制,是否收费,都查不到一个定论。在office官方网站上甚至找不到介绍这个东西的地方。

          目前只能找到一个Q&A:https://answers.microsoft.com/en-us/msoffice/forum/all/what-is-the-status-of-viewofficeappslivecom/830fd75c-9b47-43f9-89c9-4303703fd7f6

          微软官方人员回答表示:

          image.png

          翻译翻译,就是:几乎永久使用,没有收费计划,不会存储预览的文件数据,限制文件10MB,建议用于 查看互联网上公开的文件

          但经过某些用户测试发现:

          image.png

          使用了微软的文件预览服务,然后删除了文件地址,仍然可访问,但过一段时间会失效。

          2.Google Drive 查看器

          接入简单,同 Office Web Viewer,只需要把 src 改为https://drive.google.com/viewer?url=${encodeURIComponent(url)}即可。

          限制25MB,支持以下格式:

          image.png

          测试效果,支持docx,pptx,xlsx,pdf预览,但pptx预览的效果不如微软,没有动画效果,样式有小部分会错乱。

          由于某些众所周知的原因,不可用

          3.阿里云 IMM

          官方文档如下:https://help.aliyun.com/document_detail/63273.html

          image.png

          付费使用

          4.XDOC 文档预览

          说了一些大厂的,在介绍一些其他的,需要自行分辨

          官网地址:https://view.xdocin.com/view-xdocin-com_6x5f4x.htm

          image.png

          5.Office Web 365

          需要注意的是,虽然名字很像office,但我们看网页的Copyright可以发现,其实是一个西安的公司,不是微软

          但毕竟也提供了文件预览的服务

          官网地址:https://www.officeweb365.com/

          image.png

          6.WPS 开放平台

          官方地址:https://solution.wps.cn/

          image.png

          付费使用,价格如下:

          image.png

          二:前端处理方案

          1.pptx 的预览方案

          先查一下有没有现成的轮子,目前pptx的开源预览方案能找到的只有这个:https://github.com/g21589/PPTX2HTML。但已经六七年没有更新,也没有维护,笔者使用的时候发现有很多兼容性问题。

          简单来说就是,没有。对于这种情况,我们可以自行解析,主要步骤如下:

          1. 查询pptx的国际标准
          2. 解析pptx文件
          3. 渲染成html或者canvas进行展示

          我们先去找一下pptx的国际标准,官方地址:officeopenxml

          先解释下什么是officeopenxml:

          Office OpenXML,也称为 OpenXML 或 OOXML,是一种基于 XML 的办公文档格式,包括文字处理文档、电子表格、演示文稿以及图表、图表、形状和其他图形材料。该规范由微软开发,并于 2006 年被 ECMA 国际采用为 ECMA-376。第二个版本于 2008 年 12 月发布,第三个版本于 2011 年 6 月发布。该规范已被 ISO 和 IEC 采用为 ISO/IEC 29500。

          虽然 Microsoft 继续支持较旧的二进制格式 (.doc、.xls 和.ppt),但 OOXML 现在是所有 Microsoft Office 文档 (.docx、.xlsx 和.pptx) 的默认格式。

          由此可见,Office OpenXML由微软开发,目前已经是国际标准。接下来我们看一下pptx里面有哪些内容,具体可以看pptx的官方标准:officeopenxml-pptx

          PresentationML 或.pptx 文件是一个zip 文件,其中包含许多“部分”(通常是 UTF-8 或 UTF-16 编码)或 XML 文件。该包还可能包含其他媒体文件,例如图像。该结构根据 OOXML 标准 ECMA-376 第 2 部分中概述的开放打包约定进行组织。

          image.png

          根据国际标准,我们知道,pptx文件本质就是一个zip文件,其中包含许多部分:

          部件的数量和类型将根据演示文稿中的内容而有所不同,但始终会有一个 [Content_Types].xml、一个或多个关系(.rels)部件和一个演示文稿部件(演示文稿.xml),它位于 ppt 文件夹中,用于 Microsoft Powerpoint 文件。通常,还将至少有一个幻灯片部件,以及一张母版幻灯片和一张版式幻灯片,从中形成幻灯片。

          那么js如何读取zip呢?

          找到一个工具:https://www.npmjs.com/package/jszip

          于是我们可以开始尝试解析pptx了。

          ts
          import JSZip from 'jszip';
           // 加载 pptx 数据
           const zip = await JSZip.loadAsync(pptxData);
          • 解析[Content_Types].xml

          每个pptx必然会有一个 [Content_Types].xml。此文件包含包中部件的所有内容类型的列表。每个部件及其类型都必须列在 [Content_Types].xml 中。通过它里面的内容,可以解析其他的文件数据

          ts
          const filesInfo = await getContentTypes(zip);
           
          diff --git a/assets/cn_src_article_docPreview.md.to4R_V9b.lean.js b/assets/cn_src_article_docPreview.md.BriOMnC6.lean.js
          similarity index 99%
          rename from assets/cn_src_article_docPreview.md.to4R_V9b.lean.js
          rename to assets/cn_src_article_docPreview.md.BriOMnC6.lean.js
          index c88d7acb68..724129a8dc 100644
          --- a/assets/cn_src_article_docPreview.md.to4R_V9b.lean.js
          +++ b/assets/cn_src_article_docPreview.md.BriOMnC6.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const t="/ran/assets/ms_ppt.C2zYd_IC.webp",p="/ran/assets/ms_excel.CJXFi2bf.webp",l="/ran/assets/ms_word.3k-0mjp0.webp",k="/ran/assets/ms_file_not.DgOrkG3n.webp",e="/ran/assets/ms_answer.Cgv6ylFF.webp",r="/ran/assets/ms_answer_2.D-D9H1v0.webp",E="/ran/assets/google_doc_view.BknjnOKw.webp",d="/ran/assets/ali_doc.CYo30EHy.webp",g="/ran/assets/xdoc.CeowcMPq.webp",o="/ran/assets/ow365.CXWyYekS.webp",y="/ran/assets/wps_office.DiET-U8x.webp",c="/ran/assets/wps_office_price.ler9htjh.webp",F="/ran/assets/xml.NyzOyhr4.webp",C="/ran/assets/firefox_pdf.BWQR-ogn.webp",f="/ran/assets/mdn_pdf.DbNmeC8H.webp",u="/ran/assets/kkfile_des.CENUMtpY.webp",A="/ran/assets/kkfile.X1tAqvNa.webp",m="/ran/assets/kkfile_output.DD8iZdbo.webp",B="/ran/assets/kkfile_doc.CPfEUxoD.webp",O=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/docPreview.md","filePath":"cn/src/article/docPreview.md","lastUpdated":1728828157000}'),D={name:"cn/src/article/docPreview.md"};function b(x,s,v,w,_,P){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          最全的 docx,pptx,xlsx(excel),pdf 文件预览方案总结

          最近遇到了文件预览的需求,但一搜索发现,这还不是一个简单的功能。于是又去查询了很多资料,调研了一些方案,也踩了好多坑。最后总结方案如下

          1. 花钱解决 (使用市面上现有的文件预览服务)
            1. 微软
            2. google
            3. 阿里云 IMM
            4. XDOC
            5. Office Web 365
            6. wps 开放平台
          2. 前端方案
            1. pptx 的预览方案
            2. pdf 的预览方案
            3. docx 的预览方案
            4. xlsx(excel) 的预览方案
            5. 前端预览方案总结
          3. 服务端方案
            1. openOffice
            2. kkFileView
            3. onlyOffice

          如果有其他人也遇到了同样的问题,有了这篇文章,希望能更方便的解决。

          基本涵盖了所有解决方案。因此,标题写上 最全 的文件预览方案调研总结,应该不为过吧。

          一:市面上现有的文件预览服务

          1.微软

          docx,pptx,xlsx可以说是office三件套,那自然得看一下 微软官方 提供的文件预览服务。使用方法特别简单,只需要将文件链接,拼接到参数后面即可。

          记得encodeURL

          js
          https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}

          (1).PPTX 预览效果:

          image.png

          • 优点:还原度很高,功能很丰富,可以选择翻页,甚至支持点击播放动画。
          • 缺点:不知道是不是墙的原因,加载稍慢。

          (2).Excel 预览效果:

          image.png

          (3).Doxc 预览效果

          image.png

          (4).PDF 预览效果

          这个我测试没有成功,返回了一个错误,其他人可以试试。

          image.png

          (5).总的来说

          对于docx,pptx,xlsx都有较好的支持,pdf不行。

          还有一个坑点是:这个服务是否稳定,有什么限制,是否收费,都查不到一个定论。在office官方网站上甚至找不到介绍这个东西的地方。

          目前只能找到一个Q&A:https://answers.microsoft.com/en-us/msoffice/forum/all/what-is-the-status-of-viewofficeappslivecom/830fd75c-9b47-43f9-89c9-4303703fd7f6

          微软官方人员回答表示:

          image.png

          翻译翻译,就是:几乎永久使用,没有收费计划,不会存储预览的文件数据,限制文件10MB,建议用于 查看互联网上公开的文件

          但经过某些用户测试发现:

          image.png

          使用了微软的文件预览服务,然后删除了文件地址,仍然可访问,但过一段时间会失效。

          2.Google Drive 查看器

          接入简单,同 Office Web Viewer,只需要把 src 改为https://drive.google.com/viewer?url=${encodeURIComponent(url)}即可。

          限制25MB,支持以下格式:

          image.png

          测试效果,支持docx,pptx,xlsx,pdf预览,但pptx预览的效果不如微软,没有动画效果,样式有小部分会错乱。

          由于某些众所周知的原因,不可用

          3.阿里云 IMM

          官方文档如下:https://help.aliyun.com/document_detail/63273.html

          image.png

          付费使用

          4.XDOC 文档预览

          说了一些大厂的,在介绍一些其他的,需要自行分辨

          官网地址:https://view.xdocin.com/view-xdocin-com_6x5f4x.htm

          image.png

          5.Office Web 365

          需要注意的是,虽然名字很像office,但我们看网页的Copyright可以发现,其实是一个西安的公司,不是微软

          但毕竟也提供了文件预览的服务

          官网地址:https://www.officeweb365.com/

          image.png

          6.WPS 开放平台

          官方地址:https://solution.wps.cn/

          image.png

          付费使用,价格如下:

          image.png

          二:前端处理方案

          1.pptx 的预览方案

          先查一下有没有现成的轮子,目前pptx的开源预览方案能找到的只有这个:https://github.com/g21589/PPTX2HTML。但已经六七年没有更新,也没有维护,笔者使用的时候发现有很多兼容性问题。

          简单来说就是,没有。对于这种情况,我们可以自行解析,主要步骤如下:

          1. 查询pptx的国际标准
          2. 解析pptx文件
          3. 渲染成html或者canvas进行展示

          我们先去找一下pptx的国际标准,官方地址:officeopenxml

          先解释下什么是officeopenxml:

          Office OpenXML,也称为 OpenXML 或 OOXML,是一种基于 XML 的办公文档格式,包括文字处理文档、电子表格、演示文稿以及图表、图表、形状和其他图形材料。该规范由微软开发,并于 2006 年被 ECMA 国际采用为 ECMA-376。第二个版本于 2008 年 12 月发布,第三个版本于 2011 年 6 月发布。该规范已被 ISO 和 IEC 采用为 ISO/IEC 29500。

          虽然 Microsoft 继续支持较旧的二进制格式 (.doc、.xls 和.ppt),但 OOXML 现在是所有 Microsoft Office 文档 (.docx、.xlsx 和.pptx) 的默认格式。

          由此可见,Office OpenXML由微软开发,目前已经是国际标准。接下来我们看一下pptx里面有哪些内容,具体可以看pptx的官方标准:officeopenxml-pptx

          PresentationML 或.pptx 文件是一个zip 文件,其中包含许多“部分”(通常是 UTF-8 或 UTF-16 编码)或 XML 文件。该包还可能包含其他媒体文件,例如图像。该结构根据 OOXML 标准 ECMA-376 第 2 部分中概述的开放打包约定进行组织。

          image.png

          根据国际标准,我们知道,pptx文件本质就是一个zip文件,其中包含许多部分:

          部件的数量和类型将根据演示文稿中的内容而有所不同,但始终会有一个 [Content_Types].xml、一个或多个关系(.rels)部件和一个演示文稿部件(演示文稿.xml),它位于 ppt 文件夹中,用于 Microsoft Powerpoint 文件。通常,还将至少有一个幻灯片部件,以及一张母版幻灯片和一张版式幻灯片,从中形成幻灯片。

          那么js如何读取zip呢?

          找到一个工具:https://www.npmjs.com/package/jszip

          于是我们可以开始尝试解析pptx了。

          ts
          import JSZip from 'jszip';
          +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const t="/ran/assets/ms_ppt.C2zYd_IC.webp",p="/ran/assets/ms_excel.CJXFi2bf.webp",l="/ran/assets/ms_word.3k-0mjp0.webp",k="/ran/assets/ms_file_not.DgOrkG3n.webp",e="/ran/assets/ms_answer.Cgv6ylFF.webp",r="/ran/assets/ms_answer_2.D-D9H1v0.webp",E="/ran/assets/google_doc_view.BknjnOKw.webp",d="/ran/assets/ali_doc.CYo30EHy.webp",g="/ran/assets/xdoc.CeowcMPq.webp",o="/ran/assets/ow365.CXWyYekS.webp",y="/ran/assets/wps_office.DiET-U8x.webp",c="/ran/assets/wps_office_price.ler9htjh.webp",F="/ran/assets/xml.NyzOyhr4.webp",C="/ran/assets/firefox_pdf.BWQR-ogn.webp",f="/ran/assets/mdn_pdf.DbNmeC8H.webp",u="/ran/assets/kkfile_des.CENUMtpY.webp",A="/ran/assets/kkfile.X1tAqvNa.webp",m="/ran/assets/kkfile_output.DD8iZdbo.webp",B="/ran/assets/kkfile_doc.CPfEUxoD.webp",O=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/docPreview.md","filePath":"cn/src/article/docPreview.md","lastUpdated":1728921295000}'),D={name:"cn/src/article/docPreview.md"};function b(x,s,v,w,_,P){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          最全的 docx,pptx,xlsx(excel),pdf 文件预览方案总结

          最近遇到了文件预览的需求,但一搜索发现,这还不是一个简单的功能。于是又去查询了很多资料,调研了一些方案,也踩了好多坑。最后总结方案如下

          1. 花钱解决 (使用市面上现有的文件预览服务)
            1. 微软
            2. google
            3. 阿里云 IMM
            4. XDOC
            5. Office Web 365
            6. wps 开放平台
          2. 前端方案
            1. pptx 的预览方案
            2. pdf 的预览方案
            3. docx 的预览方案
            4. xlsx(excel) 的预览方案
            5. 前端预览方案总结
          3. 服务端方案
            1. openOffice
            2. kkFileView
            3. onlyOffice

          如果有其他人也遇到了同样的问题,有了这篇文章,希望能更方便的解决。

          基本涵盖了所有解决方案。因此,标题写上 最全 的文件预览方案调研总结,应该不为过吧。

          一:市面上现有的文件预览服务

          1.微软

          docx,pptx,xlsx可以说是office三件套,那自然得看一下 微软官方 提供的文件预览服务。使用方法特别简单,只需要将文件链接,拼接到参数后面即可。

          记得encodeURL

          js
          https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)}

          (1).PPTX 预览效果:

          image.png

          • 优点:还原度很高,功能很丰富,可以选择翻页,甚至支持点击播放动画。
          • 缺点:不知道是不是墙的原因,加载稍慢。

          (2).Excel 预览效果:

          image.png

          (3).Doxc 预览效果

          image.png

          (4).PDF 预览效果

          这个我测试没有成功,返回了一个错误,其他人可以试试。

          image.png

          (5).总的来说

          对于docx,pptx,xlsx都有较好的支持,pdf不行。

          还有一个坑点是:这个服务是否稳定,有什么限制,是否收费,都查不到一个定论。在office官方网站上甚至找不到介绍这个东西的地方。

          目前只能找到一个Q&A:https://answers.microsoft.com/en-us/msoffice/forum/all/what-is-the-status-of-viewofficeappslivecom/830fd75c-9b47-43f9-89c9-4303703fd7f6

          微软官方人员回答表示:

          image.png

          翻译翻译,就是:几乎永久使用,没有收费计划,不会存储预览的文件数据,限制文件10MB,建议用于 查看互联网上公开的文件

          但经过某些用户测试发现:

          image.png

          使用了微软的文件预览服务,然后删除了文件地址,仍然可访问,但过一段时间会失效。

          2.Google Drive 查看器

          接入简单,同 Office Web Viewer,只需要把 src 改为https://drive.google.com/viewer?url=${encodeURIComponent(url)}即可。

          限制25MB,支持以下格式:

          image.png

          测试效果,支持docx,pptx,xlsx,pdf预览,但pptx预览的效果不如微软,没有动画效果,样式有小部分会错乱。

          由于某些众所周知的原因,不可用

          3.阿里云 IMM

          官方文档如下:https://help.aliyun.com/document_detail/63273.html

          image.png

          付费使用

          4.XDOC 文档预览

          说了一些大厂的,在介绍一些其他的,需要自行分辨

          官网地址:https://view.xdocin.com/view-xdocin-com_6x5f4x.htm

          image.png

          5.Office Web 365

          需要注意的是,虽然名字很像office,但我们看网页的Copyright可以发现,其实是一个西安的公司,不是微软

          但毕竟也提供了文件预览的服务

          官网地址:https://www.officeweb365.com/

          image.png

          6.WPS 开放平台

          官方地址:https://solution.wps.cn/

          image.png

          付费使用,价格如下:

          image.png

          二:前端处理方案

          1.pptx 的预览方案

          先查一下有没有现成的轮子,目前pptx的开源预览方案能找到的只有这个:https://github.com/g21589/PPTX2HTML。但已经六七年没有更新,也没有维护,笔者使用的时候发现有很多兼容性问题。

          简单来说就是,没有。对于这种情况,我们可以自行解析,主要步骤如下:

          1. 查询pptx的国际标准
          2. 解析pptx文件
          3. 渲染成html或者canvas进行展示

          我们先去找一下pptx的国际标准,官方地址:officeopenxml

          先解释下什么是officeopenxml:

          Office OpenXML,也称为 OpenXML 或 OOXML,是一种基于 XML 的办公文档格式,包括文字处理文档、电子表格、演示文稿以及图表、图表、形状和其他图形材料。该规范由微软开发,并于 2006 年被 ECMA 国际采用为 ECMA-376。第二个版本于 2008 年 12 月发布,第三个版本于 2011 年 6 月发布。该规范已被 ISO 和 IEC 采用为 ISO/IEC 29500。

          虽然 Microsoft 继续支持较旧的二进制格式 (.doc、.xls 和.ppt),但 OOXML 现在是所有 Microsoft Office 文档 (.docx、.xlsx 和.pptx) 的默认格式。

          由此可见,Office OpenXML由微软开发,目前已经是国际标准。接下来我们看一下pptx里面有哪些内容,具体可以看pptx的官方标准:officeopenxml-pptx

          PresentationML 或.pptx 文件是一个zip 文件,其中包含许多“部分”(通常是 UTF-8 或 UTF-16 编码)或 XML 文件。该包还可能包含其他媒体文件,例如图像。该结构根据 OOXML 标准 ECMA-376 第 2 部分中概述的开放打包约定进行组织。

          image.png

          根据国际标准,我们知道,pptx文件本质就是一个zip文件,其中包含许多部分:

          部件的数量和类型将根据演示文稿中的内容而有所不同,但始终会有一个 [Content_Types].xml、一个或多个关系(.rels)部件和一个演示文稿部件(演示文稿.xml),它位于 ppt 文件夹中,用于 Microsoft Powerpoint 文件。通常,还将至少有一个幻灯片部件,以及一张母版幻灯片和一张版式幻灯片,从中形成幻灯片。

          那么js如何读取zip呢?

          找到一个工具:https://www.npmjs.com/package/jszip

          于是我们可以开始尝试解析pptx了。

          ts
          import JSZip from 'jszip';
           // 加载 pptx 数据
           const zip = await JSZip.loadAsync(pptxData);
          • 解析[Content_Types].xml

          每个pptx必然会有一个 [Content_Types].xml。此文件包含包中部件的所有内容类型的列表。每个部件及其类型都必须列在 [Content_Types].xml 中。通过它里面的内容,可以解析其他的文件数据

          ts
          const filesInfo = await getContentTypes(zip);
           
          diff --git a/assets/cn_src_article_functionalProgramming.md.CkKiYr9L.js b/assets/cn_src_article_functionalProgramming.md.kIfOv665.js
          similarity index 99%
          rename from assets/cn_src_article_functionalProgramming.md.CkKiYr9L.js
          rename to assets/cn_src_article_functionalProgramming.md.kIfOv665.js
          index fd5bdcddbe..42e40bea79 100644
          --- a/assets/cn_src_article_functionalProgramming.md.CkKiYr9L.js
          +++ b/assets/cn_src_article_functionalProgramming.md.kIfOv665.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"函数式编程","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/functionalProgramming.md","filePath":"cn/src/article/functionalProgramming.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/functionalProgramming.md"};function l(p,s,t,E,e,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          函数式编程

          • 概述:函数式编程 (Functional Programming)FP就是编程规范之一,我们常听说的编程规范还有面向对象编程,面向过程编程。
          • 面向对象的编程思维方式:把现实世界中的事物抽象成程序世界的类和对象,通过封装,继承和多态演示事物事件的联系
          • 函数编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界 (对运算过程进行抽象)
            • 程序的本质:根据输入,通过某种运算,获得相应的输出
            • 函数式编程中的函数不是指程序中的 (函数) 方法,而是数学中的函数,即映射关系
            • 相同的输入始终要得到相同的输出 (纯函数)
            • 函数式编程用来描述数据 (函数) 之间的映射关系
          js
          //非函数式编程,面向过程的编程方式
          +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"函数式编程","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/functionalProgramming.md","filePath":"cn/src/article/functionalProgramming.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/functionalProgramming.md"};function l(p,s,t,E,e,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          函数式编程

          • 概述:函数式编程 (Functional Programming)FP就是编程规范之一,我们常听说的编程规范还有面向对象编程,面向过程编程。
          • 面向对象的编程思维方式:把现实世界中的事物抽象成程序世界的类和对象,通过封装,继承和多态演示事物事件的联系
          • 函数编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界 (对运算过程进行抽象)
            • 程序的本质:根据输入,通过某种运算,获得相应的输出
            • 函数式编程中的函数不是指程序中的 (函数) 方法,而是数学中的函数,即映射关系
            • 相同的输入始终要得到相同的输出 (纯函数)
            • 函数式编程用来描述数据 (函数) 之间的映射关系
          js
          //非函数式编程,面向过程的编程方式
           let num1 = 1;
           let num2 = 2;
           let sum = num1 + num2;
          diff --git a/assets/cn_src_article_functionalProgramming.md.CkKiYr9L.lean.js b/assets/cn_src_article_functionalProgramming.md.kIfOv665.lean.js
          similarity index 99%
          rename from assets/cn_src_article_functionalProgramming.md.CkKiYr9L.lean.js
          rename to assets/cn_src_article_functionalProgramming.md.kIfOv665.lean.js
          index fd5bdcddbe..42e40bea79 100644
          --- a/assets/cn_src_article_functionalProgramming.md.CkKiYr9L.lean.js
          +++ b/assets/cn_src_article_functionalProgramming.md.kIfOv665.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"函数式编程","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/functionalProgramming.md","filePath":"cn/src/article/functionalProgramming.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/functionalProgramming.md"};function l(p,s,t,E,e,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          函数式编程

          • 概述:函数式编程 (Functional Programming)FP就是编程规范之一,我们常听说的编程规范还有面向对象编程,面向过程编程。
          • 面向对象的编程思维方式:把现实世界中的事物抽象成程序世界的类和对象,通过封装,继承和多态演示事物事件的联系
          • 函数编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界 (对运算过程进行抽象)
            • 程序的本质:根据输入,通过某种运算,获得相应的输出
            • 函数式编程中的函数不是指程序中的 (函数) 方法,而是数学中的函数,即映射关系
            • 相同的输入始终要得到相同的输出 (纯函数)
            • 函数式编程用来描述数据 (函数) 之间的映射关系
          js
          //非函数式编程,面向过程的编程方式
          +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"函数式编程","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/functionalProgramming.md","filePath":"cn/src/article/functionalProgramming.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/functionalProgramming.md"};function l(p,s,t,E,e,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          函数式编程

          • 概述:函数式编程 (Functional Programming)FP就是编程规范之一,我们常听说的编程规范还有面向对象编程,面向过程编程。
          • 面向对象的编程思维方式:把现实世界中的事物抽象成程序世界的类和对象,通过封装,继承和多态演示事物事件的联系
          • 函数编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界 (对运算过程进行抽象)
            • 程序的本质:根据输入,通过某种运算,获得相应的输出
            • 函数式编程中的函数不是指程序中的 (函数) 方法,而是数学中的函数,即映射关系
            • 相同的输入始终要得到相同的输出 (纯函数)
            • 函数式编程用来描述数据 (函数) 之间的映射关系
          js
          //非函数式编程,面向过程的编程方式
           let num1 = 1;
           let num2 = 2;
           let sum = num1 + num2;
          diff --git a/assets/cn_src_article_imagemin.md.CHqS0vGt.js b/assets/cn_src_article_imagemin.md.DFEWNSIZ.js
          similarity index 91%
          rename from assets/cn_src_article_imagemin.md.CHqS0vGt.js
          rename to assets/cn_src_article_imagemin.md.DFEWNSIZ.js
          index 2c437e28ee..bca7b98234 100644
          --- a/assets/cn_src_article_imagemin.md.CHqS0vGt.js
          +++ b/assets/cn_src_article_imagemin.md.DFEWNSIZ.js
          @@ -1 +1 @@
          -import{_ as t,o as i,c as r,j as a,a as n}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"imagemin 图片压缩源码分析","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/imagemin.md","filePath":"cn/src/article/imagemin.md","lastUpdated":1728828157000}'),m={name:"cn/src/article/imagemin.md"};function s(c,e,o,d,l,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[a("h1",{id:"imagemin-图片压缩源码分析",tabindex:"-1"},[n("imagemin 图片压缩源码分析 "),a("a",{class:"header-anchor",href:"#imagemin-图片压缩源码分析","aria-label":'Permalink to "imagemin 图片压缩源码分析"'},"​")],-1)]))}const _=t(m,[["render",s]]);export{f as __pageData,_ as default};
          +import{_ as t,o as i,c as r,j as a,a as n}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"imagemin 图片压缩源码分析","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/imagemin.md","filePath":"cn/src/article/imagemin.md","lastUpdated":1728921295000}'),m={name:"cn/src/article/imagemin.md"};function s(c,e,o,d,l,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[a("h1",{id:"imagemin-图片压缩源码分析",tabindex:"-1"},[n("imagemin 图片压缩源码分析 "),a("a",{class:"header-anchor",href:"#imagemin-图片压缩源码分析","aria-label":'Permalink to "imagemin 图片压缩源码分析"'},"​")],-1)]))}const _=t(m,[["render",s]]);export{f as __pageData,_ as default};
          diff --git a/assets/cn_src_article_imagemin.md.CHqS0vGt.lean.js b/assets/cn_src_article_imagemin.md.DFEWNSIZ.lean.js
          similarity index 91%
          rename from assets/cn_src_article_imagemin.md.CHqS0vGt.lean.js
          rename to assets/cn_src_article_imagemin.md.DFEWNSIZ.lean.js
          index 2c437e28ee..bca7b98234 100644
          --- a/assets/cn_src_article_imagemin.md.CHqS0vGt.lean.js
          +++ b/assets/cn_src_article_imagemin.md.DFEWNSIZ.lean.js
          @@ -1 +1 @@
          -import{_ as t,o as i,c as r,j as a,a as n}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"imagemin 图片压缩源码分析","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/imagemin.md","filePath":"cn/src/article/imagemin.md","lastUpdated":1728828157000}'),m={name:"cn/src/article/imagemin.md"};function s(c,e,o,d,l,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[a("h1",{id:"imagemin-图片压缩源码分析",tabindex:"-1"},[n("imagemin 图片压缩源码分析 "),a("a",{class:"header-anchor",href:"#imagemin-图片压缩源码分析","aria-label":'Permalink to "imagemin 图片压缩源码分析"'},"​")],-1)]))}const _=t(m,[["render",s]]);export{f as __pageData,_ as default};
          +import{_ as t,o as i,c as r,j as a,a as n}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"imagemin 图片压缩源码分析","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/imagemin.md","filePath":"cn/src/article/imagemin.md","lastUpdated":1728921295000}'),m={name:"cn/src/article/imagemin.md"};function s(c,e,o,d,l,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[a("h1",{id:"imagemin-图片压缩源码分析",tabindex:"-1"},[n("imagemin 图片压缩源码分析 "),a("a",{class:"header-anchor",href:"#imagemin-图片压缩源码分析","aria-label":'Permalink to "imagemin 图片压缩源码分析"'},"​")],-1)]))}const _=t(m,[["render",s]]);export{f as __pageData,_ as default};
          diff --git a/assets/cn_src_article_javascript_domLoad.md.Ci82ToLN.js b/assets/cn_src_article_javascript_domLoad.md.B74fIpy6.js
          similarity index 97%
          rename from assets/cn_src_article_javascript_domLoad.md.Ci82ToLN.js
          rename to assets/cn_src_article_javascript_domLoad.md.B74fIpy6.js
          index 855f661fc8..f4636d9960 100644
          --- a/assets/cn_src_article_javascript_domLoad.md.Ci82ToLN.js
          +++ b/assets/cn_src_article_javascript_domLoad.md.B74fIpy6.js
          @@ -1 +1 @@
          -import{_ as e,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"页面加载完成后事件","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/javascript/domLoad.md","filePath":"cn/src/article/javascript/domLoad.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/javascript/domLoad.md"};function o(d,a,l,r,c,h){return t(),s("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          页面加载完成后事件

          window.onload

          DOMContentLoaded

          js
          document.addEventListener('DOMContentLoaded', fun);

          <body onload="fun()">

          readyState

          js
          document.readyState;\n\ndocument.onreadystatechange;

          一个文档的 readyState 可以是以下之一:

          • loading / 加载。document 仍在加载。
          • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
          • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
          ',9)]))}const k=e(n,[["render",o]]);export{u as __pageData,k as default}; +import{_ as e,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"页面加载完成后事件","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/javascript/domLoad.md","filePath":"cn/src/article/javascript/domLoad.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/javascript/domLoad.md"};function o(d,a,l,r,c,h){return t(),s("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          页面加载完成后事件

          window.onload

          DOMContentLoaded

          js
          document.addEventListener('DOMContentLoaded', fun);

          <body onload="fun()">

          readyState

          js
          document.readyState;\n\ndocument.onreadystatechange;

          一个文档的 readyState 可以是以下之一:

          • loading / 加载。document 仍在加载。
          • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
          • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
          ',9)]))}const k=e(n,[["render",o]]);export{u as __pageData,k as default}; diff --git a/assets/cn_src_article_javascript_domLoad.md.Ci82ToLN.lean.js b/assets/cn_src_article_javascript_domLoad.md.B74fIpy6.lean.js similarity index 97% rename from assets/cn_src_article_javascript_domLoad.md.Ci82ToLN.lean.js rename to assets/cn_src_article_javascript_domLoad.md.B74fIpy6.lean.js index 855f661fc8..f4636d9960 100644 --- a/assets/cn_src_article_javascript_domLoad.md.Ci82ToLN.lean.js +++ b/assets/cn_src_article_javascript_domLoad.md.B74fIpy6.lean.js @@ -1 +1 @@ -import{_ as e,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"页面加载完成后事件","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/javascript/domLoad.md","filePath":"cn/src/article/javascript/domLoad.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/javascript/domLoad.md"};function o(d,a,l,r,c,h){return t(),s("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          页面加载完成后事件

          window.onload

          DOMContentLoaded

          js
          document.addEventListener('DOMContentLoaded', fun);

          <body onload="fun()">

          readyState

          js
          document.readyState;\n\ndocument.onreadystatechange;

          一个文档的 readyState 可以是以下之一:

          • loading / 加载。document 仍在加载。
          • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
          • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
          ',9)]))}const k=e(n,[["render",o]]);export{u as __pageData,k as default}; +import{_ as e,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"页面加载完成后事件","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/javascript/domLoad.md","filePath":"cn/src/article/javascript/domLoad.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/javascript/domLoad.md"};function o(d,a,l,r,c,h){return t(),s("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          页面加载完成后事件

          window.onload

          DOMContentLoaded

          js
          document.addEventListener('DOMContentLoaded', fun);

          <body onload="fun()">

          readyState

          js
          document.readyState;\n\ndocument.onreadystatechange;

          一个文档的 readyState 可以是以下之一:

          • loading / 加载。document 仍在加载。
          • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
          • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
          ',9)]))}const k=e(n,[["render",o]]);export{u as __pageData,k as default}; diff --git a/assets/cn_src_article_sort_bubble_index.md.CjZlxYfr.js b/assets/cn_src_article_sort_bubble_index.md.Cp1RBpmv.js similarity index 99% rename from assets/cn_src_article_sort_bubble_index.md.CjZlxYfr.js rename to assets/cn_src_article_sort_bubble_index.md.Cp1RBpmv.js index 2aba63c294..cff1d3da6c 100644 --- a/assets/cn_src_article_sort_bubble_index.md.CjZlxYfr.js +++ b/assets/cn_src_article_sort_bubble_index.md.Cp1RBpmv.js @@ -1,4 +1,4 @@ -import{_ as i}from"./chunks/bubble.Dg5jgvyl.js";import{_ as a,o as l,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"冒泡排序(Bubble Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/bubble/index.md","filePath":"cn/src/article/sort/bubble/index.md","lastUpdated":1728828157000}'),h={name:"cn/src/article/sort/bubble/index.md"};function k(p,s,e,r,E,d){return l(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

          冒泡排序(Bubble Sort)

          冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

          算法描述

          • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
          • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
          • 针对所有的元素重复以上的步骤,除了最后一个;
          • 重复步骤 1~3,直到排序完成。

          动图演示

          冒泡排序

          代码演示

          ts
          const bubble = (list: number[]) => {
          +import{_ as i}from"./chunks/bubble.Dg5jgvyl.js";import{_ as a,o as l,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"冒泡排序(Bubble Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/bubble/index.md","filePath":"cn/src/article/sort/bubble/index.md","lastUpdated":1728921295000}'),h={name:"cn/src/article/sort/bubble/index.md"};function k(p,s,e,r,E,d){return l(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

          冒泡排序(Bubble Sort)

          冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

          算法描述

          • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
          • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
          • 针对所有的元素重复以上的步骤,除了最后一个;
          • 重复步骤 1~3,直到排序完成。

          动图演示

          冒泡排序

          代码演示

          ts
          const bubble = (list: number[]) => {
             const size = list.length;
             for (let i = 0; i < size; i++) {
               for (let j = 0; j < size; j++) {
          diff --git a/assets/cn_src_article_sort_bubble_index.md.CjZlxYfr.lean.js b/assets/cn_src_article_sort_bubble_index.md.Cp1RBpmv.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_bubble_index.md.CjZlxYfr.lean.js
          rename to assets/cn_src_article_sort_bubble_index.md.Cp1RBpmv.lean.js
          index 2aba63c294..cff1d3da6c 100644
          --- a/assets/cn_src_article_sort_bubble_index.md.CjZlxYfr.lean.js
          +++ b/assets/cn_src_article_sort_bubble_index.md.Cp1RBpmv.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/bubble.Dg5jgvyl.js";import{_ as a,o as l,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"冒泡排序(Bubble Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/bubble/index.md","filePath":"cn/src/article/sort/bubble/index.md","lastUpdated":1728828157000}'),h={name:"cn/src/article/sort/bubble/index.md"};function k(p,s,e,r,E,d){return l(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

          冒泡排序(Bubble Sort)

          冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

          算法描述

          • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
          • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
          • 针对所有的元素重复以上的步骤,除了最后一个;
          • 重复步骤 1~3,直到排序完成。

          动图演示

          冒泡排序

          代码演示

          ts
          const bubble = (list: number[]) => {
          +import{_ as i}from"./chunks/bubble.Dg5jgvyl.js";import{_ as a,o as l,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"冒泡排序(Bubble Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/bubble/index.md","filePath":"cn/src/article/sort/bubble/index.md","lastUpdated":1728921295000}'),h={name:"cn/src/article/sort/bubble/index.md"};function k(p,s,e,r,E,d){return l(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

          冒泡排序(Bubble Sort)

          冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

          算法描述

          • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
          • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;
          • 针对所有的元素重复以上的步骤,除了最后一个;
          • 重复步骤 1~3,直到排序完成。

          动图演示

          冒泡排序

          代码演示

          ts
          const bubble = (list: number[]) => {
             const size = list.length;
             for (let i = 0; i < size; i++) {
               for (let j = 0; j < size; j++) {
          diff --git a/assets/cn_src_article_sort_bucket_index.md.B4drqe-3.js b/assets/cn_src_article_sort_bucket_index.md.DART29Tq.js
          similarity index 99%
          rename from assets/cn_src_article_sort_bucket_index.md.B4drqe-3.js
          rename to assets/cn_src_article_sort_bucket_index.md.DART29Tq.js
          index 6109147e22..2522406b86 100644
          --- a/assets/cn_src_article_sort_bucket_index.md.B4drqe-3.js
          +++ b/assets/cn_src_article_sort_bucket_index.md.DART29Tq.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"桶排序 (Bucket Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/bucket/index.md","filePath":"cn/src/article/sort/bucket/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/sort/bucket/index.md"};function l(t,s,p,E,e,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          桶排序 (Bucket Sort)

          高效与否的关键在于这个分桶函数。将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

          算法描述

          • 设置一个定量的数组当作空桶;
          • 遍历输入数据,并且把数据一个一个放到对应的桶里去;
          • 对每个不是空的桶进行排序;
          • 从不是空的桶里把排好序的数据拼接起来。

          代码演示

          ts
          const count = (list: Array<number>, max: number = 100): Array<number> => {
          +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"桶排序 (Bucket Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/bucket/index.md","filePath":"cn/src/article/sort/bucket/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/sort/bucket/index.md"};function l(t,s,p,E,e,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          桶排序 (Bucket Sort)

          高效与否的关键在于这个分桶函数。将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

          算法描述

          • 设置一个定量的数组当作空桶;
          • 遍历输入数据,并且把数据一个一个放到对应的桶里去;
          • 对每个不是空的桶进行排序;
          • 从不是空的桶里把排好序的数据拼接起来。

          代码演示

          ts
          const count = (list: Array<number>, max: number = 100): Array<number> => {
             const countList = new Array(max + 1);
             for (let i = 0; i < list.length; i++) {
               if (!countList[list[i]]) {
          diff --git a/assets/cn_src_article_sort_bucket_index.md.B4drqe-3.lean.js b/assets/cn_src_article_sort_bucket_index.md.DART29Tq.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_bucket_index.md.B4drqe-3.lean.js
          rename to assets/cn_src_article_sort_bucket_index.md.DART29Tq.lean.js
          index 6109147e22..2522406b86 100644
          --- a/assets/cn_src_article_sort_bucket_index.md.B4drqe-3.lean.js
          +++ b/assets/cn_src_article_sort_bucket_index.md.DART29Tq.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"桶排序 (Bucket Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/bucket/index.md","filePath":"cn/src/article/sort/bucket/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/sort/bucket/index.md"};function l(t,s,p,E,e,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          桶排序 (Bucket Sort)

          高效与否的关键在于这个分桶函数。将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

          算法描述

          • 设置一个定量的数组当作空桶;
          • 遍历输入数据,并且把数据一个一个放到对应的桶里去;
          • 对每个不是空的桶进行排序;
          • 从不是空的桶里把排好序的数据拼接起来。

          代码演示

          ts
          const count = (list: Array<number>, max: number = 100): Array<number> => {
          +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"桶排序 (Bucket Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/bucket/index.md","filePath":"cn/src/article/sort/bucket/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/sort/bucket/index.md"};function l(t,s,p,E,e,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          桶排序 (Bucket Sort)

          高效与否的关键在于这个分桶函数。将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

          算法描述

          • 设置一个定量的数组当作空桶;
          • 遍历输入数据,并且把数据一个一个放到对应的桶里去;
          • 对每个不是空的桶进行排序;
          • 从不是空的桶里把排好序的数据拼接起来。

          代码演示

          ts
          const count = (list: Array<number>, max: number = 100): Array<number> => {
             const countList = new Array(max + 1);
             for (let i = 0; i < list.length; i++) {
               if (!countList[list[i]]) {
          diff --git a/assets/cn_src_article_sort_count_index.md.DYoyFiDb.js b/assets/cn_src_article_sort_count_index.md.00GyLjR_.js
          similarity index 99%
          rename from assets/cn_src_article_sort_count_index.md.DYoyFiDb.js
          rename to assets/cn_src_article_sort_count_index.md.00GyLjR_.js
          index e4a49bc1cf..0eeb6822fe 100644
          --- a/assets/cn_src_article_sort_count_index.md.DYoyFiDb.js
          +++ b/assets/cn_src_article_sort_count_index.md.00GyLjR_.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/count.CcfK-WL7.js";import{_ as a,o as n,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"计数排序( Count Sort )","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/count/index.md","filePath":"cn/src/article/sort/count/index.md","lastUpdated":1728828157000}'),t={name:"cn/src/article/sort/count/index.md"};function l(p,s,e,E,r,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          计数排序( Count Sort )

          计数排序(counting sort)就是一种牺牲内存空间来换取低时间复杂度的排序算法,同时它也是一种不基于比较的算法。这里的不基于比较指的是数组元素之间不存在比较大小的排序算法,我们知道,用分治法来解决排序问题最快也只能使算法的时间复杂度接近 Θ(nlogn),即基于比较的时间复杂度存在下界 Ω(nlog⁡n),而不基于比较的排序算法可以突破这一下界。

          算法描述

          • 找出待排序的数组中最大和最小的元素;
          • 统计数组中每个值为 i 的元素出现的次数,存入数组 C 的第 i 项;
          • 对所有的计数累加(从 C 中的第一个元素开始,每一项和前一项相加);
          • 反向填充目标数组:将每个元素 i 放在新数组的第 C(i)项,每放一个元素就将 C(i)减去 1。

          动图演示

          计数排序

          代码演示

          ts
          const getMax = (list: number[]) => {
          +import{_ as i}from"./chunks/count.CcfK-WL7.js";import{_ as a,o as n,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"计数排序( Count Sort )","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/count/index.md","filePath":"cn/src/article/sort/count/index.md","lastUpdated":1728921295000}'),t={name:"cn/src/article/sort/count/index.md"};function l(p,s,e,E,r,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          计数排序( Count Sort )

          计数排序(counting sort)就是一种牺牲内存空间来换取低时间复杂度的排序算法,同时它也是一种不基于比较的算法。这里的不基于比较指的是数组元素之间不存在比较大小的排序算法,我们知道,用分治法来解决排序问题最快也只能使算法的时间复杂度接近 Θ(nlogn),即基于比较的时间复杂度存在下界 Ω(nlog⁡n),而不基于比较的排序算法可以突破这一下界。

          算法描述

          • 找出待排序的数组中最大和最小的元素;
          • 统计数组中每个值为 i 的元素出现的次数,存入数组 C 的第 i 项;
          • 对所有的计数累加(从 C 中的第一个元素开始,每一项和前一项相加);
          • 反向填充目标数组:将每个元素 i 放在新数组的第 C(i)项,每放一个元素就将 C(i)减去 1。

          动图演示

          计数排序

          代码演示

          ts
          const getMax = (list: number[]) => {
             let max = list[0];
             for (let i = 1; i < list.length; i++) {
               if (max < list[i]) {
          diff --git a/assets/cn_src_article_sort_count_index.md.DYoyFiDb.lean.js b/assets/cn_src_article_sort_count_index.md.00GyLjR_.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_count_index.md.DYoyFiDb.lean.js
          rename to assets/cn_src_article_sort_count_index.md.00GyLjR_.lean.js
          index e4a49bc1cf..0eeb6822fe 100644
          --- a/assets/cn_src_article_sort_count_index.md.DYoyFiDb.lean.js
          +++ b/assets/cn_src_article_sort_count_index.md.00GyLjR_.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/count.CcfK-WL7.js";import{_ as a,o as n,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"计数排序( Count Sort )","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/count/index.md","filePath":"cn/src/article/sort/count/index.md","lastUpdated":1728828157000}'),t={name:"cn/src/article/sort/count/index.md"};function l(p,s,e,E,r,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          计数排序( Count Sort )

          计数排序(counting sort)就是一种牺牲内存空间来换取低时间复杂度的排序算法,同时它也是一种不基于比较的算法。这里的不基于比较指的是数组元素之间不存在比较大小的排序算法,我们知道,用分治法来解决排序问题最快也只能使算法的时间复杂度接近 Θ(nlogn),即基于比较的时间复杂度存在下界 Ω(nlog⁡n),而不基于比较的排序算法可以突破这一下界。

          算法描述

          • 找出待排序的数组中最大和最小的元素;
          • 统计数组中每个值为 i 的元素出现的次数,存入数组 C 的第 i 项;
          • 对所有的计数累加(从 C 中的第一个元素开始,每一项和前一项相加);
          • 反向填充目标数组:将每个元素 i 放在新数组的第 C(i)项,每放一个元素就将 C(i)减去 1。

          动图演示

          计数排序

          代码演示

          ts
          const getMax = (list: number[]) => {
          +import{_ as i}from"./chunks/count.CcfK-WL7.js";import{_ as a,o as n,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"计数排序( Count Sort )","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/count/index.md","filePath":"cn/src/article/sort/count/index.md","lastUpdated":1728921295000}'),t={name:"cn/src/article/sort/count/index.md"};function l(p,s,e,E,r,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          计数排序( Count Sort )

          计数排序(counting sort)就是一种牺牲内存空间来换取低时间复杂度的排序算法,同时它也是一种不基于比较的算法。这里的不基于比较指的是数组元素之间不存在比较大小的排序算法,我们知道,用分治法来解决排序问题最快也只能使算法的时间复杂度接近 Θ(nlogn),即基于比较的时间复杂度存在下界 Ω(nlog⁡n),而不基于比较的排序算法可以突破这一下界。

          算法描述

          • 找出待排序的数组中最大和最小的元素;
          • 统计数组中每个值为 i 的元素出现的次数,存入数组 C 的第 i 项;
          • 对所有的计数累加(从 C 中的第一个元素开始,每一项和前一项相加);
          • 反向填充目标数组:将每个元素 i 放在新数组的第 C(i)项,每放一个元素就将 C(i)减去 1。

          动图演示

          计数排序

          代码演示

          ts
          const getMax = (list: number[]) => {
             let max = list[0];
             for (let i = 1; i < list.length; i++) {
               if (max < list[i]) {
          diff --git a/assets/cn_src_article_sort_heap_index.md.CkqW8bYY.js b/assets/cn_src_article_sort_heap_index.md.CzO5sZ8i.js
          similarity index 99%
          rename from assets/cn_src_article_sort_heap_index.md.CkqW8bYY.js
          rename to assets/cn_src_article_sort_heap_index.md.CzO5sZ8i.js
          index c07cd8514c..afe360284e 100644
          --- a/assets/cn_src_article_sort_heap_index.md.CkqW8bYY.js
          +++ b/assets/cn_src_article_sort_heap_index.md.CzO5sZ8i.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/heap.xduQWyUN.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"堆排序(Heap Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/heap/index.md","filePath":"cn/src/article/sort/heap/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/heap/index.md"};function t(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          堆排序(Heap Sort)

          堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

          算法描述

          • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
          • 将堆顶元素 R[1]与最后一个元素 R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足 R[1,2…n-1]<=R[n];
          • 由于交换后新的堆顶 R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将 R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为 n-1,则整个排序过程完成。
          • 升序用大根堆,降序用小根堆

          动图演示

          堆排序

          代码演示

          ts
          class Heap {
          +import{_ as i}from"./chunks/heap.xduQWyUN.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"堆排序(Heap Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/heap/index.md","filePath":"cn/src/article/sort/heap/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/heap/index.md"};function t(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          堆排序(Heap Sort)

          堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

          算法描述

          • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
          • 将堆顶元素 R[1]与最后一个元素 R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足 R[1,2…n-1]<=R[n];
          • 由于交换后新的堆顶 R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将 R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为 n-1,则整个排序过程完成。
          • 升序用大根堆,降序用小根堆

          动图演示

          堆排序

          代码演示

          ts
          class Heap {
             value: Array<number>;
             size: number;
             constructor(arr: Array<number> = []) {
          diff --git a/assets/cn_src_article_sort_heap_index.md.CkqW8bYY.lean.js b/assets/cn_src_article_sort_heap_index.md.CzO5sZ8i.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_heap_index.md.CkqW8bYY.lean.js
          rename to assets/cn_src_article_sort_heap_index.md.CzO5sZ8i.lean.js
          index c07cd8514c..afe360284e 100644
          --- a/assets/cn_src_article_sort_heap_index.md.CkqW8bYY.lean.js
          +++ b/assets/cn_src_article_sort_heap_index.md.CzO5sZ8i.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/heap.xduQWyUN.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"堆排序(Heap Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/heap/index.md","filePath":"cn/src/article/sort/heap/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/heap/index.md"};function t(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          堆排序(Heap Sort)

          堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

          算法描述

          • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
          • 将堆顶元素 R[1]与最后一个元素 R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足 R[1,2…n-1]<=R[n];
          • 由于交换后新的堆顶 R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将 R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为 n-1,则整个排序过程完成。
          • 升序用大根堆,降序用小根堆

          动图演示

          堆排序

          代码演示

          ts
          class Heap {
          +import{_ as i}from"./chunks/heap.xduQWyUN.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"堆排序(Heap Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/heap/index.md","filePath":"cn/src/article/sort/heap/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/heap/index.md"};function t(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          堆排序(Heap Sort)

          堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

          算法描述

          • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
          • 将堆顶元素 R[1]与最后一个元素 R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足 R[1,2…n-1]<=R[n];
          • 由于交换后新的堆顶 R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将 R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为 n-1,则整个排序过程完成。
          • 升序用大根堆,降序用小根堆

          动图演示

          堆排序

          代码演示

          ts
          class Heap {
             value: Array<number>;
             size: number;
             constructor(arr: Array<number> = []) {
          diff --git a/assets/cn_src_article_sort_index.md.D92LVwEh.js b/assets/cn_src_article_sort_index.md.BocISVrP.js
          similarity index 96%
          rename from assets/cn_src_article_sort_index.md.D92LVwEh.js
          rename to assets/cn_src_article_sort_index.md.BocISVrP.js
          index 5b14decf98..310d60c98f 100644
          --- a/assets/cn_src_article_sort_index.md.D92LVwEh.js
          +++ b/assets/cn_src_article_sort_index.md.BocISVrP.js
          @@ -1 +1 @@
          -import{_ as t,a as e}from"./chunks/complexity.CSkvDr7k.js";import{_ as r,o as i,c as o,a3 as l}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"十大经典排序","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/index.md","filePath":"cn/src/article/sort/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/sort/index.md"};function s(c,a,d,p,m,h){return i(),o("div",{"data-pagefind-body":!0},a[0]||(a[0]=[l('

          十大经典排序

          十种常见排序算法可以分为两大类:

          • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O(nlogn),因此也称为非线性时间比较类排序。
          • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

          排序分类

          算法复杂度

          算法复杂度

          相关概念

          • 稳定:如果 a 原本在 b 前面,而 a=b,排序之后 a 仍然在 b 的前面。
          • 不稳定:如果 a 原本在 b 的前面,而 a=b,排序之后 a 可能会出现在 b 的后面。
          • 时间复杂度:对排序数据的总的操作次数。反映当 n 变化时,操作次数呈现什么规律。
          • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模 n 的函数。
          ',8)]))}const f=r(n,[["render",s]]);export{b as __pageData,f as default}; +import{_ as t,a as e}from"./chunks/complexity.CSkvDr7k.js";import{_ as r,o as i,c as o,a3 as l}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"十大经典排序","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/index.md","filePath":"cn/src/article/sort/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/sort/index.md"};function s(c,a,d,p,m,h){return i(),o("div",{"data-pagefind-body":!0},a[0]||(a[0]=[l('

          十大经典排序

          十种常见排序算法可以分为两大类:

          • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O(nlogn),因此也称为非线性时间比较类排序。
          • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

          排序分类

          算法复杂度

          算法复杂度

          相关概念

          • 稳定:如果 a 原本在 b 前面,而 a=b,排序之后 a 仍然在 b 的前面。
          • 不稳定:如果 a 原本在 b 的前面,而 a=b,排序之后 a 可能会出现在 b 的后面。
          • 时间复杂度:对排序数据的总的操作次数。反映当 n 变化时,操作次数呈现什么规律。
          • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模 n 的函数。
          ',8)]))}const f=r(n,[["render",s]]);export{b as __pageData,f as default}; diff --git a/assets/cn_src_article_sort_index.md.D92LVwEh.lean.js b/assets/cn_src_article_sort_index.md.BocISVrP.lean.js similarity index 96% rename from assets/cn_src_article_sort_index.md.D92LVwEh.lean.js rename to assets/cn_src_article_sort_index.md.BocISVrP.lean.js index 5b14decf98..310d60c98f 100644 --- a/assets/cn_src_article_sort_index.md.D92LVwEh.lean.js +++ b/assets/cn_src_article_sort_index.md.BocISVrP.lean.js @@ -1 +1 @@ -import{_ as t,a as e}from"./chunks/complexity.CSkvDr7k.js";import{_ as r,o as i,c as o,a3 as l}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"十大经典排序","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/index.md","filePath":"cn/src/article/sort/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/sort/index.md"};function s(c,a,d,p,m,h){return i(),o("div",{"data-pagefind-body":!0},a[0]||(a[0]=[l('

          十大经典排序

          十种常见排序算法可以分为两大类:

          • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O(nlogn),因此也称为非线性时间比较类排序。
          • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

          排序分类

          算法复杂度

          算法复杂度

          相关概念

          • 稳定:如果 a 原本在 b 前面,而 a=b,排序之后 a 仍然在 b 的前面。
          • 不稳定:如果 a 原本在 b 的前面,而 a=b,排序之后 a 可能会出现在 b 的后面。
          • 时间复杂度:对排序数据的总的操作次数。反映当 n 变化时,操作次数呈现什么规律。
          • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模 n 的函数。
          ',8)]))}const f=r(n,[["render",s]]);export{b as __pageData,f as default}; +import{_ as t,a as e}from"./chunks/complexity.CSkvDr7k.js";import{_ as r,o as i,c as o,a3 as l}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"十大经典排序","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/index.md","filePath":"cn/src/article/sort/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/sort/index.md"};function s(c,a,d,p,m,h){return i(),o("div",{"data-pagefind-body":!0},a[0]||(a[0]=[l('

          十大经典排序

          十种常见排序算法可以分为两大类:

          • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O(nlogn),因此也称为非线性时间比较类排序。
          • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

          排序分类

          算法复杂度

          算法复杂度

          相关概念

          • 稳定:如果 a 原本在 b 前面,而 a=b,排序之后 a 仍然在 b 的前面。
          • 不稳定:如果 a 原本在 b 的前面,而 a=b,排序之后 a 可能会出现在 b 的后面。
          • 时间复杂度:对排序数据的总的操作次数。反映当 n 变化时,操作次数呈现什么规律。
          • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模 n 的函数。
          ',8)]))}const f=r(n,[["render",s]]);export{b as __pageData,f as default}; diff --git a/assets/cn_src_article_sort_insert_index.md.CmQ1YgOQ.js b/assets/cn_src_article_sort_insert_index.md.DjxCK_3e.js similarity index 99% rename from assets/cn_src_article_sort_insert_index.md.CmQ1YgOQ.js rename to assets/cn_src_article_sort_insert_index.md.DjxCK_3e.js index 877ddd618c..acb3ba9776 100644 --- a/assets/cn_src_article_sort_insert_index.md.CmQ1YgOQ.js +++ b/assets/cn_src_article_sort_insert_index.md.DjxCK_3e.js @@ -1,4 +1,4 @@ -import{_ as i}from"./chunks/insert.Bde3uDH4.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"插入排序(Insert Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/insert/index.md","filePath":"cn/src/article/sort/insert/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/insert/index.md"};function k(p,s,e,r,E,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          插入排序(Insert Sort)

          表现稳定的排序算法,因为无论什么数据进去都是 O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。优点是不占用额外的内存空间。工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

          算法描述

          • 从第一个元素开始,该元素可以认为已经被排序;
          • 取出下一个元素,在已经排序的元素序列中从后向前扫描;
          • 如果该元素(已排序)大于新元素,将该元素移到下一位置;
          • 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置;
          • 将新元素插入到该位置后;
          • 重复步骤 2~5。

          动图演示

          插入排序

          代码演示

          ts
          const insert = (list: number[]): number[] => {
          +import{_ as i}from"./chunks/insert.Bde3uDH4.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"插入排序(Insert Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/insert/index.md","filePath":"cn/src/article/sort/insert/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/insert/index.md"};function k(p,s,e,r,E,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          插入排序(Insert Sort)

          表现稳定的排序算法,因为无论什么数据进去都是 O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。优点是不占用额外的内存空间。工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

          算法描述

          • 从第一个元素开始,该元素可以认为已经被排序;
          • 取出下一个元素,在已经排序的元素序列中从后向前扫描;
          • 如果该元素(已排序)大于新元素,将该元素移到下一位置;
          • 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置;
          • 将新元素插入到该位置后;
          • 重复步骤 2~5。

          动图演示

          插入排序

          代码演示

          ts
          const insert = (list: number[]): number[] => {
             const size = list.length;
             for (let i = 1; i < size; i++) {
               const current = list[i];
          diff --git a/assets/cn_src_article_sort_insert_index.md.CmQ1YgOQ.lean.js b/assets/cn_src_article_sort_insert_index.md.DjxCK_3e.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_insert_index.md.CmQ1YgOQ.lean.js
          rename to assets/cn_src_article_sort_insert_index.md.DjxCK_3e.lean.js
          index 877ddd618c..acb3ba9776 100644
          --- a/assets/cn_src_article_sort_insert_index.md.CmQ1YgOQ.lean.js
          +++ b/assets/cn_src_article_sort_insert_index.md.DjxCK_3e.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/insert.Bde3uDH4.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"插入排序(Insert Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/insert/index.md","filePath":"cn/src/article/sort/insert/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/insert/index.md"};function k(p,s,e,r,E,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          插入排序(Insert Sort)

          表现稳定的排序算法,因为无论什么数据进去都是 O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。优点是不占用额外的内存空间。工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

          算法描述

          • 从第一个元素开始,该元素可以认为已经被排序;
          • 取出下一个元素,在已经排序的元素序列中从后向前扫描;
          • 如果该元素(已排序)大于新元素,将该元素移到下一位置;
          • 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置;
          • 将新元素插入到该位置后;
          • 重复步骤 2~5。

          动图演示

          插入排序

          代码演示

          ts
          const insert = (list: number[]): number[] => {
          +import{_ as i}from"./chunks/insert.Bde3uDH4.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"插入排序(Insert Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/insert/index.md","filePath":"cn/src/article/sort/insert/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/insert/index.md"};function k(p,s,e,r,E,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          插入排序(Insert Sort)

          表现稳定的排序算法,因为无论什么数据进去都是 O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。优点是不占用额外的内存空间。工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

          算法描述

          • 从第一个元素开始,该元素可以认为已经被排序;
          • 取出下一个元素,在已经排序的元素序列中从后向前扫描;
          • 如果该元素(已排序)大于新元素,将该元素移到下一位置;
          • 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置;
          • 将新元素插入到该位置后;
          • 重复步骤 2~5。

          动图演示

          插入排序

          代码演示

          ts
          const insert = (list: number[]): number[] => {
             const size = list.length;
             for (let i = 1; i < size; i++) {
               const current = list[i];
          diff --git a/assets/cn_src_article_sort_merge_index.md.MDU-inBg.js b/assets/cn_src_article_sort_merge_index.md.CkGKR7pJ.js
          similarity index 99%
          rename from assets/cn_src_article_sort_merge_index.md.MDU-inBg.js
          rename to assets/cn_src_article_sort_merge_index.md.CkGKR7pJ.js
          index 1781866b9e..ca5b3aff99 100644
          --- a/assets/cn_src_article_sort_merge_index.md.MDU-inBg.js
          +++ b/assets/cn_src_article_sort_merge_index.md.CkGKR7pJ.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/merge.D_M4N_iU.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"归并排序(Merge Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/merge/index.md","filePath":"cn/src/article/sort/merge/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/merge/index.md"};function t(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          归并排序(Merge Sort)

          归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为 2-路归并。

          算法描述

          • 把长度为 n 的输入序列分成两个长度为 n/2 的子序列;
          • 对这两个子序列分别采用归并排序;
          • 将两个排序好的子序列合并成一个最终的排序序列。

          动图演示

          归并排序

          代码演示

          ts
          const combine = (left: Array<number>, right: Array<number>) => {
          +import{_ as i}from"./chunks/merge.D_M4N_iU.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"归并排序(Merge Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/merge/index.md","filePath":"cn/src/article/sort/merge/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/merge/index.md"};function t(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          归并排序(Merge Sort)

          归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为 2-路归并。

          算法描述

          • 把长度为 n 的输入序列分成两个长度为 n/2 的子序列;
          • 对这两个子序列分别采用归并排序;
          • 将两个排序好的子序列合并成一个最终的排序序列。

          动图演示

          归并排序

          代码演示

          ts
          const combine = (left: Array<number>, right: Array<number>) => {
             const list: Array<number> = [];
             while (left.length > 0 && right.length > 0) {
               if (left[0] <= right[0]) {
          diff --git a/assets/cn_src_article_sort_merge_index.md.MDU-inBg.lean.js b/assets/cn_src_article_sort_merge_index.md.CkGKR7pJ.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_merge_index.md.MDU-inBg.lean.js
          rename to assets/cn_src_article_sort_merge_index.md.CkGKR7pJ.lean.js
          index 1781866b9e..ca5b3aff99 100644
          --- a/assets/cn_src_article_sort_merge_index.md.MDU-inBg.lean.js
          +++ b/assets/cn_src_article_sort_merge_index.md.CkGKR7pJ.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/merge.D_M4N_iU.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"归并排序(Merge Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/merge/index.md","filePath":"cn/src/article/sort/merge/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/merge/index.md"};function t(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          归并排序(Merge Sort)

          归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为 2-路归并。

          算法描述

          • 把长度为 n 的输入序列分成两个长度为 n/2 的子序列;
          • 对这两个子序列分别采用归并排序;
          • 将两个排序好的子序列合并成一个最终的排序序列。

          动图演示

          归并排序

          代码演示

          ts
          const combine = (left: Array<number>, right: Array<number>) => {
          +import{_ as i}from"./chunks/merge.D_M4N_iU.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"归并排序(Merge Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/merge/index.md","filePath":"cn/src/article/sort/merge/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/merge/index.md"};function t(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          归并排序(Merge Sort)

          归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为 2-路归并。

          算法描述

          • 把长度为 n 的输入序列分成两个长度为 n/2 的子序列;
          • 对这两个子序列分别采用归并排序;
          • 将两个排序好的子序列合并成一个最终的排序序列。

          动图演示

          归并排序

          代码演示

          ts
          const combine = (left: Array<number>, right: Array<number>) => {
             const list: Array<number> = [];
             while (left.length > 0 && right.length > 0) {
               if (left[0] <= right[0]) {
          diff --git a/assets/cn_src_article_sort_quick_index.md.CvZw-icp.js b/assets/cn_src_article_sort_quick_index.md.CGqy4-ZS.js
          similarity index 99%
          rename from assets/cn_src_article_sort_quick_index.md.CvZw-icp.js
          rename to assets/cn_src_article_sort_quick_index.md.CGqy4-ZS.js
          index 6f5f5463cb..5343aa8553 100644
          --- a/assets/cn_src_article_sort_quick_index.md.CvZw-icp.js
          +++ b/assets/cn_src_article_sort_quick_index.md.CGqy4-ZS.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/quick.WcLzRUPH.js";import{_ as a,o as n,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"快速排序(Quick Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/quick/index.md","filePath":"cn/src/article/sort/quick/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/quick/index.md"};function t(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          快速排序(Quick Sort)

          快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

          算法描述

          快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

          • 从数列中挑出一个元素,称为 “基准”(pivot);
          • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
          • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

          动图演示

          快速排序

          代码演示

          ts
          /**
          +import{_ as i}from"./chunks/quick.WcLzRUPH.js";import{_ as a,o as n,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"快速排序(Quick Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/quick/index.md","filePath":"cn/src/article/sort/quick/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/quick/index.md"};function t(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          快速排序(Quick Sort)

          快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

          算法描述

          快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

          • 从数列中挑出一个元素,称为 “基准”(pivot);
          • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
          • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

          动图演示

          快速排序

          代码演示

          ts
          /**
            * @description: 设置基准值pivot
            * @param {Array} list
            * @param {number} left
          diff --git a/assets/cn_src_article_sort_quick_index.md.CvZw-icp.lean.js b/assets/cn_src_article_sort_quick_index.md.CGqy4-ZS.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_quick_index.md.CvZw-icp.lean.js
          rename to assets/cn_src_article_sort_quick_index.md.CGqy4-ZS.lean.js
          index 6f5f5463cb..5343aa8553 100644
          --- a/assets/cn_src_article_sort_quick_index.md.CvZw-icp.lean.js
          +++ b/assets/cn_src_article_sort_quick_index.md.CGqy4-ZS.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/quick.WcLzRUPH.js";import{_ as a,o as n,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"快速排序(Quick Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/quick/index.md","filePath":"cn/src/article/sort/quick/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/quick/index.md"};function t(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          快速排序(Quick Sort)

          快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

          算法描述

          快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

          • 从数列中挑出一个元素,称为 “基准”(pivot);
          • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
          • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

          动图演示

          快速排序

          代码演示

          ts
          /**
          +import{_ as i}from"./chunks/quick.WcLzRUPH.js";import{_ as a,o as n,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"快速排序(Quick Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/quick/index.md","filePath":"cn/src/article/sort/quick/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/quick/index.md"};function t(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          快速排序(Quick Sort)

          快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

          算法描述

          快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

          • 从数列中挑出一个元素,称为 “基准”(pivot);
          • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
          • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

          动图演示

          快速排序

          代码演示

          ts
          /**
            * @description: 设置基准值pivot
            * @param {Array} list
            * @param {number} left
          diff --git a/assets/cn_src_article_sort_radix_index.md.D1vfzfWU.js b/assets/cn_src_article_sort_radix_index.md.DL17V-7-.js
          similarity index 99%
          rename from assets/cn_src_article_sort_radix_index.md.D1vfzfWU.js
          rename to assets/cn_src_article_sort_radix_index.md.DL17V-7-.js
          index a8116cdffe..33a3614b2b 100644
          --- a/assets/cn_src_article_sort_radix_index.md.D1vfzfWU.js
          +++ b/assets/cn_src_article_sort_radix_index.md.DL17V-7-.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/radix.CHOmrmB0.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"基数排序(Radix Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/radix/index.md","filePath":"cn/src/article/sort/radix/index.md","lastUpdated":1728828157000}'),t={name:"cn/src/article/sort/radix/index.md"};function l(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          基数排序(Radix Sort)

          基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。桶排序扩展,类似于指定桶排序按位数排序规则,同时能利用计数排序适用于小范围数的特点。

          算法描述

          • 取得数组中的最大数,并取得位数;
          • arr 为原始数组,从最低位开始取每个位组成 radix 数组;
          • 对 radix 进行计数排序(利用计数排序适用于小范围数的特点);

          动图演示

          基数排序

          代码演示

          ts
          const getMax = (list: Array<number>) => {
          +import{_ as i}from"./chunks/radix.CHOmrmB0.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"基数排序(Radix Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/radix/index.md","filePath":"cn/src/article/sort/radix/index.md","lastUpdated":1728921295000}'),t={name:"cn/src/article/sort/radix/index.md"};function l(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          基数排序(Radix Sort)

          基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。桶排序扩展,类似于指定桶排序按位数排序规则,同时能利用计数排序适用于小范围数的特点。

          算法描述

          • 取得数组中的最大数,并取得位数;
          • arr 为原始数组,从最低位开始取每个位组成 radix 数组;
          • 对 radix 进行计数排序(利用计数排序适用于小范围数的特点);

          动图演示

          基数排序

          代码演示

          ts
          const getMax = (list: Array<number>) => {
             let max = list[0];
             for (let i = 0; i < list.length; i++) {
               if (max < list[i]) {
          diff --git a/assets/cn_src_article_sort_radix_index.md.D1vfzfWU.lean.js b/assets/cn_src_article_sort_radix_index.md.DL17V-7-.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_radix_index.md.D1vfzfWU.lean.js
          rename to assets/cn_src_article_sort_radix_index.md.DL17V-7-.lean.js
          index a8116cdffe..33a3614b2b 100644
          --- a/assets/cn_src_article_sort_radix_index.md.D1vfzfWU.lean.js
          +++ b/assets/cn_src_article_sort_radix_index.md.DL17V-7-.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/radix.CHOmrmB0.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"基数排序(Radix Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/radix/index.md","filePath":"cn/src/article/sort/radix/index.md","lastUpdated":1728828157000}'),t={name:"cn/src/article/sort/radix/index.md"};function l(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          基数排序(Radix Sort)

          基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。桶排序扩展,类似于指定桶排序按位数排序规则,同时能利用计数排序适用于小范围数的特点。

          算法描述

          • 取得数组中的最大数,并取得位数;
          • arr 为原始数组,从最低位开始取每个位组成 radix 数组;
          • 对 radix 进行计数排序(利用计数排序适用于小范围数的特点);

          动图演示

          基数排序

          代码演示

          ts
          const getMax = (list: Array<number>) => {
          +import{_ as i}from"./chunks/radix.CHOmrmB0.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"基数排序(Radix Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/radix/index.md","filePath":"cn/src/article/sort/radix/index.md","lastUpdated":1728921295000}'),t={name:"cn/src/article/sort/radix/index.md"};function l(p,s,e,E,r,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

          基数排序(Radix Sort)

          基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。桶排序扩展,类似于指定桶排序按位数排序规则,同时能利用计数排序适用于小范围数的特点。

          算法描述

          • 取得数组中的最大数,并取得位数;
          • arr 为原始数组,从最低位开始取每个位组成 radix 数组;
          • 对 radix 进行计数排序(利用计数排序适用于小范围数的特点);

          动图演示

          基数排序

          代码演示

          ts
          const getMax = (list: Array<number>) => {
             let max = list[0];
             for (let i = 0; i < list.length; i++) {
               if (max < list[i]) {
          diff --git a/assets/cn_src_article_sort_select_index.md.HS1vLdcG.js b/assets/cn_src_article_sort_select_index.md.CnGat9lb.js
          similarity index 99%
          rename from assets/cn_src_article_sort_select_index.md.HS1vLdcG.js
          rename to assets/cn_src_article_sort_select_index.md.CnGat9lb.js
          index 3d69e77926..ccd3f0191e 100644
          --- a/assets/cn_src_article_sort_select_index.md.HS1vLdcG.js
          +++ b/assets/cn_src_article_sort_select_index.md.CnGat9lb.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/select.BGReufCV.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"选择排序(Selection Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/select/index.md","filePath":"cn/src/article/sort/select/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/select/index.md"};function k(p,s,e,E,r,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          选择排序(Selection Sort)

          选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

          算法描述

          n 个记录的直接选择排序可经过 n-1 趟直接选择排序得到有序结果。具体算法描述如下:

          • 初始状态:无序区为 R[1..n],有序区为空;
          • 第 i 趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为 R[1..i-1]和 R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第 1 个记录 R 交换,使 R[1..i]和 R[i+1..n)分别变为记录个数增加 1 个的新有序区和记录个数减少 1 个的新无序区;
          • n-1 趟结束,数组有序化了。

          动图演示

          选择排序

          代码实现

          js
          const select = (list: number[]): number[] => {
          +import{_ as i}from"./chunks/select.BGReufCV.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"选择排序(Selection Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/select/index.md","filePath":"cn/src/article/sort/select/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/select/index.md"};function k(p,s,e,E,r,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          选择排序(Selection Sort)

          选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

          算法描述

          n 个记录的直接选择排序可经过 n-1 趟直接选择排序得到有序结果。具体算法描述如下:

          • 初始状态:无序区为 R[1..n],有序区为空;
          • 第 i 趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为 R[1..i-1]和 R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第 1 个记录 R 交换,使 R[1..i]和 R[i+1..n)分别变为记录个数增加 1 个的新有序区和记录个数减少 1 个的新无序区;
          • n-1 趟结束,数组有序化了。

          动图演示

          选择排序

          代码实现

          js
          const select = (list: number[]): number[] => {
             const size = list.length;
             for (let i = 0; i < size; i++) {
               let minIndex = i;
          diff --git a/assets/cn_src_article_sort_select_index.md.HS1vLdcG.lean.js b/assets/cn_src_article_sort_select_index.md.CnGat9lb.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_select_index.md.HS1vLdcG.lean.js
          rename to assets/cn_src_article_sort_select_index.md.CnGat9lb.lean.js
          index 3d69e77926..ccd3f0191e 100644
          --- a/assets/cn_src_article_sort_select_index.md.HS1vLdcG.lean.js
          +++ b/assets/cn_src_article_sort_select_index.md.CnGat9lb.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/select.BGReufCV.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"选择排序(Selection Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/select/index.md","filePath":"cn/src/article/sort/select/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/article/sort/select/index.md"};function k(p,s,e,E,r,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          选择排序(Selection Sort)

          选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

          算法描述

          n 个记录的直接选择排序可经过 n-1 趟直接选择排序得到有序结果。具体算法描述如下:

          • 初始状态:无序区为 R[1..n],有序区为空;
          • 第 i 趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为 R[1..i-1]和 R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第 1 个记录 R 交换,使 R[1..i]和 R[i+1..n)分别变为记录个数增加 1 个的新有序区和记录个数减少 1 个的新无序区;
          • n-1 趟结束,数组有序化了。

          动图演示

          选择排序

          代码实现

          js
          const select = (list: number[]): number[] => {
          +import{_ as i}from"./chunks/select.BGReufCV.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"选择排序(Selection Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/select/index.md","filePath":"cn/src/article/sort/select/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/article/sort/select/index.md"};function k(p,s,e,E,r,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          选择排序(Selection Sort)

          选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

          算法描述

          n 个记录的直接选择排序可经过 n-1 趟直接选择排序得到有序结果。具体算法描述如下:

          • 初始状态:无序区为 R[1..n],有序区为空;
          • 第 i 趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为 R[1..i-1]和 R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第 1 个记录 R 交换,使 R[1..i]和 R[i+1..n)分别变为记录个数增加 1 个的新有序区和记录个数减少 1 个的新无序区;
          • n-1 趟结束,数组有序化了。

          动图演示

          选择排序

          代码实现

          js
          const select = (list: number[]): number[] => {
             const size = list.length;
             for (let i = 0; i < size; i++) {
               let minIndex = i;
          diff --git a/assets/cn_src_article_sort_shell_index.md.DecAJ1tS.js b/assets/cn_src_article_sort_shell_index.md.DLjGy-JA.js
          similarity index 99%
          rename from assets/cn_src_article_sort_shell_index.md.DecAJ1tS.js
          rename to assets/cn_src_article_sort_shell_index.md.DLjGy-JA.js
          index eff34ce5d5..a9d08c5e39 100644
          --- a/assets/cn_src_article_sort_shell_index.md.DecAJ1tS.js
          +++ b/assets/cn_src_article_sort_shell_index.md.DLjGy-JA.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/shell.CGEkKxrp.js";import{_ as a,o as n,c as h,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"希尔排序(Shell Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/shell/index.md","filePath":"cn/src/article/sort/shell/index.md","lastUpdated":1728828157000}'),t={name:"cn/src/article/sort/shell/index.md"};function k(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l('

          希尔排序(Shell Sort)

          1959 年 Shell 发明,第一个突破 O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。

          算法描述

          先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

          • 选择一个增量序列 t1,t2,…,tk,其中 ti>tj,tk=1;
          • 按增量序列个数 k,对序列进行 k 趟排序;
          • 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

          动图演示

          希尔排序

          代码实现

          js
          /**
          +import{_ as i}from"./chunks/shell.CGEkKxrp.js";import{_ as a,o as n,c as h,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"希尔排序(Shell Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/shell/index.md","filePath":"cn/src/article/sort/shell/index.md","lastUpdated":1728921295000}'),t={name:"cn/src/article/sort/shell/index.md"};function k(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l('

          希尔排序(Shell Sort)

          1959 年 Shell 发明,第一个突破 O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。

          算法描述

          先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

          • 选择一个增量序列 t1,t2,…,tk,其中 ti>tj,tk=1;
          • 按增量序列个数 k,对序列进行 k 趟排序;
          • 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

          动图演示

          希尔排序

          代码实现

          js
          /**
            * @description: 希尔排序,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
            * @param {Array} list
            * @return {Array}
          diff --git a/assets/cn_src_article_sort_shell_index.md.DecAJ1tS.lean.js b/assets/cn_src_article_sort_shell_index.md.DLjGy-JA.lean.js
          similarity index 99%
          rename from assets/cn_src_article_sort_shell_index.md.DecAJ1tS.lean.js
          rename to assets/cn_src_article_sort_shell_index.md.DLjGy-JA.lean.js
          index eff34ce5d5..a9d08c5e39 100644
          --- a/assets/cn_src_article_sort_shell_index.md.DecAJ1tS.lean.js
          +++ b/assets/cn_src_article_sort_shell_index.md.DLjGy-JA.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i}from"./chunks/shell.CGEkKxrp.js";import{_ as a,o as n,c as h,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"希尔排序(Shell Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/shell/index.md","filePath":"cn/src/article/sort/shell/index.md","lastUpdated":1728828157000}'),t={name:"cn/src/article/sort/shell/index.md"};function k(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l('

          希尔排序(Shell Sort)

          1959 年 Shell 发明,第一个突破 O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。

          算法描述

          先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

          • 选择一个增量序列 t1,t2,…,tk,其中 ti>tj,tk=1;
          • 按增量序列个数 k,对序列进行 k 趟排序;
          • 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

          动图演示

          希尔排序

          代码实现

          js
          /**
          +import{_ as i}from"./chunks/shell.CGEkKxrp.js";import{_ as a,o as n,c as h,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"希尔排序(Shell Sort)","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/sort/shell/index.md","filePath":"cn/src/article/sort/shell/index.md","lastUpdated":1728921295000}'),t={name:"cn/src/article/sort/shell/index.md"};function k(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l('

          希尔排序(Shell Sort)

          1959 年 Shell 发明,第一个突破 O(n2)的排序算法,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。

          算法描述

          先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:

          • 选择一个增量序列 t1,t2,…,tk,其中 ti>tj,tk=1;
          • 按增量序列个数 k,对序列进行 k 趟排序;
          • 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。

          动图演示

          希尔排序

          代码实现

          js
          /**
            * @description: 希尔排序,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
            * @param {Array} list
            * @return {Array}
          diff --git a/assets/cn_src_article_systemDesign.md.hOp1x72G.js b/assets/cn_src_article_systemDesign.md.6LK-pZuK.js
          similarity index 97%
          rename from assets/cn_src_article_systemDesign.md.hOp1x72G.js
          rename to assets/cn_src_article_systemDesign.md.6LK-pZuK.js
          index 377167beb1..2eddf6bca3 100644
          --- a/assets/cn_src_article_systemDesign.md.hOp1x72G.js
          +++ b/assets/cn_src_article_systemDesign.md.6LK-pZuK.js
          @@ -1 +1 @@
          -import{_ as e,o as t,c as r,a3 as s}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"如何处理一个系统设计","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/systemDesign.md","filePath":"cn/src/article/systemDesign.md","lastUpdated":1728828157000}'),o={name:"cn/src/article/systemDesign.md"};function i(n,a,l,p,c,d){return t(),r("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s('

          如何处理一个系统设计

          系统设计是一个开放式的对话。他们期望你去主导这个对话。

          你可以使用下面的步骤来指引讨论。为了巩固这个过程,请使用下面的步骤完成系统设计的面试题和解答这个章节。

          第一步:描述使用场景,约束和假设

          把所有需要的东西聚集在一起,审视问题。不停的提问,以至于我们可以明确使用场景和约束。讨论假设。

          谁会使用它? 他们会怎样使用它? 有多少用户? 系统的作用是什么? 系统的输入输出分别是什么? 我们希望处理多少数据? 我们希望每秒钟处理多少请求? 我们希望的读写比率?

          第二步:创造一个高层级的设计

          使用所有重要的组件来描绘出一个高层级的设计。

          画出主要的组件和连接 证明你的想法

          第三步:设计核心组件

          对每一个核心组件进行详细深入的分析。举例来说,如果你被问到设计一个 url 缩写服务,开始讨论:

          生成并储存一个完整 url 的 hash MD5 和 Base62 Hash 碰撞 SQL 还是 NoSQL 数据库模型 将一个 hashed url 翻译成完整的 url 数据库查找 API 和面向对象设计

          第四步:扩展设计

          确认和处理瓶颈以及一些限制。举例来说就是你需要下面的这些来完成扩展性的议题吗?

          负载均衡 水平扩展 缓存 数据库分片 论述可能的解决办法和代价。每件事情需要取舍。可以使用可扩展系统的设计原则来处理瓶颈。

          ',15)]))}const m=e(o,[["render",i]]);export{u as __pageData,m as default}; +import{_ as e,o as t,c as r,a3 as s}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"如何处理一个系统设计","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/systemDesign.md","filePath":"cn/src/article/systemDesign.md","lastUpdated":1728921295000}'),o={name:"cn/src/article/systemDesign.md"};function i(n,a,l,p,c,d){return t(),r("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s('

          如何处理一个系统设计

          系统设计是一个开放式的对话。他们期望你去主导这个对话。

          你可以使用下面的步骤来指引讨论。为了巩固这个过程,请使用下面的步骤完成系统设计的面试题和解答这个章节。

          第一步:描述使用场景,约束和假设

          把所有需要的东西聚集在一起,审视问题。不停的提问,以至于我们可以明确使用场景和约束。讨论假设。

          谁会使用它? 他们会怎样使用它? 有多少用户? 系统的作用是什么? 系统的输入输出分别是什么? 我们希望处理多少数据? 我们希望每秒钟处理多少请求? 我们希望的读写比率?

          第二步:创造一个高层级的设计

          使用所有重要的组件来描绘出一个高层级的设计。

          画出主要的组件和连接 证明你的想法

          第三步:设计核心组件

          对每一个核心组件进行详细深入的分析。举例来说,如果你被问到设计一个 url 缩写服务,开始讨论:

          生成并储存一个完整 url 的 hash MD5 和 Base62 Hash 碰撞 SQL 还是 NoSQL 数据库模型 将一个 hashed url 翻译成完整的 url 数据库查找 API 和面向对象设计

          第四步:扩展设计

          确认和处理瓶颈以及一些限制。举例来说就是你需要下面的这些来完成扩展性的议题吗?

          负载均衡 水平扩展 缓存 数据库分片 论述可能的解决办法和代价。每件事情需要取舍。可以使用可扩展系统的设计原则来处理瓶颈。

          ',15)]))}const m=e(o,[["render",i]]);export{u as __pageData,m as default}; diff --git a/assets/cn_src_article_systemDesign.md.hOp1x72G.lean.js b/assets/cn_src_article_systemDesign.md.6LK-pZuK.lean.js similarity index 97% rename from assets/cn_src_article_systemDesign.md.hOp1x72G.lean.js rename to assets/cn_src_article_systemDesign.md.6LK-pZuK.lean.js index 377167beb1..2eddf6bca3 100644 --- a/assets/cn_src_article_systemDesign.md.hOp1x72G.lean.js +++ b/assets/cn_src_article_systemDesign.md.6LK-pZuK.lean.js @@ -1 +1 @@ -import{_ as e,o as t,c as r,a3 as s}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"如何处理一个系统设计","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/systemDesign.md","filePath":"cn/src/article/systemDesign.md","lastUpdated":1728828157000}'),o={name:"cn/src/article/systemDesign.md"};function i(n,a,l,p,c,d){return t(),r("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s('

          如何处理一个系统设计

          系统设计是一个开放式的对话。他们期望你去主导这个对话。

          你可以使用下面的步骤来指引讨论。为了巩固这个过程,请使用下面的步骤完成系统设计的面试题和解答这个章节。

          第一步:描述使用场景,约束和假设

          把所有需要的东西聚集在一起,审视问题。不停的提问,以至于我们可以明确使用场景和约束。讨论假设。

          谁会使用它? 他们会怎样使用它? 有多少用户? 系统的作用是什么? 系统的输入输出分别是什么? 我们希望处理多少数据? 我们希望每秒钟处理多少请求? 我们希望的读写比率?

          第二步:创造一个高层级的设计

          使用所有重要的组件来描绘出一个高层级的设计。

          画出主要的组件和连接 证明你的想法

          第三步:设计核心组件

          对每一个核心组件进行详细深入的分析。举例来说,如果你被问到设计一个 url 缩写服务,开始讨论:

          生成并储存一个完整 url 的 hash MD5 和 Base62 Hash 碰撞 SQL 还是 NoSQL 数据库模型 将一个 hashed url 翻译成完整的 url 数据库查找 API 和面向对象设计

          第四步:扩展设计

          确认和处理瓶颈以及一些限制。举例来说就是你需要下面的这些来完成扩展性的议题吗?

          负载均衡 水平扩展 缓存 数据库分片 论述可能的解决办法和代价。每件事情需要取舍。可以使用可扩展系统的设计原则来处理瓶颈。

          ',15)]))}const m=e(o,[["render",i]]);export{u as __pageData,m as default}; +import{_ as e,o as t,c as r,a3 as s}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"如何处理一个系统设计","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/systemDesign.md","filePath":"cn/src/article/systemDesign.md","lastUpdated":1728921295000}'),o={name:"cn/src/article/systemDesign.md"};function i(n,a,l,p,c,d){return t(),r("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s('

          如何处理一个系统设计

          系统设计是一个开放式的对话。他们期望你去主导这个对话。

          你可以使用下面的步骤来指引讨论。为了巩固这个过程,请使用下面的步骤完成系统设计的面试题和解答这个章节。

          第一步:描述使用场景,约束和假设

          把所有需要的东西聚集在一起,审视问题。不停的提问,以至于我们可以明确使用场景和约束。讨论假设。

          谁会使用它? 他们会怎样使用它? 有多少用户? 系统的作用是什么? 系统的输入输出分别是什么? 我们希望处理多少数据? 我们希望每秒钟处理多少请求? 我们希望的读写比率?

          第二步:创造一个高层级的设计

          使用所有重要的组件来描绘出一个高层级的设计。

          画出主要的组件和连接 证明你的想法

          第三步:设计核心组件

          对每一个核心组件进行详细深入的分析。举例来说,如果你被问到设计一个 url 缩写服务,开始讨论:

          生成并储存一个完整 url 的 hash MD5 和 Base62 Hash 碰撞 SQL 还是 NoSQL 数据库模型 将一个 hashed url 翻译成完整的 url 数据库查找 API 和面向对象设计

          第四步:扩展设计

          确认和处理瓶颈以及一些限制。举例来说就是你需要下面的这些来完成扩展性的议题吗?

          负载均衡 水平扩展 缓存 数据库分片 论述可能的解决办法和代价。每件事情需要取舍。可以使用可扩展系统的设计原则来处理瓶颈。

          ',15)]))}const m=e(o,[["render",i]]);export{u as __pageData,m as default}; diff --git a/assets/cn_src_article_typescript_calculate.md.CNAvvheA.js b/assets/cn_src_article_typescript_calculate.md.CC_IXoWD.js similarity index 99% rename from assets/cn_src_article_typescript_calculate.md.CNAvvheA.js rename to assets/cn_src_article_typescript_calculate.md.CC_IXoWD.js index aca5e28a25..9713c313b4 100644 --- a/assets/cn_src_article_typescript_calculate.md.CNAvvheA.js +++ b/assets/cn_src_article_typescript_calculate.md.CC_IXoWD.js @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"数组长度做计数","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/calculate.md","filePath":"cn/src/article/typescript/calculate.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/typescript/calculate.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          数组长度做计数

          类型系统不是图灵完备,各种逻辑都能写么,但好像没发现数值相关的逻辑。

          没错,数值相关的逻辑比较绕,被我单独摘了出来,就是这节要讲的内容。

          这是类型体操的第四个套路:数组长度做计数。

          TypeScript 类型系统没有加减乘除运算符,怎么做数值运算呢?

          不知道大家有没有注意到数组类型取 length 就是数值。

          比如:

          ts
          type num1 = [unknown]['length'];
          +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"数组长度做计数","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/calculate.md","filePath":"cn/src/article/typescript/calculate.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/typescript/calculate.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          数组长度做计数

          类型系统不是图灵完备,各种逻辑都能写么,但好像没发现数值相关的逻辑。

          没错,数值相关的逻辑比较绕,被我单独摘了出来,就是这节要讲的内容。

          这是类型体操的第四个套路:数组长度做计数。

          TypeScript 类型系统没有加减乘除运算符,怎么做数值运算呢?

          不知道大家有没有注意到数组类型取 length 就是数值。

          比如:

          ts
          type num1 = [unknown]['length'];
           // type num1 = 1
           type num2 = [unknown, unknown]['length'];
           // type num1 = 2
          diff --git a/assets/cn_src_article_typescript_calculate.md.CNAvvheA.lean.js b/assets/cn_src_article_typescript_calculate.md.CC_IXoWD.lean.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_calculate.md.CNAvvheA.lean.js
          rename to assets/cn_src_article_typescript_calculate.md.CC_IXoWD.lean.js
          index aca5e28a25..9713c313b4 100644
          --- a/assets/cn_src_article_typescript_calculate.md.CNAvvheA.lean.js
          +++ b/assets/cn_src_article_typescript_calculate.md.CC_IXoWD.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"数组长度做计数","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/calculate.md","filePath":"cn/src/article/typescript/calculate.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/typescript/calculate.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          数组长度做计数

          类型系统不是图灵完备,各种逻辑都能写么,但好像没发现数值相关的逻辑。

          没错,数值相关的逻辑比较绕,被我单独摘了出来,就是这节要讲的内容。

          这是类型体操的第四个套路:数组长度做计数。

          TypeScript 类型系统没有加减乘除运算符,怎么做数值运算呢?

          不知道大家有没有注意到数组类型取 length 就是数值。

          比如:

          ts
          type num1 = [unknown]['length'];
          +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"数组长度做计数","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/calculate.md","filePath":"cn/src/article/typescript/calculate.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/typescript/calculate.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          数组长度做计数

          类型系统不是图灵完备,各种逻辑都能写么,但好像没发现数值相关的逻辑。

          没错,数值相关的逻辑比较绕,被我单独摘了出来,就是这节要讲的内容。

          这是类型体操的第四个套路:数组长度做计数。

          TypeScript 类型系统没有加减乘除运算符,怎么做数值运算呢?

          不知道大家有没有注意到数组类型取 length 就是数值。

          比如:

          ts
          type num1 = [unknown]['length'];
           // type num1 = 1
           type num2 = [unknown, unknown]['length'];
           // type num1 = 2
          diff --git a/assets/cn_src_article_typescript_index.md.1jbAHunE.js b/assets/cn_src_article_typescript_index.md.BUmi2po9.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_index.md.1jbAHunE.js
          rename to assets/cn_src_article_typescript_index.md.BUmi2po9.js
          index 6d048fadb8..6abe861c25 100644
          --- a/assets/cn_src_article_typescript_index.md.1jbAHunE.js
          +++ b/assets/cn_src_article_typescript_index.md.BUmi2po9.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 的类型系统","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/index.md","filePath":"cn/src/article/typescript/index.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/typescript/index.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          TypeScript 的类型系统

          一.类型是什么

          类型具体点来说就是指 number、boolean、string 等基础类型和 Object、Function 等复合类型,它们是编程语言提供的对不同内容的抽象:

          • 不同类型变量占据的内存大小不同: boolean 类型的变量会分配 4 个字节的内存,而 number 类型的变量则会分配 8 个字节的内存,给变量声明了不同的类型就代表了会占据不同的内存空间。

          • 不同类型变量可做的操作不同: number 类型可以做加减乘除等运算,boolean 就不可以,复合类型中不同类型的对象可用的方法不同,比如 Date 和 RegExp,变量的类型不同代表可以对该变量做的操作就不同。

          有了类型,那我们的操作必须和类型相匹配,否则就会报错,这就是类型检查。

          如果能保证对某种类型只做该类型允许的操作,这就叫做类型安全。

          类型检查可以在运行时做,也可以运行之前的编译期做。这是两种不同的类型,前者叫做动态类型检查,后者叫做静态类型检查。

          两种类型检查各有优缺点。动态类型检查 在源码中不保留类型信息,对某个变量赋什么值、做什么操作都是允许的,写代码很灵活。但这也埋下了类型不安全的隐患,比如对 string 做了乘除,对 Date 对象调用了 exec 方法,这些都是运行时才能检查出来的错误。

          其中,最常见的错误应该是 “null is not an object”、“undefined is not a function” 之类的了,写代码时没发现类型不匹配,到了运行的时候才发现,就会有很多这种报错。

          所以,动态类型虽然代码写起来简单,但代码中很容易藏着一些类型不匹配的隐患。

          静态类型检查则是在源码中保留类型信息,声明变量要指定类型,对变量做的操作要和类型匹配,会有专门的编译器在编译期间做检查。

          静态类型给写代码增加了一些难度,因为你除了要考虑代码要表达的逻辑之外,还要考虑类型逻辑:变量是什么类型的、是不是匹配、要不要做类型转换等。

          不过,静态类型也消除了类型不安全的隐患,因为在编译期间就做了类型检查,就不会出现对 string 做了乘除,调用了 Date 的 exec 方法这类问题。

          所以,静态类型虽然代码写起来要考虑的问题多一些,会复杂一些,但是却消除了代码中潜藏类型不安全问题的可能。

          知道了动态类型检查和静态类型检查的区别,我们自然可以得出这样的结论:

          动态类型只适合简单的场景,对于大项目却不太合适,因为代码中可能藏着的隐患太多了,万一线上报一个类型不匹配的错误,那可能就是大问题。

          而静态类型虽然会增加写代码的成本,但是却能更好的保证代码的健壮性,减少 Bug 率。

          所以,大型项目注定会用静态类型语言开发。

          二.类型系统的分类

          1.简单的类型系统

          变量、函数、类等都可以声明类型,编译器会基于声明的类型做类型检查,类型不匹配时会报错。

          这是最基础的类型系统,能保证类型安全,但有些死板。

          比如一个 add 函数既可以做整数加法、又可以做浮点数加法,却需要声明两个函数:

          c
          int add(int a, int b) {
          +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 的类型系统","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/index.md","filePath":"cn/src/article/typescript/index.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/typescript/index.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          TypeScript 的类型系统

          一.类型是什么

          类型具体点来说就是指 number、boolean、string 等基础类型和 Object、Function 等复合类型,它们是编程语言提供的对不同内容的抽象:

          • 不同类型变量占据的内存大小不同: boolean 类型的变量会分配 4 个字节的内存,而 number 类型的变量则会分配 8 个字节的内存,给变量声明了不同的类型就代表了会占据不同的内存空间。

          • 不同类型变量可做的操作不同: number 类型可以做加减乘除等运算,boolean 就不可以,复合类型中不同类型的对象可用的方法不同,比如 Date 和 RegExp,变量的类型不同代表可以对该变量做的操作就不同。

          有了类型,那我们的操作必须和类型相匹配,否则就会报错,这就是类型检查。

          如果能保证对某种类型只做该类型允许的操作,这就叫做类型安全。

          类型检查可以在运行时做,也可以运行之前的编译期做。这是两种不同的类型,前者叫做动态类型检查,后者叫做静态类型检查。

          两种类型检查各有优缺点。动态类型检查 在源码中不保留类型信息,对某个变量赋什么值、做什么操作都是允许的,写代码很灵活。但这也埋下了类型不安全的隐患,比如对 string 做了乘除,对 Date 对象调用了 exec 方法,这些都是运行时才能检查出来的错误。

          其中,最常见的错误应该是 “null is not an object”、“undefined is not a function” 之类的了,写代码时没发现类型不匹配,到了运行的时候才发现,就会有很多这种报错。

          所以,动态类型虽然代码写起来简单,但代码中很容易藏着一些类型不匹配的隐患。

          静态类型检查则是在源码中保留类型信息,声明变量要指定类型,对变量做的操作要和类型匹配,会有专门的编译器在编译期间做检查。

          静态类型给写代码增加了一些难度,因为你除了要考虑代码要表达的逻辑之外,还要考虑类型逻辑:变量是什么类型的、是不是匹配、要不要做类型转换等。

          不过,静态类型也消除了类型不安全的隐患,因为在编译期间就做了类型检查,就不会出现对 string 做了乘除,调用了 Date 的 exec 方法这类问题。

          所以,静态类型虽然代码写起来要考虑的问题多一些,会复杂一些,但是却消除了代码中潜藏类型不安全问题的可能。

          知道了动态类型检查和静态类型检查的区别,我们自然可以得出这样的结论:

          动态类型只适合简单的场景,对于大项目却不太合适,因为代码中可能藏着的隐患太多了,万一线上报一个类型不匹配的错误,那可能就是大问题。

          而静态类型虽然会增加写代码的成本,但是却能更好的保证代码的健壮性,减少 Bug 率。

          所以,大型项目注定会用静态类型语言开发。

          二.类型系统的分类

          1.简单的类型系统

          变量、函数、类等都可以声明类型,编译器会基于声明的类型做类型检查,类型不匹配时会报错。

          这是最基础的类型系统,能保证类型安全,但有些死板。

          比如一个 add 函数既可以做整数加法、又可以做浮点数加法,却需要声明两个函数:

          c
          int add(int a, int b) {
               return a + b;
           }
           
          diff --git a/assets/cn_src_article_typescript_index.md.1jbAHunE.lean.js b/assets/cn_src_article_typescript_index.md.BUmi2po9.lean.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_index.md.1jbAHunE.lean.js
          rename to assets/cn_src_article_typescript_index.md.BUmi2po9.lean.js
          index 6d048fadb8..6abe861c25 100644
          --- a/assets/cn_src_article_typescript_index.md.1jbAHunE.lean.js
          +++ b/assets/cn_src_article_typescript_index.md.BUmi2po9.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 的类型系统","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/index.md","filePath":"cn/src/article/typescript/index.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/typescript/index.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          TypeScript 的类型系统

          一.类型是什么

          类型具体点来说就是指 number、boolean、string 等基础类型和 Object、Function 等复合类型,它们是编程语言提供的对不同内容的抽象:

          • 不同类型变量占据的内存大小不同: boolean 类型的变量会分配 4 个字节的内存,而 number 类型的变量则会分配 8 个字节的内存,给变量声明了不同的类型就代表了会占据不同的内存空间。

          • 不同类型变量可做的操作不同: number 类型可以做加减乘除等运算,boolean 就不可以,复合类型中不同类型的对象可用的方法不同,比如 Date 和 RegExp,变量的类型不同代表可以对该变量做的操作就不同。

          有了类型,那我们的操作必须和类型相匹配,否则就会报错,这就是类型检查。

          如果能保证对某种类型只做该类型允许的操作,这就叫做类型安全。

          类型检查可以在运行时做,也可以运行之前的编译期做。这是两种不同的类型,前者叫做动态类型检查,后者叫做静态类型检查。

          两种类型检查各有优缺点。动态类型检查 在源码中不保留类型信息,对某个变量赋什么值、做什么操作都是允许的,写代码很灵活。但这也埋下了类型不安全的隐患,比如对 string 做了乘除,对 Date 对象调用了 exec 方法,这些都是运行时才能检查出来的错误。

          其中,最常见的错误应该是 “null is not an object”、“undefined is not a function” 之类的了,写代码时没发现类型不匹配,到了运行的时候才发现,就会有很多这种报错。

          所以,动态类型虽然代码写起来简单,但代码中很容易藏着一些类型不匹配的隐患。

          静态类型检查则是在源码中保留类型信息,声明变量要指定类型,对变量做的操作要和类型匹配,会有专门的编译器在编译期间做检查。

          静态类型给写代码增加了一些难度,因为你除了要考虑代码要表达的逻辑之外,还要考虑类型逻辑:变量是什么类型的、是不是匹配、要不要做类型转换等。

          不过,静态类型也消除了类型不安全的隐患,因为在编译期间就做了类型检查,就不会出现对 string 做了乘除,调用了 Date 的 exec 方法这类问题。

          所以,静态类型虽然代码写起来要考虑的问题多一些,会复杂一些,但是却消除了代码中潜藏类型不安全问题的可能。

          知道了动态类型检查和静态类型检查的区别,我们自然可以得出这样的结论:

          动态类型只适合简单的场景,对于大项目却不太合适,因为代码中可能藏着的隐患太多了,万一线上报一个类型不匹配的错误,那可能就是大问题。

          而静态类型虽然会增加写代码的成本,但是却能更好的保证代码的健壮性,减少 Bug 率。

          所以,大型项目注定会用静态类型语言开发。

          二.类型系统的分类

          1.简单的类型系统

          变量、函数、类等都可以声明类型,编译器会基于声明的类型做类型检查,类型不匹配时会报错。

          这是最基础的类型系统,能保证类型安全,但有些死板。

          比如一个 add 函数既可以做整数加法、又可以做浮点数加法,却需要声明两个函数:

          c
          int add(int a, int b) {
          +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 的类型系统","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/index.md","filePath":"cn/src/article/typescript/index.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/typescript/index.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          TypeScript 的类型系统

          一.类型是什么

          类型具体点来说就是指 number、boolean、string 等基础类型和 Object、Function 等复合类型,它们是编程语言提供的对不同内容的抽象:

          • 不同类型变量占据的内存大小不同: boolean 类型的变量会分配 4 个字节的内存,而 number 类型的变量则会分配 8 个字节的内存,给变量声明了不同的类型就代表了会占据不同的内存空间。

          • 不同类型变量可做的操作不同: number 类型可以做加减乘除等运算,boolean 就不可以,复合类型中不同类型的对象可用的方法不同,比如 Date 和 RegExp,变量的类型不同代表可以对该变量做的操作就不同。

          有了类型,那我们的操作必须和类型相匹配,否则就会报错,这就是类型检查。

          如果能保证对某种类型只做该类型允许的操作,这就叫做类型安全。

          类型检查可以在运行时做,也可以运行之前的编译期做。这是两种不同的类型,前者叫做动态类型检查,后者叫做静态类型检查。

          两种类型检查各有优缺点。动态类型检查 在源码中不保留类型信息,对某个变量赋什么值、做什么操作都是允许的,写代码很灵活。但这也埋下了类型不安全的隐患,比如对 string 做了乘除,对 Date 对象调用了 exec 方法,这些都是运行时才能检查出来的错误。

          其中,最常见的错误应该是 “null is not an object”、“undefined is not a function” 之类的了,写代码时没发现类型不匹配,到了运行的时候才发现,就会有很多这种报错。

          所以,动态类型虽然代码写起来简单,但代码中很容易藏着一些类型不匹配的隐患。

          静态类型检查则是在源码中保留类型信息,声明变量要指定类型,对变量做的操作要和类型匹配,会有专门的编译器在编译期间做检查。

          静态类型给写代码增加了一些难度,因为你除了要考虑代码要表达的逻辑之外,还要考虑类型逻辑:变量是什么类型的、是不是匹配、要不要做类型转换等。

          不过,静态类型也消除了类型不安全的隐患,因为在编译期间就做了类型检查,就不会出现对 string 做了乘除,调用了 Date 的 exec 方法这类问题。

          所以,静态类型虽然代码写起来要考虑的问题多一些,会复杂一些,但是却消除了代码中潜藏类型不安全问题的可能。

          知道了动态类型检查和静态类型检查的区别,我们自然可以得出这样的结论:

          动态类型只适合简单的场景,对于大项目却不太合适,因为代码中可能藏着的隐患太多了,万一线上报一个类型不匹配的错误,那可能就是大问题。

          而静态类型虽然会增加写代码的成本,但是却能更好的保证代码的健壮性,减少 Bug 率。

          所以,大型项目注定会用静态类型语言开发。

          二.类型系统的分类

          1.简单的类型系统

          变量、函数、类等都可以声明类型,编译器会基于声明的类型做类型检查,类型不匹配时会报错。

          这是最基础的类型系统,能保证类型安全,但有些死板。

          比如一个 add 函数既可以做整数加法、又可以做浮点数加法,却需要声明两个函数:

          c
          int add(int a, int b) {
               return a + b;
           }
           
          diff --git a/assets/cn_src_article_typescript_pattern.md.rnM0NHZ9.js b/assets/cn_src_article_typescript_pattern.md.CyszQeR8.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_pattern.md.rnM0NHZ9.js
          rename to assets/cn_src_article_typescript_pattern.md.CyszQeR8.js
          index 3b7812626b..f1bb3d2167 100644
          --- a/assets/cn_src_article_typescript_pattern.md.rnM0NHZ9.js
          +++ b/assets/cn_src_article_typescript_pattern.md.CyszQeR8.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"模式匹配提取","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/pattern.md","filePath":"cn/src/article/typescript/pattern.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/typescript/pattern.md"};function k(p,s,l,e,r,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          模式匹配提取

          字符串可以和正则做模式匹配,找到匹配的部分,提取子组,之后可以用 1,2 等引用匹配的子组。

          ts
          'abc'.replace(/a(b)c/, '$1,$1,$1');
          +import{_ as i,o as a,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"模式匹配提取","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/pattern.md","filePath":"cn/src/article/typescript/pattern.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/typescript/pattern.md"};function k(p,s,l,e,r,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          模式匹配提取

          字符串可以和正则做模式匹配,找到匹配的部分,提取子组,之后可以用 1,2 等引用匹配的子组。

          ts
          'abc'.replace(/a(b)c/, '$1,$1,$1');
           // 'b,b,b'

          Typescript 的类型也同样可以做模式匹配。

          比如这样一个 Promise 类型:

          ts
          type p = Promise<'value'>;

          我们想提取 value 的类型,可以这样做:

          ts
          type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

          通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

          ts
          // type GetValueResult = 'value'
           type GetValueResult = GetValueType<Promise<'value'>>;

          这就是 Typescript 类型的模式匹配:

          Typescript 类型的模式匹配是通过 extends 对类型参数做匹配,结果保存到通过 infer 声明的局部类型变量里,如果匹配就能从该局部变量里拿到提取出的类型。

          这个模式匹配的套路有多有用呢?我们来看下在数组、字符串、函数、构造器等类型里的应用。

          1.数组类型

          提取第一个元素

          数组类型想提取第一个元素的类型怎么做呢?

          ts
          type arr = [1, 2, 3];

          用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

          ts
          type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never;

          类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unkown 也就是可以是任何值。

          any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

          对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never;
           type GetFirstValue = GetFirst<[1, 2, 3]>;
          diff --git a/assets/cn_src_article_typescript_pattern.md.rnM0NHZ9.lean.js b/assets/cn_src_article_typescript_pattern.md.CyszQeR8.lean.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_pattern.md.rnM0NHZ9.lean.js
          rename to assets/cn_src_article_typescript_pattern.md.CyszQeR8.lean.js
          index 3b7812626b..f1bb3d2167 100644
          --- a/assets/cn_src_article_typescript_pattern.md.rnM0NHZ9.lean.js
          +++ b/assets/cn_src_article_typescript_pattern.md.CyszQeR8.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"模式匹配提取","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/pattern.md","filePath":"cn/src/article/typescript/pattern.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/typescript/pattern.md"};function k(p,s,l,e,r,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          模式匹配提取

          字符串可以和正则做模式匹配,找到匹配的部分,提取子组,之后可以用 1,2 等引用匹配的子组。

          ts
          'abc'.replace(/a(b)c/, '$1,$1,$1');
          +import{_ as i,o as a,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"模式匹配提取","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/pattern.md","filePath":"cn/src/article/typescript/pattern.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/typescript/pattern.md"};function k(p,s,l,e,r,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          模式匹配提取

          字符串可以和正则做模式匹配,找到匹配的部分,提取子组,之后可以用 1,2 等引用匹配的子组。

          ts
          'abc'.replace(/a(b)c/, '$1,$1,$1');
           // 'b,b,b'

          Typescript 的类型也同样可以做模式匹配。

          比如这样一个 Promise 类型:

          ts
          type p = Promise<'value'>;

          我们想提取 value 的类型,可以这样做:

          ts
          type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

          通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

          ts
          // type GetValueResult = 'value'
           type GetValueResult = GetValueType<Promise<'value'>>;

          这就是 Typescript 类型的模式匹配:

          Typescript 类型的模式匹配是通过 extends 对类型参数做匹配,结果保存到通过 infer 声明的局部类型变量里,如果匹配就能从该局部变量里拿到提取出的类型。

          这个模式匹配的套路有多有用呢?我们来看下在数组、字符串、函数、构造器等类型里的应用。

          1.数组类型

          提取第一个元素

          数组类型想提取第一个元素的类型怎么做呢?

          ts
          type arr = [1, 2, 3];

          用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

          ts
          type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never;

          类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unkown 也就是可以是任何值。

          any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

          对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never;
           type GetFirstValue = GetFirst<[1, 2, 3]>;
          diff --git a/assets/cn_src_article_typescript_reconstruction.md.BhFbdKZJ.js b/assets/cn_src_article_typescript_reconstruction.md.B9hETE9S.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_reconstruction.md.BhFbdKZJ.js
          rename to assets/cn_src_article_typescript_reconstruction.md.B9hETE9S.js
          index 8fa1434e78..2412f14a4d 100644
          --- a/assets/cn_src_article_typescript_reconstruction.md.BhFbdKZJ.js
          +++ b/assets/cn_src_article_typescript_reconstruction.md.B9hETE9S.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"重新构造做变换","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/reconstruction.md","filePath":"cn/src/article/typescript/reconstruction.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/typescript/reconstruction.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

          重新构造做变换

          类型编程主要的目的就是对类型做各种转换,那么如何对类型做修改呢?

          TypeScript 类型系统支持 3 种可以声明任意类型的变量: type、infer、类型参数。

          type 叫做类型别名,其实就是声明一个变量存储某个类型:

          ts
          type ttt = Promise<number>;

          infer 用于类型的提取,然后存到一个变量里,相当于局部变量:

          ts
          type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

          类型参数用于接受具体的类型,在类型运算中也相当于局部变量:

          ts
          type isTwo<T> = T extends 2 ? true : false;

          但是,严格来说这三种也都不叫变量,因为它们不能被重新赋值。

          TypeScript 设计可以做类型编程的类型系统的目的就是为了产生各种复杂的类型,那不能修改怎么产生新类型呢?

          答案是重新构造。

          这就涉及到了第二个类型体操套路:重新构造做变换。

          重新构造

          TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。

          数组、字符串、函数等类型的重新构造比较简单。

          索引类型,也就是多个元素的聚合类型的重新构造复杂一些,涉及到了映射类型的语法。

          我们先从简单的开始:

          数组类型的重新构造

          Push

          有这样一个元组类型:

          ts
          type tuple = [1, 2, 3];

          我想给这个元组类型再添加一些类型,怎么做呢?

          TypeScript 类型变量不支持修改,我们可以构造一个新的元组类型:

          ts
          type Push<Arr extends unknown[], Ele> = [...Arr, Ele];

          类型参数 Arr 是要修改的数组/元组类型,元素的类型任意,也就是 unknown。

          类型参数 Ele 是添加的元素的类型。

          返回的是用 Arr 已有的元素加上 Ele 构造的新的元组类型。

          ts
          type PushResult = Push<[1, 2, 3], 4>;
          +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"重新构造做变换","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/reconstruction.md","filePath":"cn/src/article/typescript/reconstruction.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/typescript/reconstruction.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

          重新构造做变换

          类型编程主要的目的就是对类型做各种转换,那么如何对类型做修改呢?

          TypeScript 类型系统支持 3 种可以声明任意类型的变量: type、infer、类型参数。

          type 叫做类型别名,其实就是声明一个变量存储某个类型:

          ts
          type ttt = Promise<number>;

          infer 用于类型的提取,然后存到一个变量里,相当于局部变量:

          ts
          type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

          类型参数用于接受具体的类型,在类型运算中也相当于局部变量:

          ts
          type isTwo<T> = T extends 2 ? true : false;

          但是,严格来说这三种也都不叫变量,因为它们不能被重新赋值。

          TypeScript 设计可以做类型编程的类型系统的目的就是为了产生各种复杂的类型,那不能修改怎么产生新类型呢?

          答案是重新构造。

          这就涉及到了第二个类型体操套路:重新构造做变换。

          重新构造

          TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。

          数组、字符串、函数等类型的重新构造比较简单。

          索引类型,也就是多个元素的聚合类型的重新构造复杂一些,涉及到了映射类型的语法。

          我们先从简单的开始:

          数组类型的重新构造

          Push

          有这样一个元组类型:

          ts
          type tuple = [1, 2, 3];

          我想给这个元组类型再添加一些类型,怎么做呢?

          TypeScript 类型变量不支持修改,我们可以构造一个新的元组类型:

          ts
          type Push<Arr extends unknown[], Ele> = [...Arr, Ele];

          类型参数 Arr 是要修改的数组/元组类型,元素的类型任意,也就是 unknown。

          类型参数 Ele 是添加的元素的类型。

          返回的是用 Arr 已有的元素加上 Ele 构造的新的元组类型。

          ts
          type PushResult = Push<[1, 2, 3], 4>;
           // type PushResult = [1,2,3,4]

          这就是数组/元组的重新构造。

          数组和元组的区别:数组类型是指任意多个同一类型的元素构成的,比如 number[]Array<number>,而元组则是数量固定,类型可以不同的元素构成的,比如 [1, true, 'name']

          Unshift

          可以在后面添加,同样也可以在前面添加:

          ts
          type Unshift<Arr extends unknown[], Ele> = [Ele, ...Arr];

          Zip

          有这样两个元组:

          ts
          type tuple1 = [1, 2];
           type tuple2 = ['name', 'value'];

          我们想把它们合并成这样的元组:

          ts
          type tuple = [[1, 'name'], [2, 'value']];

          思路很容易想到,提取元组中的两个元素,构造成新的元组:

          ts
          type Zip<One extends [unknown, unknown], Other extends [unknown, unknown]> = One extends [
             infer OneFirst,
          diff --git a/assets/cn_src_article_typescript_reconstruction.md.BhFbdKZJ.lean.js b/assets/cn_src_article_typescript_reconstruction.md.B9hETE9S.lean.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_reconstruction.md.BhFbdKZJ.lean.js
          rename to assets/cn_src_article_typescript_reconstruction.md.B9hETE9S.lean.js
          index 8fa1434e78..2412f14a4d 100644
          --- a/assets/cn_src_article_typescript_reconstruction.md.BhFbdKZJ.lean.js
          +++ b/assets/cn_src_article_typescript_reconstruction.md.B9hETE9S.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"重新构造做变换","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/reconstruction.md","filePath":"cn/src/article/typescript/reconstruction.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/typescript/reconstruction.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

          重新构造做变换

          类型编程主要的目的就是对类型做各种转换,那么如何对类型做修改呢?

          TypeScript 类型系统支持 3 种可以声明任意类型的变量: type、infer、类型参数。

          type 叫做类型别名,其实就是声明一个变量存储某个类型:

          ts
          type ttt = Promise<number>;

          infer 用于类型的提取,然后存到一个变量里,相当于局部变量:

          ts
          type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

          类型参数用于接受具体的类型,在类型运算中也相当于局部变量:

          ts
          type isTwo<T> = T extends 2 ? true : false;

          但是,严格来说这三种也都不叫变量,因为它们不能被重新赋值。

          TypeScript 设计可以做类型编程的类型系统的目的就是为了产生各种复杂的类型,那不能修改怎么产生新类型呢?

          答案是重新构造。

          这就涉及到了第二个类型体操套路:重新构造做变换。

          重新构造

          TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。

          数组、字符串、函数等类型的重新构造比较简单。

          索引类型,也就是多个元素的聚合类型的重新构造复杂一些,涉及到了映射类型的语法。

          我们先从简单的开始:

          数组类型的重新构造

          Push

          有这样一个元组类型:

          ts
          type tuple = [1, 2, 3];

          我想给这个元组类型再添加一些类型,怎么做呢?

          TypeScript 类型变量不支持修改,我们可以构造一个新的元组类型:

          ts
          type Push<Arr extends unknown[], Ele> = [...Arr, Ele];

          类型参数 Arr 是要修改的数组/元组类型,元素的类型任意,也就是 unknown。

          类型参数 Ele 是添加的元素的类型。

          返回的是用 Arr 已有的元素加上 Ele 构造的新的元组类型。

          ts
          type PushResult = Push<[1, 2, 3], 4>;
          +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"重新构造做变换","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/reconstruction.md","filePath":"cn/src/article/typescript/reconstruction.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/typescript/reconstruction.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

          重新构造做变换

          类型编程主要的目的就是对类型做各种转换,那么如何对类型做修改呢?

          TypeScript 类型系统支持 3 种可以声明任意类型的变量: type、infer、类型参数。

          type 叫做类型别名,其实就是声明一个变量存储某个类型:

          ts
          type ttt = Promise<number>;

          infer 用于类型的提取,然后存到一个变量里,相当于局部变量:

          ts
          type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

          类型参数用于接受具体的类型,在类型运算中也相当于局部变量:

          ts
          type isTwo<T> = T extends 2 ? true : false;

          但是,严格来说这三种也都不叫变量,因为它们不能被重新赋值。

          TypeScript 设计可以做类型编程的类型系统的目的就是为了产生各种复杂的类型,那不能修改怎么产生新类型呢?

          答案是重新构造。

          这就涉及到了第二个类型体操套路:重新构造做变换。

          重新构造

          TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。

          数组、字符串、函数等类型的重新构造比较简单。

          索引类型,也就是多个元素的聚合类型的重新构造复杂一些,涉及到了映射类型的语法。

          我们先从简单的开始:

          数组类型的重新构造

          Push

          有这样一个元组类型:

          ts
          type tuple = [1, 2, 3];

          我想给这个元组类型再添加一些类型,怎么做呢?

          TypeScript 类型变量不支持修改,我们可以构造一个新的元组类型:

          ts
          type Push<Arr extends unknown[], Ele> = [...Arr, Ele];

          类型参数 Arr 是要修改的数组/元组类型,元素的类型任意,也就是 unknown。

          类型参数 Ele 是添加的元素的类型。

          返回的是用 Arr 已有的元素加上 Ele 构造的新的元组类型。

          ts
          type PushResult = Push<[1, 2, 3], 4>;
           // type PushResult = [1,2,3,4]

          这就是数组/元组的重新构造。

          数组和元组的区别:数组类型是指任意多个同一类型的元素构成的,比如 number[]Array<number>,而元组则是数量固定,类型可以不同的元素构成的,比如 [1, true, 'name']

          Unshift

          可以在后面添加,同样也可以在前面添加:

          ts
          type Unshift<Arr extends unknown[], Ele> = [Ele, ...Arr];

          Zip

          有这样两个元组:

          ts
          type tuple1 = [1, 2];
           type tuple2 = ['name', 'value'];

          我们想把它们合并成这样的元组:

          ts
          type tuple = [[1, 'name'], [2, 'value']];

          思路很容易想到,提取元组中的两个元素,构造成新的元组:

          ts
          type Zip<One extends [unknown, unknown], Other extends [unknown, unknown]> = One extends [
             infer OneFirst,
          diff --git a/assets/cn_src_article_typescript_recursion.md.D22JKCo3.js b/assets/cn_src_article_typescript_recursion.md.BuRNB37-.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_recursion.md.D22JKCo3.js
          rename to assets/cn_src_article_typescript_recursion.md.BuRNB37-.js
          index 80c1165c22..f992bff0f0 100644
          --- a/assets/cn_src_article_typescript_recursion.md.D22JKCo3.js
          +++ b/assets/cn_src_article_typescript_recursion.md.BuRNB37-.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"递归复用","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/recursion.md","filePath":"cn/src/article/typescript/recursion.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/typescript/recursion.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          递归复用

          递归是把问题分解为一系列相似的小问题,通过函数不断调用自身来解决这一个个小问题,直到满足结束条件,就完成了问题的求解。

          TypeScript 的高级类型支持类型参数,可以做各种类型运算逻辑,返回新的类型,和函数调用是对应的,自然也支持递归。

          TypeScript 类型系统不支持循环,但支持递归。当处理数量(个数、长度、层数)不固定的类型的时候,可以只处理一个类型,然后递归的调用自身处理下一个类型,直到结束条件也就是所有的类型都处理完了,就完成了不确定数量的类型编程,达到循环的效果。

          既然提到了数组、字符串、对象等类型,那么我们就来看一下这些类型的递归案例吧。

          Promise 的递归复用

          DeepPromiseValueType

          先用 Promise 热热身,实现一个提取不确定层数的 Promise 中的 value 类型的高级类型。

          ts
          type ttt = Promise<Promise<Promise<Record<string, any>>>>;

          这里是 3 层 Promise,value 类型是索引类型。

          数量不确定,一涉及到这个就要想到用递归来做,每次只处理一层的提取,然后剩下的到下次递归做,直到结束条件。

          所以高级类型是这样的:

          ts
          type DeepPromiseValueType<P extends Promise<unknown>> =
          +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"递归复用","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/recursion.md","filePath":"cn/src/article/typescript/recursion.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/typescript/recursion.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          递归复用

          递归是把问题分解为一系列相似的小问题,通过函数不断调用自身来解决这一个个小问题,直到满足结束条件,就完成了问题的求解。

          TypeScript 的高级类型支持类型参数,可以做各种类型运算逻辑,返回新的类型,和函数调用是对应的,自然也支持递归。

          TypeScript 类型系统不支持循环,但支持递归。当处理数量(个数、长度、层数)不固定的类型的时候,可以只处理一个类型,然后递归的调用自身处理下一个类型,直到结束条件也就是所有的类型都处理完了,就完成了不确定数量的类型编程,达到循环的效果。

          既然提到了数组、字符串、对象等类型,那么我们就来看一下这些类型的递归案例吧。

          Promise 的递归复用

          DeepPromiseValueType

          先用 Promise 热热身,实现一个提取不确定层数的 Promise 中的 value 类型的高级类型。

          ts
          type ttt = Promise<Promise<Promise<Record<string, any>>>>;

          这里是 3 层 Promise,value 类型是索引类型。

          数量不确定,一涉及到这个就要想到用递归来做,每次只处理一层的提取,然后剩下的到下次递归做,直到结束条件。

          所以高级类型是这样的:

          ts
          type DeepPromiseValueType<P extends Promise<unknown>> =
             P extends Promise<infer ValueType>
               ? ValueType extends Promise<unknown>
                 ? DeepPromiseValueType<ValueType>
          diff --git a/assets/cn_src_article_typescript_recursion.md.D22JKCo3.lean.js b/assets/cn_src_article_typescript_recursion.md.BuRNB37-.lean.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_recursion.md.D22JKCo3.lean.js
          rename to assets/cn_src_article_typescript_recursion.md.BuRNB37-.lean.js
          index 80c1165c22..f992bff0f0 100644
          --- a/assets/cn_src_article_typescript_recursion.md.D22JKCo3.lean.js
          +++ b/assets/cn_src_article_typescript_recursion.md.BuRNB37-.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"递归复用","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/recursion.md","filePath":"cn/src/article/typescript/recursion.md","lastUpdated":1728828157000}'),n={name:"cn/src/article/typescript/recursion.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          递归复用

          递归是把问题分解为一系列相似的小问题,通过函数不断调用自身来解决这一个个小问题,直到满足结束条件,就完成了问题的求解。

          TypeScript 的高级类型支持类型参数,可以做各种类型运算逻辑,返回新的类型,和函数调用是对应的,自然也支持递归。

          TypeScript 类型系统不支持循环,但支持递归。当处理数量(个数、长度、层数)不固定的类型的时候,可以只处理一个类型,然后递归的调用自身处理下一个类型,直到结束条件也就是所有的类型都处理完了,就完成了不确定数量的类型编程,达到循环的效果。

          既然提到了数组、字符串、对象等类型,那么我们就来看一下这些类型的递归案例吧。

          Promise 的递归复用

          DeepPromiseValueType

          先用 Promise 热热身,实现一个提取不确定层数的 Promise 中的 value 类型的高级类型。

          ts
          type ttt = Promise<Promise<Promise<Record<string, any>>>>;

          这里是 3 层 Promise,value 类型是索引类型。

          数量不确定,一涉及到这个就要想到用递归来做,每次只处理一层的提取,然后剩下的到下次递归做,直到结束条件。

          所以高级类型是这样的:

          ts
          type DeepPromiseValueType<P extends Promise<unknown>> =
          +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"递归复用","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/recursion.md","filePath":"cn/src/article/typescript/recursion.md","lastUpdated":1728921295000}'),n={name:"cn/src/article/typescript/recursion.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          递归复用

          递归是把问题分解为一系列相似的小问题,通过函数不断调用自身来解决这一个个小问题,直到满足结束条件,就完成了问题的求解。

          TypeScript 的高级类型支持类型参数,可以做各种类型运算逻辑,返回新的类型,和函数调用是对应的,自然也支持递归。

          TypeScript 类型系统不支持循环,但支持递归。当处理数量(个数、长度、层数)不固定的类型的时候,可以只处理一个类型,然后递归的调用自身处理下一个类型,直到结束条件也就是所有的类型都处理完了,就完成了不确定数量的类型编程,达到循环的效果。

          既然提到了数组、字符串、对象等类型,那么我们就来看一下这些类型的递归案例吧。

          Promise 的递归复用

          DeepPromiseValueType

          先用 Promise 热热身,实现一个提取不确定层数的 Promise 中的 value 类型的高级类型。

          ts
          type ttt = Promise<Promise<Promise<Record<string, any>>>>;

          这里是 3 层 Promise,value 类型是索引类型。

          数量不确定,一涉及到这个就要想到用递归来做,每次只处理一层的提取,然后剩下的到下次递归做,直到结束条件。

          所以高级类型是这样的:

          ts
          type DeepPromiseValueType<P extends Promise<unknown>> =
             P extends Promise<infer ValueType>
               ? ValueType extends Promise<unknown>
                 ? DeepPromiseValueType<ValueType>
          diff --git a/assets/cn_src_article_typescript_unionType.md.atUNmveE.js b/assets/cn_src_article_typescript_unionType.md.wPcbHmYa.js
          similarity index 99%
          rename from assets/cn_src_article_typescript_unionType.md.atUNmveE.js
          rename to assets/cn_src_article_typescript_unionType.md.wPcbHmYa.js
          index 6e9793cb28..d0f649000b 100644
          --- a/assets/cn_src_article_typescript_unionType.md.atUNmveE.js
          +++ b/assets/cn_src_article_typescript_unionType.md.wPcbHmYa.js
          @@ -1 +1 @@
          -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"分布式条件类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/unionType.md","filePath":"cn/src/article/typescript/unionType.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/typescript/unionType.md"};function n(p,s,l,e,d,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

          分布式条件类型

          当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。

          比如这样一个联合类型:

          ts
          type Union = 'a' | 'b' | 'c';

          我们想把其中的 a 大写,就可以这样写:

          ts
          type UppercaseA<Item extends string> = Item extends 'a' ? Uppercase<Item> : Item;
          ts
          type result = UppercaseA<Union>;\n// type result = 'A' | 'b' | 'c';

          可以看到,我们类型参数 Item 约束为 string,条件类型的判断中也是判断是否是 a,但传入的是联合类型。

          这就是 TypeScript 对联合类型在条件类型中使用时的特殊处理:会把联合类型的每一个元素单独传入做类型计算,最后合并。

          这和联合类型遇到字符串时的处理一样:

          这样确实是简化了类型编程逻辑的,不需要递归提取每个元素再处理。

          TypeScript 之所以这样处理联合类型也很容易理解,因为联合类型的每个元素都是互不相关的,不像数组、索引、字符串那样元素之间是有关系的。所以设计成了每一个单独处理,最后合并。

          知道了 TypeScript 怎么处理的联合类型,趁热打铁来练习一下:

          CamelcaseUnion

          Camelcase 我们实现过,就是提取字符串中的字符,首字母大写以后重新构造一个新的。

          ts
          type Camelcase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${Camelcase<Rest>}`\n  : Str;

          提取 _ 左右的字符,把右边字符大写之后构造成新的字符串,余下的字符串递归处理。

          ts
          type CamelcaseResult = Camelcase<'aa_aa_aa'>;\n// type CamelcaseResult = 'aaAaAa'

          如果是对字符串数组做 Camelcase,那就要递归处理每一个元素:

          ts
          type CamelcaseArr<Arr extends unknown[]> = Arr extends [infer Item, ...infer RestArr]\n  ? [Camelcase<Item & string>, ...CamelcaseArr<RestArr>]\n  : [];

          类型参数 Arr 为待处理数组。

          递归提取每一个元素做 Camelcase,因为 Camelcase 要求传入 string,这里要 & string 来变成 string 类型。

          那如果是联合类型呢?

          联合类型不需要递归提取每个元素,TypeScript 内部会把每一个元素传入单独做计算,之后把每个元素的计算结果合并成联合类型。

          ts
          type CamelcaseUnion<Item extends string> = Item extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${CamelcaseUnion<Rest>}`\n  : Item;

          这不和单个字符串的处理没区别么?

          没错,对联合类型的处理和对单个类型的处理没什么区别,TypeScript 会把每个单独的类型拆开传入。不需要像数组类型那样需要递归提取每个元素做处理。

          确实简化了很多,好像都是优点?

          也不全是,其实这样处理也增加了一些认知成本,不信我们再来看个例子:

          IsUnion

          判断联合类型我们会这样写:

          ts
          type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

          当传入联合类型时,会返回 true:

          ts
          type IsUnionResult = IsUnion<'a' | 'b' 'c'>\n// type IsUnionResult = true

          当传入其他类型时,会返回 false:

          ts
          type IsUnionResult = IsUnion<['a' | 'b' 'c']>\n// type IsUnionResult = false

          这就是分布式条件类型带来的认知成本。

          我们先来看这样一个类型:

          ts
          type TestUnion<A, B = A> = A extends A ? { a: A; b: B } : never;\n\ntype TestUnionResult = TestUnion<'a' | 'b' | 'c'>;

          传入联合类型 'a' | 'b' | 'c' 的时候,结果是这样的:

          A 和 B 都是同一个联合类型,为啥值还不一样呢?

          因为条件类型中如果左边的类型是联合类型,会把每个元素单独传入做计算,而右边不会。

          所以 A 是 'a' 的时候,B 是 'a' | 'b' | 'c', A 是 'b' 的时候,B 是 'a' | 'b' | 'c'。。。

          那么利用这个特点就可以实现 Union 类型的判断:

          ts
          type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

          类型参数 A、B 是待判断的联合类型,B 默认值为 A,也就是同一个类型。

          A extends A 这段看似没啥意义,主要是为了触发分布式条件类型,让 A 的每个类型单独传入。

          [B] extends [A] 这样不直接写 B 就可以避免触发分布式条件类型,那么 B 就是整个联合类型。

          B 是联合类型整体,而 A 是单个类型,自然不成立,而其它类型没有这种特殊处理,A 和 B 都是同一个,怎么判断都成立。

          利用这个特点就可以判断出是否是联合类型。

          其中有两个点比较困惑,我们重点记一下:

          当 A 是联合类型时:

          A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。

          A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。

          理解了这两点,分布式条件类型就算掌握了。

          BEM

          bem 是 css 命名规范,用 block__element--modifier 的形式来描述某个区块下面的某个元素的某个状态的样式。

          那么我们可以写这样一个高级类型,传入 block、element、modifier,返回构造出的 class 名:

          这样使用:

          ts
          type bemResult = BEM<'guang', ['aaa', 'bbb'], ['warning', 'success']>;

          它的实现就是三部分的合并,但传入的是数组,要递归遍历取出每一个元素来和其他部分组合,这样太麻烦了。

          而如果是联合类型就不用递归遍历了,因为联合类型遇到字符串也是会单独每个元素单独传入做处理。

          数组转联合类型可以这样写:

          ts
          type union = ['aaa', 'bbb'][number];\n// type union = 'aaa' | 'bbb'

          那么 BEM 就可以这样实现:

          ts
          type BEM<\n  Block extends string,\n  Element extends string[],\n  Modifiers extends string[],\n> = `${Block}__${Element[number]}--${Modifiers[number]}`;

          类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

          构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

          字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

          ts
          type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;\n// type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

          可以看到,用好了联合类型,确实能简化类型编程逻辑。

          AllCombinations

          我们再来实现一个全组合的高级类型,也是联合类型相关的:

          希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

          这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

          比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

          任何两个类型的组合有四种:A、B、AB、BA

          ts
          type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

          然后构造出来的字符串再和其他字符串组合。

          所以全组合的高级类型就是这样:

          ts
          type AllCombinations<A extends string, B extends string = A> = A extends A\n  ? Combination<A, AllCombinations<Exclude<B, A>>>\n  : never;

          类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

          A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

          A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

          而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

          总结

          联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

          条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

          有两点特别要注意:

          • A extends A 不是没意义,意义是取出联合类型中的单个类型放入 A

          • A extends A 才是分布式条件类型, [A] extends [A] 就不是了,只有左边是单独的类型参数才可以。

          我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

          ',91)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"分布式条件类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/unionType.md","filePath":"cn/src/article/typescript/unionType.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/typescript/unionType.md"};function n(p,s,l,e,d,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

          分布式条件类型

          当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。

          比如这样一个联合类型:

          ts
          type Union = 'a' | 'b' | 'c';

          我们想把其中的 a 大写,就可以这样写:

          ts
          type UppercaseA<Item extends string> = Item extends 'a' ? Uppercase<Item> : Item;
          ts
          type result = UppercaseA<Union>;\n// type result = 'A' | 'b' | 'c';

          可以看到,我们类型参数 Item 约束为 string,条件类型的判断中也是判断是否是 a,但传入的是联合类型。

          这就是 TypeScript 对联合类型在条件类型中使用时的特殊处理:会把联合类型的每一个元素单独传入做类型计算,最后合并。

          这和联合类型遇到字符串时的处理一样:

          这样确实是简化了类型编程逻辑的,不需要递归提取每个元素再处理。

          TypeScript 之所以这样处理联合类型也很容易理解,因为联合类型的每个元素都是互不相关的,不像数组、索引、字符串那样元素之间是有关系的。所以设计成了每一个单独处理,最后合并。

          知道了 TypeScript 怎么处理的联合类型,趁热打铁来练习一下:

          CamelcaseUnion

          Camelcase 我们实现过,就是提取字符串中的字符,首字母大写以后重新构造一个新的。

          ts
          type Camelcase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${Camelcase<Rest>}`\n  : Str;

          提取 _ 左右的字符,把右边字符大写之后构造成新的字符串,余下的字符串递归处理。

          ts
          type CamelcaseResult = Camelcase<'aa_aa_aa'>;\n// type CamelcaseResult = 'aaAaAa'

          如果是对字符串数组做 Camelcase,那就要递归处理每一个元素:

          ts
          type CamelcaseArr<Arr extends unknown[]> = Arr extends [infer Item, ...infer RestArr]\n  ? [Camelcase<Item & string>, ...CamelcaseArr<RestArr>]\n  : [];

          类型参数 Arr 为待处理数组。

          递归提取每一个元素做 Camelcase,因为 Camelcase 要求传入 string,这里要 & string 来变成 string 类型。

          那如果是联合类型呢?

          联合类型不需要递归提取每个元素,TypeScript 内部会把每一个元素传入单独做计算,之后把每个元素的计算结果合并成联合类型。

          ts
          type CamelcaseUnion<Item extends string> = Item extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${CamelcaseUnion<Rest>}`\n  : Item;

          这不和单个字符串的处理没区别么?

          没错,对联合类型的处理和对单个类型的处理没什么区别,TypeScript 会把每个单独的类型拆开传入。不需要像数组类型那样需要递归提取每个元素做处理。

          确实简化了很多,好像都是优点?

          也不全是,其实这样处理也增加了一些认知成本,不信我们再来看个例子:

          IsUnion

          判断联合类型我们会这样写:

          ts
          type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

          当传入联合类型时,会返回 true:

          ts
          type IsUnionResult = IsUnion<'a' | 'b' 'c'>\n// type IsUnionResult = true

          当传入其他类型时,会返回 false:

          ts
          type IsUnionResult = IsUnion<['a' | 'b' 'c']>\n// type IsUnionResult = false

          这就是分布式条件类型带来的认知成本。

          我们先来看这样一个类型:

          ts
          type TestUnion<A, B = A> = A extends A ? { a: A; b: B } : never;\n\ntype TestUnionResult = TestUnion<'a' | 'b' | 'c'>;

          传入联合类型 'a' | 'b' | 'c' 的时候,结果是这样的:

          A 和 B 都是同一个联合类型,为啥值还不一样呢?

          因为条件类型中如果左边的类型是联合类型,会把每个元素单独传入做计算,而右边不会。

          所以 A 是 'a' 的时候,B 是 'a' | 'b' | 'c', A 是 'b' 的时候,B 是 'a' | 'b' | 'c'。。。

          那么利用这个特点就可以实现 Union 类型的判断:

          ts
          type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

          类型参数 A、B 是待判断的联合类型,B 默认值为 A,也就是同一个类型。

          A extends A 这段看似没啥意义,主要是为了触发分布式条件类型,让 A 的每个类型单独传入。

          [B] extends [A] 这样不直接写 B 就可以避免触发分布式条件类型,那么 B 就是整个联合类型。

          B 是联合类型整体,而 A 是单个类型,自然不成立,而其它类型没有这种特殊处理,A 和 B 都是同一个,怎么判断都成立。

          利用这个特点就可以判断出是否是联合类型。

          其中有两个点比较困惑,我们重点记一下:

          当 A 是联合类型时:

          A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。

          A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。

          理解了这两点,分布式条件类型就算掌握了。

          BEM

          bem 是 css 命名规范,用 block__element--modifier 的形式来描述某个区块下面的某个元素的某个状态的样式。

          那么我们可以写这样一个高级类型,传入 block、element、modifier,返回构造出的 class 名:

          这样使用:

          ts
          type bemResult = BEM<'guang', ['aaa', 'bbb'], ['warning', 'success']>;

          它的实现就是三部分的合并,但传入的是数组,要递归遍历取出每一个元素来和其他部分组合,这样太麻烦了。

          而如果是联合类型就不用递归遍历了,因为联合类型遇到字符串也是会单独每个元素单独传入做处理。

          数组转联合类型可以这样写:

          ts
          type union = ['aaa', 'bbb'][number];\n// type union = 'aaa' | 'bbb'

          那么 BEM 就可以这样实现:

          ts
          type BEM<\n  Block extends string,\n  Element extends string[],\n  Modifiers extends string[],\n> = `${Block}__${Element[number]}--${Modifiers[number]}`;

          类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

          构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

          字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

          ts
          type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;\n// type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

          可以看到,用好了联合类型,确实能简化类型编程逻辑。

          AllCombinations

          我们再来实现一个全组合的高级类型,也是联合类型相关的:

          希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

          这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

          比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

          任何两个类型的组合有四种:A、B、AB、BA

          ts
          type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

          然后构造出来的字符串再和其他字符串组合。

          所以全组合的高级类型就是这样:

          ts
          type AllCombinations<A extends string, B extends string = A> = A extends A\n  ? Combination<A, AllCombinations<Exclude<B, A>>>\n  : never;

          类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

          A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

          A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

          而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

          总结

          联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

          条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

          有两点特别要注意:

          • A extends A 不是没意义,意义是取出联合类型中的单个类型放入 A

          • A extends A 才是分布式条件类型, [A] extends [A] 就不是了,只有左边是单独的类型参数才可以。

          我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

          ',91)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; diff --git a/assets/cn_src_article_typescript_unionType.md.atUNmveE.lean.js b/assets/cn_src_article_typescript_unionType.md.wPcbHmYa.lean.js similarity index 99% rename from assets/cn_src_article_typescript_unionType.md.atUNmveE.lean.js rename to assets/cn_src_article_typescript_unionType.md.wPcbHmYa.lean.js index 6e9793cb28..d0f649000b 100644 --- a/assets/cn_src_article_typescript_unionType.md.atUNmveE.lean.js +++ b/assets/cn_src_article_typescript_unionType.md.wPcbHmYa.lean.js @@ -1 +1 @@ -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"分布式条件类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/unionType.md","filePath":"cn/src/article/typescript/unionType.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/typescript/unionType.md"};function n(p,s,l,e,d,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

          分布式条件类型

          当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。

          比如这样一个联合类型:

          ts
          type Union = 'a' | 'b' | 'c';

          我们想把其中的 a 大写,就可以这样写:

          ts
          type UppercaseA<Item extends string> = Item extends 'a' ? Uppercase<Item> : Item;
          ts
          type result = UppercaseA<Union>;\n// type result = 'A' | 'b' | 'c';

          可以看到,我们类型参数 Item 约束为 string,条件类型的判断中也是判断是否是 a,但传入的是联合类型。

          这就是 TypeScript 对联合类型在条件类型中使用时的特殊处理:会把联合类型的每一个元素单独传入做类型计算,最后合并。

          这和联合类型遇到字符串时的处理一样:

          这样确实是简化了类型编程逻辑的,不需要递归提取每个元素再处理。

          TypeScript 之所以这样处理联合类型也很容易理解,因为联合类型的每个元素都是互不相关的,不像数组、索引、字符串那样元素之间是有关系的。所以设计成了每一个单独处理,最后合并。

          知道了 TypeScript 怎么处理的联合类型,趁热打铁来练习一下:

          CamelcaseUnion

          Camelcase 我们实现过,就是提取字符串中的字符,首字母大写以后重新构造一个新的。

          ts
          type Camelcase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${Camelcase<Rest>}`\n  : Str;

          提取 _ 左右的字符,把右边字符大写之后构造成新的字符串,余下的字符串递归处理。

          ts
          type CamelcaseResult = Camelcase<'aa_aa_aa'>;\n// type CamelcaseResult = 'aaAaAa'

          如果是对字符串数组做 Camelcase,那就要递归处理每一个元素:

          ts
          type CamelcaseArr<Arr extends unknown[]> = Arr extends [infer Item, ...infer RestArr]\n  ? [Camelcase<Item & string>, ...CamelcaseArr<RestArr>]\n  : [];

          类型参数 Arr 为待处理数组。

          递归提取每一个元素做 Camelcase,因为 Camelcase 要求传入 string,这里要 & string 来变成 string 类型。

          那如果是联合类型呢?

          联合类型不需要递归提取每个元素,TypeScript 内部会把每一个元素传入单独做计算,之后把每个元素的计算结果合并成联合类型。

          ts
          type CamelcaseUnion<Item extends string> = Item extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${CamelcaseUnion<Rest>}`\n  : Item;

          这不和单个字符串的处理没区别么?

          没错,对联合类型的处理和对单个类型的处理没什么区别,TypeScript 会把每个单独的类型拆开传入。不需要像数组类型那样需要递归提取每个元素做处理。

          确实简化了很多,好像都是优点?

          也不全是,其实这样处理也增加了一些认知成本,不信我们再来看个例子:

          IsUnion

          判断联合类型我们会这样写:

          ts
          type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

          当传入联合类型时,会返回 true:

          ts
          type IsUnionResult = IsUnion<'a' | 'b' 'c'>\n// type IsUnionResult = true

          当传入其他类型时,会返回 false:

          ts
          type IsUnionResult = IsUnion<['a' | 'b' 'c']>\n// type IsUnionResult = false

          这就是分布式条件类型带来的认知成本。

          我们先来看这样一个类型:

          ts
          type TestUnion<A, B = A> = A extends A ? { a: A; b: B } : never;\n\ntype TestUnionResult = TestUnion<'a' | 'b' | 'c'>;

          传入联合类型 'a' | 'b' | 'c' 的时候,结果是这样的:

          A 和 B 都是同一个联合类型,为啥值还不一样呢?

          因为条件类型中如果左边的类型是联合类型,会把每个元素单独传入做计算,而右边不会。

          所以 A 是 'a' 的时候,B 是 'a' | 'b' | 'c', A 是 'b' 的时候,B 是 'a' | 'b' | 'c'。。。

          那么利用这个特点就可以实现 Union 类型的判断:

          ts
          type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

          类型参数 A、B 是待判断的联合类型,B 默认值为 A,也就是同一个类型。

          A extends A 这段看似没啥意义,主要是为了触发分布式条件类型,让 A 的每个类型单独传入。

          [B] extends [A] 这样不直接写 B 就可以避免触发分布式条件类型,那么 B 就是整个联合类型。

          B 是联合类型整体,而 A 是单个类型,自然不成立,而其它类型没有这种特殊处理,A 和 B 都是同一个,怎么判断都成立。

          利用这个特点就可以判断出是否是联合类型。

          其中有两个点比较困惑,我们重点记一下:

          当 A 是联合类型时:

          A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。

          A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。

          理解了这两点,分布式条件类型就算掌握了。

          BEM

          bem 是 css 命名规范,用 block__element--modifier 的形式来描述某个区块下面的某个元素的某个状态的样式。

          那么我们可以写这样一个高级类型,传入 block、element、modifier,返回构造出的 class 名:

          这样使用:

          ts
          type bemResult = BEM<'guang', ['aaa', 'bbb'], ['warning', 'success']>;

          它的实现就是三部分的合并,但传入的是数组,要递归遍历取出每一个元素来和其他部分组合,这样太麻烦了。

          而如果是联合类型就不用递归遍历了,因为联合类型遇到字符串也是会单独每个元素单独传入做处理。

          数组转联合类型可以这样写:

          ts
          type union = ['aaa', 'bbb'][number];\n// type union = 'aaa' | 'bbb'

          那么 BEM 就可以这样实现:

          ts
          type BEM<\n  Block extends string,\n  Element extends string[],\n  Modifiers extends string[],\n> = `${Block}__${Element[number]}--${Modifiers[number]}`;

          类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

          构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

          字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

          ts
          type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;\n// type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

          可以看到,用好了联合类型,确实能简化类型编程逻辑。

          AllCombinations

          我们再来实现一个全组合的高级类型,也是联合类型相关的:

          希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

          这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

          比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

          任何两个类型的组合有四种:A、B、AB、BA

          ts
          type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

          然后构造出来的字符串再和其他字符串组合。

          所以全组合的高级类型就是这样:

          ts
          type AllCombinations<A extends string, B extends string = A> = A extends A\n  ? Combination<A, AllCombinations<Exclude<B, A>>>\n  : never;

          类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

          A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

          A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

          而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

          总结

          联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

          条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

          有两点特别要注意:

          • A extends A 不是没意义,意义是取出联合类型中的单个类型放入 A

          • A extends A 才是分布式条件类型, [A] extends [A] 就不是了,只有左边是单独的类型参数才可以。

          我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

          ',91)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"分布式条件类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/typescript/unionType.md","filePath":"cn/src/article/typescript/unionType.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/typescript/unionType.md"};function n(p,s,l,e,d,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

          分布式条件类型

          当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。

          比如这样一个联合类型:

          ts
          type Union = 'a' | 'b' | 'c';

          我们想把其中的 a 大写,就可以这样写:

          ts
          type UppercaseA<Item extends string> = Item extends 'a' ? Uppercase<Item> : Item;
          ts
          type result = UppercaseA<Union>;\n// type result = 'A' | 'b' | 'c';

          可以看到,我们类型参数 Item 约束为 string,条件类型的判断中也是判断是否是 a,但传入的是联合类型。

          这就是 TypeScript 对联合类型在条件类型中使用时的特殊处理:会把联合类型的每一个元素单独传入做类型计算,最后合并。

          这和联合类型遇到字符串时的处理一样:

          这样确实是简化了类型编程逻辑的,不需要递归提取每个元素再处理。

          TypeScript 之所以这样处理联合类型也很容易理解,因为联合类型的每个元素都是互不相关的,不像数组、索引、字符串那样元素之间是有关系的。所以设计成了每一个单独处理,最后合并。

          知道了 TypeScript 怎么处理的联合类型,趁热打铁来练习一下:

          CamelcaseUnion

          Camelcase 我们实现过,就是提取字符串中的字符,首字母大写以后重新构造一个新的。

          ts
          type Camelcase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${Camelcase<Rest>}`\n  : Str;

          提取 _ 左右的字符,把右边字符大写之后构造成新的字符串,余下的字符串递归处理。

          ts
          type CamelcaseResult = Camelcase<'aa_aa_aa'>;\n// type CamelcaseResult = 'aaAaAa'

          如果是对字符串数组做 Camelcase,那就要递归处理每一个元素:

          ts
          type CamelcaseArr<Arr extends unknown[]> = Arr extends [infer Item, ...infer RestArr]\n  ? [Camelcase<Item & string>, ...CamelcaseArr<RestArr>]\n  : [];

          类型参数 Arr 为待处理数组。

          递归提取每一个元素做 Camelcase,因为 Camelcase 要求传入 string,这里要 & string 来变成 string 类型。

          那如果是联合类型呢?

          联合类型不需要递归提取每个元素,TypeScript 内部会把每一个元素传入单独做计算,之后把每个元素的计算结果合并成联合类型。

          ts
          type CamelcaseUnion<Item extends string> = Item extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${CamelcaseUnion<Rest>}`\n  : Item;

          这不和单个字符串的处理没区别么?

          没错,对联合类型的处理和对单个类型的处理没什么区别,TypeScript 会把每个单独的类型拆开传入。不需要像数组类型那样需要递归提取每个元素做处理。

          确实简化了很多,好像都是优点?

          也不全是,其实这样处理也增加了一些认知成本,不信我们再来看个例子:

          IsUnion

          判断联合类型我们会这样写:

          ts
          type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

          当传入联合类型时,会返回 true:

          ts
          type IsUnionResult = IsUnion<'a' | 'b' 'c'>\n// type IsUnionResult = true

          当传入其他类型时,会返回 false:

          ts
          type IsUnionResult = IsUnion<['a' | 'b' 'c']>\n// type IsUnionResult = false

          这就是分布式条件类型带来的认知成本。

          我们先来看这样一个类型:

          ts
          type TestUnion<A, B = A> = A extends A ? { a: A; b: B } : never;\n\ntype TestUnionResult = TestUnion<'a' | 'b' | 'c'>;

          传入联合类型 'a' | 'b' | 'c' 的时候,结果是这样的:

          A 和 B 都是同一个联合类型,为啥值还不一样呢?

          因为条件类型中如果左边的类型是联合类型,会把每个元素单独传入做计算,而右边不会。

          所以 A 是 'a' 的时候,B 是 'a' | 'b' | 'c', A 是 'b' 的时候,B 是 'a' | 'b' | 'c'。。。

          那么利用这个特点就可以实现 Union 类型的判断:

          ts
          type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

          类型参数 A、B 是待判断的联合类型,B 默认值为 A,也就是同一个类型。

          A extends A 这段看似没啥意义,主要是为了触发分布式条件类型,让 A 的每个类型单独传入。

          [B] extends [A] 这样不直接写 B 就可以避免触发分布式条件类型,那么 B 就是整个联合类型。

          B 是联合类型整体,而 A 是单个类型,自然不成立,而其它类型没有这种特殊处理,A 和 B 都是同一个,怎么判断都成立。

          利用这个特点就可以判断出是否是联合类型。

          其中有两个点比较困惑,我们重点记一下:

          当 A 是联合类型时:

          A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。

          A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。

          理解了这两点,分布式条件类型就算掌握了。

          BEM

          bem 是 css 命名规范,用 block__element--modifier 的形式来描述某个区块下面的某个元素的某个状态的样式。

          那么我们可以写这样一个高级类型,传入 block、element、modifier,返回构造出的 class 名:

          这样使用:

          ts
          type bemResult = BEM<'guang', ['aaa', 'bbb'], ['warning', 'success']>;

          它的实现就是三部分的合并,但传入的是数组,要递归遍历取出每一个元素来和其他部分组合,这样太麻烦了。

          而如果是联合类型就不用递归遍历了,因为联合类型遇到字符串也是会单独每个元素单独传入做处理。

          数组转联合类型可以这样写:

          ts
          type union = ['aaa', 'bbb'][number];\n// type union = 'aaa' | 'bbb'

          那么 BEM 就可以这样实现:

          ts
          type BEM<\n  Block extends string,\n  Element extends string[],\n  Modifiers extends string[],\n> = `${Block}__${Element[number]}--${Modifiers[number]}`;

          类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

          构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

          字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

          ts
          type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;\n// type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

          可以看到,用好了联合类型,确实能简化类型编程逻辑。

          AllCombinations

          我们再来实现一个全组合的高级类型,也是联合类型相关的:

          希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

          这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

          比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

          任何两个类型的组合有四种:A、B、AB、BA

          ts
          type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

          然后构造出来的字符串再和其他字符串组合。

          所以全组合的高级类型就是这样:

          ts
          type AllCombinations<A extends string, B extends string = A> = A extends A\n  ? Combination<A, AllCombinations<Exclude<B, A>>>\n  : never;

          类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

          A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

          A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

          而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

          总结

          联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

          条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

          有两点特别要注意:

          • A extends A 不是没意义,意义是取出联合类型中的单个类型放入 A

          • A extends A 才是分布式条件类型, [A] extends [A] 就不是了,只有左边是单独的类型参数才可以。

          我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

          ',91)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; diff --git a/assets/cn_src_article_video.md.Dr5fjwZA.js b/assets/cn_src_article_video.md.BmsbKb7b.js similarity index 99% rename from assets/cn_src_article_video.md.Dr5fjwZA.js rename to assets/cn_src_article_video.md.BmsbKb7b.js index acd56a88f3..38126beceb 100644 --- a/assets/cn_src_article_video.md.Dr5fjwZA.js +++ b/assets/cn_src_article_video.md.BmsbKb7b.js @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const t="/ran/assets/bilibili_video_code.DgWtgAEf.webp",p="/ran/assets/bili_demo_url.BQDGtHUp.webp",l="/ran/assets/bilibili_video_m4s.BccuY7bk.webp",k="/ran/assets/aqiyi_demo.s0swGzvF.webp",e="/ran/assets/tiktok_video.DuwKyIdt.webp",d="/ran/assets/tiktik_video_demo.mxxBzLay.webp",E="/ran/assets/red_book.DiBEvryP.webp",r="/ran/assets/safari_support_media.Bafr23bR.webp",g="/ran/assets/firefox_support_media.BLmSeBNy.webp",o="/ran/assets/ms_support.CaZSSiRt.webp",c="/ran/assets/ts_demo.D_l_mv9k.webp",y="/ran/assets/video_format.CRMCTmKB.webp",F="/ran/assets/xgplayer_docs.CpHb1Wan.webp",C="/ran/assets/bili_demo.CI8Ur8IA.webp",u="/ran/assets/rplayer_demo.CoJ7kuJt.webp",x=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/video.md","filePath":"cn/src/article/video.md","lastUpdated":1728828157000}'),B={name:"cn/src/article/video.md"};function m(A,s,b,v,D,f){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          实现自适应码率 Web 视频加密播放:前后端的挑战与解决方案

          最近又遇到了web视频化的场景,之前也有过调研:H5 视频化调研浅析

          但这次稍微复杂一些,这次解决的是:

          1. 视频播放的技术方案调研

          服务端实现:

          1. 视频转码
          2. 生成不同码率的视频
          3. 进行视频标准加密
          4. 不同码率视频合并,用于动态码率播放

          web端实现

          1. web端播放器的设计
          2. web端播放器的自定义扩展
          3. 可拖拽进度条
          4. 音量控制
          5. 根据当前带宽自适应码率切换
          6. 手动清晰度切换
          7. 倍速播放
          8. 样式自定义覆盖
          9. 标准加密视频播放
          10. 基于原生开发,可在所有框架运行,统一跨框架情况
          11. 各浏览器控件统一

          其中web端源码已添加MIT协议并完全开源,如果看完对大家有帮助的话,欢迎大家star,issue,pr,也希望能友好交流~

          demo 地址:https://chaxus.github.io/ran/src/ranui/player/

          源码地址:https://github.com/chaxus/ran

          demo文档做了国际化,可切换到中文

          任何一个项目,立项肯定先是技术调研,我们先看看一些大公司的视频播放方案

          一:一些知名公司的 web 视频播放方案

          1.B 站

          我们先看看 B 站的,毕竟 B 站的主营业务就是视频弹幕网站,简直专业对口。

          先找一个例子:https://www.bilibili.com/video/BV1FM411N7LJ 访问它。

          image.png

          打开控制台,可以看到,视频在播放的时候,会不断的请求m4s的视频文件。

          毕竟一整个视频文件往往比较大,不可能先请求完视频文件,再进行播放。因此将一个大的视频文件分割成很多小的片段,边加载边播放,是一种更好的方式。

          image.png

          每次请求的m4s文件大概在几十kb到几百kb不等。

          image.png

          那为什么不采用httprange呢,可以请求一个文件的部分内容,而且粒度更细,可以设置字节范围。在http请求的header中,类似这样

          js
          Range: bytes = 3171375 - 3203867;

          我们可以检查这个链接请求https://upos-sz-mirror08c.bilivideo.com/upgcxcode/67/92/1008149267/1008149267-1-30064.m4s的请求头,就能发现,B 站采用的是,即分片加载,同时还用了range的方式。

          2. 爱奇艺:(爱奇艺、土豆、优酷)

          爱奇艺这里就不贴视频链接了,因为随便点一个视频,都要先看广告。

          image.png

          爱奇艺的视频主要请求的是f4v格式,也是分片加载。

          播放一个视频时,请求多个f4v文件。

          也采用Range。但和 B 站不一样的是,B 站的Range属性是在m4s请求的请求头里面,而爱奇艺的看起来是在querystring上,在请求query上带着range参数。

          因为没发现这个请求的header里面有range参数。比如:

          https://v-6fce1712.71edge.com/videos/other/20231113/6b/bb/3f3fe83b89124248c3216156dfe2f4c3.f4v?dis_k=2ba39ee8c55c4d23781e3fb9f91fa7a46&dis_t=1701439831&dis_dz=CNC-BeiJing&dis_st=46&src=iqiyi.com&dis_hit=0&dis_tag=01010000&uuid=72713f52-6569e957-351&cross-domain=1&ssl=1&pv=0.1&cphc=arta&range=0-9000

          3.抖音:

          抖音的方案简单粗暴,访问的链接是这个: https://m.ixigua.com/douyin/share/video/7206914252840370721?aweme_type=107&schema_type=1&utm_source=copy&utm_campaign=client_share&utm_medium=android&app=aweme

          通过查看控制台,我们可以发现,直接请求了一个视频的地址

          image.png

          没有进行分片,但用到了请求range,所以可以看到视频,是边播放边缓冲一部分。

          不过我在开发的时候发现,目前租用的服务云厂商,默认会帮我们实现这项技术。

          因为我把mp4视频上传到云服务器,通过链接进行播放的时候,就是边缓冲边播放的。

          我们可以直接把这个视频地址拿出来,放到浏览器里面能直接播放,这样观察更明显。

          image.png

          但 B 站和爱奇艺却不能这样,因为他们采用的m4sf4v都不是一种通用的视频格式,需要使用专门的软件或工具才能打开和编辑。

          4.小红书:

          测试用的例子链接:https://www.xiaohongshu.com/discovery/item/63b286d1000000001f00b495

          小红书的方案更加简单粗暴,打开控制台,直接告诉你就是请求一个mp4,然后直接播放就完事了。

          image.png

          5.总结

          看完了以上的各家大厂的方案,我们可以看到,基本原理都是边播放边加载,减少直接加载大视频文本的成本。并且通过分片传输,还能动态控制视频码率(清晰度)。做到根据网速,加载不同码率的分片文件,做到动态码率适应。

          同时采用的视频格式,比如f4vm4s,都不是能直接播放的媒体格式,需要一定的处理。增加盗取视频的成本,增加一定的安全性。

          如果没有强要求,也可以直接采用mp4,或者直接用video播放一个视频文件地址。

          二:常见的视频格式与协议

          我们知道视频的常见格式有mp4,同时上面介绍了 B 站播放用的m4s格式,爱奇艺用的f4v格式

          • 除了这些还有哪些视频格式?
          • 为什么有这么多视频格式,有哪些不同点呢?
          • 为什么这些公司会采用这种格式来播放视频呢?

          1. B 站用的m4s

          M4S格式不是一种通用的视频格式,需要使用专门的软件或工具才能打开和编辑。

          M4S 通常会和 MPEG-DASH 流媒体技术一起,通过流式传输的视频的一小部分。播放器会按接收顺序播放这些片段。第一个 M4S 段会包含一些初始化的数据标识。

          MPEG-DASH 是一种自适应比特率流媒体技术,通过将内容分解为一系列不同码率的M4S片段,然后根据当前网络带宽进行自动调整。如果想在在web音视频中采用DASH技术,可以看下 https://github.com/Dash-Industry-Forum/dash.js

          2. 爱奇艺的f4v

          F4V是一种流媒体格式,它是由Adobe公司推出的,继FLV格式之后支持H.264编码的流媒体格式。F4V格式的视频不是一种通用的视频格式,但通常情况下,都可以将文件后缀改为FLV,这样就可以使用支持FLV的播放器进行观看。

          FLV格式跟常见的MP4格式比起来,结构更加简单,所以加载metadata(视频元数据,比如视频时长等信息) 会更快。具体结构我们可以在这里查到:https://en.wikipedia.org/wiki/Flash_Video#Flash_Video_Structure

          比如,这是FLV文件的标准头,定义了从几个比特到几个比特之间,是什么含义。我们知道后,可以用MediaSource进行读取和转码。

          FieldData TypeDefaultDetails
          Signature 签名byte[3]"FLV"始终就是“FLV”
          Version 版本uint81只有 0x01 才有效
          Flags 标志uint8 位掩码0x050x04 是音频,0x01 是视频(所以 0x05 是音频 + 视频)
          Header Sizeuint32_be9用于跳过较新的扩展标头

          MP4格式会稍微复杂一些,具体标准在 ISO/IEC 14496-12 大概有两百多页,这里放不下,对这方面有兴趣的可以自行查看。

          然而这并不表示MP4更差,因为它是一种基础通用标准,所以定义上会留有很多空间,和各种情况,甚至允许在标准之内进行自行发挥和扩展。而FLV格式则更加固定,但优点也是更加简单。

          对于FLV的视频播放,我们可以采用:https://github.com/bilibili/flv.js flvjs主要作用就是用MediaSourceflv转码成mp4从而喂给浏览器进行播放。

          接下来是一些其他的视频格式,简单介绍一下:

          3.AVI

          文件名以.avi结尾,AVI 最初由 Microsoft1992 年开发,是 Windows 的标准视频格式。AVI 文件使用较少的压缩来存储文件,并且比许多其他视频格式占用更多空间,这导致文件大小非常大,每分钟视频大约 2-3 GB

          无损文件不会随着时间的推移而降低质量,无论您打开或保存文件多少次。此外,这允许在不使用任何编解码器的情况下播放。参考资料:Audio Video Interleave

          4.MPEG

          文件名以“.mpg”或“.mpeg”结尾,MPEG 是由 ISO 和 IEC 联合成立的工作组联盟,旨在制定媒体编码标准,包括音频、视频、图形和基因组数据的压缩编码;以及各种应用程序的传输和文件格式。MPEG 格式用于各种多媒体系统。最广为人知的旧 MPEG 媒体格式通常使用 MPEG-1、MPEG-2 和 MPEG-4 AVC 媒体编码,MPEG-2 系统传输流和节目流。较新的系统通常使用 MPEG 基本媒体文件格式和动态流式处理(又名 .MPEG-DASH)。参考资料:Moving Picture Experts Group

          5.MP4

          带有音频和视频的 MPEG-4 文件通常使用标准的 .mp4 扩展名。纯音频 MPEG-4 文件通常具有 .m4a 扩展名,原始 MPEG-4 可视比特流命名为 .m4v。Apple iPhone 使用 MPEG-4 音频作为其铃声,但使用.m4r 扩展名而不是.m4a 扩展名。参考资料:MPEG-4 Part 14

          6.QuickTime

          文件名以“.mov”结尾,QuickTime 能够包含媒体数据的抽象数据引用,并将媒体数据与媒体偏移和轨道编辑列表分离,这意味着 QuickTime 特别适合编辑,因为它能够就地导入和编辑(无需数据复制)。由于 QuickTime 和 MP4 容器格式都可以使用相同的 MPEG-4 格式,因此在仅限 QuickTime 的环境中,它们大多可以互换。MP4 作为国际标准,得到了更多的支持。参考资料:QuickTime File Format

          7.TS

          TS 是 MPEG2-TS 的简称,是一种音视频封装格式。TS 流的后缀通常是.ts、.mpg 或者.mpeg,多数播放器直接支持这种格式的播放。TS 格式主要用于直播的码流结构,具有很好的容错能力。

          三:浏览器对各种视频格式的兼容性

          上面了解常用的视频格式,和适用范围之后,还需要看一下当前浏览器,对各种视频格式的支持程度,然后制定技术方案。

          1. Chrome

          支持的视频格式从官方文档可以查到,主要有以下这些

          • MP4 (QuickTime/ MOV / ISO-BMFF / CMAF)
          • Ogg
          • WebM
          • WAV
          • HLS [Only on Android and only single-origin manifests]

          官方文档如下:https://www.chromium.org/audio-video/

          2. Safari

          支持的视频格式有这些:

          image.png

          官方文档:https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html

          3.Firefox

          支持的视频格式:

          image.png

          官方文档:https://support.mozilla.org/en-US/kb/html5-audio-and-video-firefox

          四:MediaSource 和视频编码,解码,封装介绍

          上面介绍了一些视频格式,和目前浏览器的一些兼容性问题。就能发现,在web上播放音视频其实限制还是很大的。如何解决这些限制,就会用到MediaSource

          视频其实是无数个图片的叠加,如果视频是一秒60帧,大约一秒中需要播放60张图片。这就导致一个几分钟的视频,就会非常大。比如上面介绍的无损格式,avi格式,每分钟视频大约 2-3 GB。这时候视频就需要进行编码。其实就是压缩。

          编码分为视频编码和音频编码,常见的视频编码有:

          • MPEG 系列MPEG-1第二部分、MPEG-2第二部分(等同于H.262)、MPEG-4第二部分、MPEG-4第十部分(等同于H.264,有时候也被叫做“MPEG-4 AVC”或“H.264/AVC”)。
          • H.26x 系列H.261H.262H.263H.264(等同于MPEG-4第十部分)、H.265/HEVCITU-TISO/IEC联合推出)。
          • 其它视频编码WMV系列、RV系列、VC-1DivXXviDX264X265VP8VP9Sorenson VideoAVS

          常见的音频编码有:AACMP3AC-3

          编码之后,还需要将音频和视频合并在一个文件里,这就是封装

          所以相对的,播放一个视频,就需要解封装,解码,音视频同步喂给声卡和显卡进行播放。

          MediaSource做的就是这个工作,读取视频流,转换成浏览器能播放的格式。

          以下是flv.jsparseChunks部分内容。读取buffer,一个字节一个字节的根据标准进行解析。然后转码。

          js
          if (byteStart === 0) {
          +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const t="/ran/assets/bilibili_video_code.DgWtgAEf.webp",p="/ran/assets/bili_demo_url.BQDGtHUp.webp",l="/ran/assets/bilibili_video_m4s.BccuY7bk.webp",k="/ran/assets/aqiyi_demo.s0swGzvF.webp",e="/ran/assets/tiktok_video.DuwKyIdt.webp",d="/ran/assets/tiktik_video_demo.mxxBzLay.webp",E="/ran/assets/red_book.DiBEvryP.webp",r="/ran/assets/safari_support_media.Bafr23bR.webp",g="/ran/assets/firefox_support_media.BLmSeBNy.webp",o="/ran/assets/ms_support.CaZSSiRt.webp",c="/ran/assets/ts_demo.D_l_mv9k.webp",y="/ran/assets/video_format.CRMCTmKB.webp",F="/ran/assets/xgplayer_docs.CpHb1Wan.webp",C="/ran/assets/bili_demo.CI8Ur8IA.webp",u="/ran/assets/rplayer_demo.CoJ7kuJt.webp",x=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/video.md","filePath":"cn/src/article/video.md","lastUpdated":1728921295000}'),B={name:"cn/src/article/video.md"};function m(A,s,b,v,D,f){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          实现自适应码率 Web 视频加密播放:前后端的挑战与解决方案

          最近又遇到了web视频化的场景,之前也有过调研:H5 视频化调研浅析

          但这次稍微复杂一些,这次解决的是:

          1. 视频播放的技术方案调研

          服务端实现:

          1. 视频转码
          2. 生成不同码率的视频
          3. 进行视频标准加密
          4. 不同码率视频合并,用于动态码率播放

          web端实现

          1. web端播放器的设计
          2. web端播放器的自定义扩展
          3. 可拖拽进度条
          4. 音量控制
          5. 根据当前带宽自适应码率切换
          6. 手动清晰度切换
          7. 倍速播放
          8. 样式自定义覆盖
          9. 标准加密视频播放
          10. 基于原生开发,可在所有框架运行,统一跨框架情况
          11. 各浏览器控件统一

          其中web端源码已添加MIT协议并完全开源,如果看完对大家有帮助的话,欢迎大家star,issue,pr,也希望能友好交流~

          demo 地址:https://chaxus.github.io/ran/src/ranui/player/

          源码地址:https://github.com/chaxus/ran

          demo文档做了国际化,可切换到中文

          任何一个项目,立项肯定先是技术调研,我们先看看一些大公司的视频播放方案

          一:一些知名公司的 web 视频播放方案

          1.B 站

          我们先看看 B 站的,毕竟 B 站的主营业务就是视频弹幕网站,简直专业对口。

          先找一个例子:https://www.bilibili.com/video/BV1FM411N7LJ 访问它。

          image.png

          打开控制台,可以看到,视频在播放的时候,会不断的请求m4s的视频文件。

          毕竟一整个视频文件往往比较大,不可能先请求完视频文件,再进行播放。因此将一个大的视频文件分割成很多小的片段,边加载边播放,是一种更好的方式。

          image.png

          每次请求的m4s文件大概在几十kb到几百kb不等。

          image.png

          那为什么不采用httprange呢,可以请求一个文件的部分内容,而且粒度更细,可以设置字节范围。在http请求的header中,类似这样

          js
          Range: bytes = 3171375 - 3203867;

          我们可以检查这个链接请求https://upos-sz-mirror08c.bilivideo.com/upgcxcode/67/92/1008149267/1008149267-1-30064.m4s的请求头,就能发现,B 站采用的是,即分片加载,同时还用了range的方式。

          2. 爱奇艺:(爱奇艺、土豆、优酷)

          爱奇艺这里就不贴视频链接了,因为随便点一个视频,都要先看广告。

          image.png

          爱奇艺的视频主要请求的是f4v格式,也是分片加载。

          播放一个视频时,请求多个f4v文件。

          也采用Range。但和 B 站不一样的是,B 站的Range属性是在m4s请求的请求头里面,而爱奇艺的看起来是在querystring上,在请求query上带着range参数。

          因为没发现这个请求的header里面有range参数。比如:

          https://v-6fce1712.71edge.com/videos/other/20231113/6b/bb/3f3fe83b89124248c3216156dfe2f4c3.f4v?dis_k=2ba39ee8c55c4d23781e3fb9f91fa7a46&dis_t=1701439831&dis_dz=CNC-BeiJing&dis_st=46&src=iqiyi.com&dis_hit=0&dis_tag=01010000&uuid=72713f52-6569e957-351&cross-domain=1&ssl=1&pv=0.1&cphc=arta&range=0-9000

          3.抖音:

          抖音的方案简单粗暴,访问的链接是这个: https://m.ixigua.com/douyin/share/video/7206914252840370721?aweme_type=107&schema_type=1&utm_source=copy&utm_campaign=client_share&utm_medium=android&app=aweme

          通过查看控制台,我们可以发现,直接请求了一个视频的地址

          image.png

          没有进行分片,但用到了请求range,所以可以看到视频,是边播放边缓冲一部分。

          不过我在开发的时候发现,目前租用的服务云厂商,默认会帮我们实现这项技术。

          因为我把mp4视频上传到云服务器,通过链接进行播放的时候,就是边缓冲边播放的。

          我们可以直接把这个视频地址拿出来,放到浏览器里面能直接播放,这样观察更明显。

          image.png

          但 B 站和爱奇艺却不能这样,因为他们采用的m4sf4v都不是一种通用的视频格式,需要使用专门的软件或工具才能打开和编辑。

          4.小红书:

          测试用的例子链接:https://www.xiaohongshu.com/discovery/item/63b286d1000000001f00b495

          小红书的方案更加简单粗暴,打开控制台,直接告诉你就是请求一个mp4,然后直接播放就完事了。

          image.png

          5.总结

          看完了以上的各家大厂的方案,我们可以看到,基本原理都是边播放边加载,减少直接加载大视频文本的成本。并且通过分片传输,还能动态控制视频码率(清晰度)。做到根据网速,加载不同码率的分片文件,做到动态码率适应。

          同时采用的视频格式,比如f4vm4s,都不是能直接播放的媒体格式,需要一定的处理。增加盗取视频的成本,增加一定的安全性。

          如果没有强要求,也可以直接采用mp4,或者直接用video播放一个视频文件地址。

          二:常见的视频格式与协议

          我们知道视频的常见格式有mp4,同时上面介绍了 B 站播放用的m4s格式,爱奇艺用的f4v格式

          • 除了这些还有哪些视频格式?
          • 为什么有这么多视频格式,有哪些不同点呢?
          • 为什么这些公司会采用这种格式来播放视频呢?

          1. B 站用的m4s

          M4S格式不是一种通用的视频格式,需要使用专门的软件或工具才能打开和编辑。

          M4S 通常会和 MPEG-DASH 流媒体技术一起,通过流式传输的视频的一小部分。播放器会按接收顺序播放这些片段。第一个 M4S 段会包含一些初始化的数据标识。

          MPEG-DASH 是一种自适应比特率流媒体技术,通过将内容分解为一系列不同码率的M4S片段,然后根据当前网络带宽进行自动调整。如果想在在web音视频中采用DASH技术,可以看下 https://github.com/Dash-Industry-Forum/dash.js

          2. 爱奇艺的f4v

          F4V是一种流媒体格式,它是由Adobe公司推出的,继FLV格式之后支持H.264编码的流媒体格式。F4V格式的视频不是一种通用的视频格式,但通常情况下,都可以将文件后缀改为FLV,这样就可以使用支持FLV的播放器进行观看。

          FLV格式跟常见的MP4格式比起来,结构更加简单,所以加载metadata(视频元数据,比如视频时长等信息) 会更快。具体结构我们可以在这里查到:https://en.wikipedia.org/wiki/Flash_Video#Flash_Video_Structure

          比如,这是FLV文件的标准头,定义了从几个比特到几个比特之间,是什么含义。我们知道后,可以用MediaSource进行读取和转码。

          FieldData TypeDefaultDetails
          Signature 签名byte[3]"FLV"始终就是“FLV”
          Version 版本uint81只有 0x01 才有效
          Flags 标志uint8 位掩码0x050x04 是音频,0x01 是视频(所以 0x05 是音频 + 视频)
          Header Sizeuint32_be9用于跳过较新的扩展标头

          MP4格式会稍微复杂一些,具体标准在 ISO/IEC 14496-12 大概有两百多页,这里放不下,对这方面有兴趣的可以自行查看。

          然而这并不表示MP4更差,因为它是一种基础通用标准,所以定义上会留有很多空间,和各种情况,甚至允许在标准之内进行自行发挥和扩展。而FLV格式则更加固定,但优点也是更加简单。

          对于FLV的视频播放,我们可以采用:https://github.com/bilibili/flv.js flvjs主要作用就是用MediaSourceflv转码成mp4从而喂给浏览器进行播放。

          接下来是一些其他的视频格式,简单介绍一下:

          3.AVI

          文件名以.avi结尾,AVI 最初由 Microsoft1992 年开发,是 Windows 的标准视频格式。AVI 文件使用较少的压缩来存储文件,并且比许多其他视频格式占用更多空间,这导致文件大小非常大,每分钟视频大约 2-3 GB

          无损文件不会随着时间的推移而降低质量,无论您打开或保存文件多少次。此外,这允许在不使用任何编解码器的情况下播放。参考资料:Audio Video Interleave

          4.MPEG

          文件名以“.mpg”或“.mpeg”结尾,MPEG 是由 ISO 和 IEC 联合成立的工作组联盟,旨在制定媒体编码标准,包括音频、视频、图形和基因组数据的压缩编码;以及各种应用程序的传输和文件格式。MPEG 格式用于各种多媒体系统。最广为人知的旧 MPEG 媒体格式通常使用 MPEG-1、MPEG-2 和 MPEG-4 AVC 媒体编码,MPEG-2 系统传输流和节目流。较新的系统通常使用 MPEG 基本媒体文件格式和动态流式处理(又名 .MPEG-DASH)。参考资料:Moving Picture Experts Group

          5.MP4

          带有音频和视频的 MPEG-4 文件通常使用标准的 .mp4 扩展名。纯音频 MPEG-4 文件通常具有 .m4a 扩展名,原始 MPEG-4 可视比特流命名为 .m4v。Apple iPhone 使用 MPEG-4 音频作为其铃声,但使用.m4r 扩展名而不是.m4a 扩展名。参考资料:MPEG-4 Part 14

          6.QuickTime

          文件名以“.mov”结尾,QuickTime 能够包含媒体数据的抽象数据引用,并将媒体数据与媒体偏移和轨道编辑列表分离,这意味着 QuickTime 特别适合编辑,因为它能够就地导入和编辑(无需数据复制)。由于 QuickTime 和 MP4 容器格式都可以使用相同的 MPEG-4 格式,因此在仅限 QuickTime 的环境中,它们大多可以互换。MP4 作为国际标准,得到了更多的支持。参考资料:QuickTime File Format

          7.TS

          TS 是 MPEG2-TS 的简称,是一种音视频封装格式。TS 流的后缀通常是.ts、.mpg 或者.mpeg,多数播放器直接支持这种格式的播放。TS 格式主要用于直播的码流结构,具有很好的容错能力。

          三:浏览器对各种视频格式的兼容性

          上面了解常用的视频格式,和适用范围之后,还需要看一下当前浏览器,对各种视频格式的支持程度,然后制定技术方案。

          1. Chrome

          支持的视频格式从官方文档可以查到,主要有以下这些

          • MP4 (QuickTime/ MOV / ISO-BMFF / CMAF)
          • Ogg
          • WebM
          • WAV
          • HLS [Only on Android and only single-origin manifests]

          官方文档如下:https://www.chromium.org/audio-video/

          2. Safari

          支持的视频格式有这些:

          image.png

          官方文档:https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html

          3.Firefox

          支持的视频格式:

          image.png

          官方文档:https://support.mozilla.org/en-US/kb/html5-audio-and-video-firefox

          四:MediaSource 和视频编码,解码,封装介绍

          上面介绍了一些视频格式,和目前浏览器的一些兼容性问题。就能发现,在web上播放音视频其实限制还是很大的。如何解决这些限制,就会用到MediaSource

          视频其实是无数个图片的叠加,如果视频是一秒60帧,大约一秒中需要播放60张图片。这就导致一个几分钟的视频,就会非常大。比如上面介绍的无损格式,avi格式,每分钟视频大约 2-3 GB。这时候视频就需要进行编码。其实就是压缩。

          编码分为视频编码和音频编码,常见的视频编码有:

          • MPEG 系列MPEG-1第二部分、MPEG-2第二部分(等同于H.262)、MPEG-4第二部分、MPEG-4第十部分(等同于H.264,有时候也被叫做“MPEG-4 AVC”或“H.264/AVC”)。
          • H.26x 系列H.261H.262H.263H.264(等同于MPEG-4第十部分)、H.265/HEVCITU-TISO/IEC联合推出)。
          • 其它视频编码WMV系列、RV系列、VC-1DivXXviDX264X265VP8VP9Sorenson VideoAVS

          常见的音频编码有:AACMP3AC-3

          编码之后,还需要将音频和视频合并在一个文件里,这就是封装

          所以相对的,播放一个视频,就需要解封装,解码,音视频同步喂给声卡和显卡进行播放。

          MediaSource做的就是这个工作,读取视频流,转换成浏览器能播放的格式。

          以下是flv.jsparseChunks部分内容。读取buffer,一个字节一个字节的根据标准进行解析。然后转码。

          js
          if (byteStart === 0) {
             // buffer with FLV header
             if (chunk.byteLength > 13) {
               let probeData = FLVDemuxer.probe(chunk);
          diff --git a/assets/cn_src_article_video.md.Dr5fjwZA.lean.js b/assets/cn_src_article_video.md.BmsbKb7b.lean.js
          similarity index 99%
          rename from assets/cn_src_article_video.md.Dr5fjwZA.lean.js
          rename to assets/cn_src_article_video.md.BmsbKb7b.lean.js
          index acd56a88f3..38126beceb 100644
          --- a/assets/cn_src_article_video.md.Dr5fjwZA.lean.js
          +++ b/assets/cn_src_article_video.md.BmsbKb7b.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const t="/ran/assets/bilibili_video_code.DgWtgAEf.webp",p="/ran/assets/bili_demo_url.BQDGtHUp.webp",l="/ran/assets/bilibili_video_m4s.BccuY7bk.webp",k="/ran/assets/aqiyi_demo.s0swGzvF.webp",e="/ran/assets/tiktok_video.DuwKyIdt.webp",d="/ran/assets/tiktik_video_demo.mxxBzLay.webp",E="/ran/assets/red_book.DiBEvryP.webp",r="/ran/assets/safari_support_media.Bafr23bR.webp",g="/ran/assets/firefox_support_media.BLmSeBNy.webp",o="/ran/assets/ms_support.CaZSSiRt.webp",c="/ran/assets/ts_demo.D_l_mv9k.webp",y="/ran/assets/video_format.CRMCTmKB.webp",F="/ran/assets/xgplayer_docs.CpHb1Wan.webp",C="/ran/assets/bili_demo.CI8Ur8IA.webp",u="/ran/assets/rplayer_demo.CoJ7kuJt.webp",x=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/video.md","filePath":"cn/src/article/video.md","lastUpdated":1728828157000}'),B={name:"cn/src/article/video.md"};function m(A,s,b,v,D,f){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          实现自适应码率 Web 视频加密播放:前后端的挑战与解决方案

          最近又遇到了web视频化的场景,之前也有过调研:H5 视频化调研浅析

          但这次稍微复杂一些,这次解决的是:

          1. 视频播放的技术方案调研

          服务端实现:

          1. 视频转码
          2. 生成不同码率的视频
          3. 进行视频标准加密
          4. 不同码率视频合并,用于动态码率播放

          web端实现

          1. web端播放器的设计
          2. web端播放器的自定义扩展
          3. 可拖拽进度条
          4. 音量控制
          5. 根据当前带宽自适应码率切换
          6. 手动清晰度切换
          7. 倍速播放
          8. 样式自定义覆盖
          9. 标准加密视频播放
          10. 基于原生开发,可在所有框架运行,统一跨框架情况
          11. 各浏览器控件统一

          其中web端源码已添加MIT协议并完全开源,如果看完对大家有帮助的话,欢迎大家star,issue,pr,也希望能友好交流~

          demo 地址:https://chaxus.github.io/ran/src/ranui/player/

          源码地址:https://github.com/chaxus/ran

          demo文档做了国际化,可切换到中文

          任何一个项目,立项肯定先是技术调研,我们先看看一些大公司的视频播放方案

          一:一些知名公司的 web 视频播放方案

          1.B 站

          我们先看看 B 站的,毕竟 B 站的主营业务就是视频弹幕网站,简直专业对口。

          先找一个例子:https://www.bilibili.com/video/BV1FM411N7LJ 访问它。

          image.png

          打开控制台,可以看到,视频在播放的时候,会不断的请求m4s的视频文件。

          毕竟一整个视频文件往往比较大,不可能先请求完视频文件,再进行播放。因此将一个大的视频文件分割成很多小的片段,边加载边播放,是一种更好的方式。

          image.png

          每次请求的m4s文件大概在几十kb到几百kb不等。

          image.png

          那为什么不采用httprange呢,可以请求一个文件的部分内容,而且粒度更细,可以设置字节范围。在http请求的header中,类似这样

          js
          Range: bytes = 3171375 - 3203867;

          我们可以检查这个链接请求https://upos-sz-mirror08c.bilivideo.com/upgcxcode/67/92/1008149267/1008149267-1-30064.m4s的请求头,就能发现,B 站采用的是,即分片加载,同时还用了range的方式。

          2. 爱奇艺:(爱奇艺、土豆、优酷)

          爱奇艺这里就不贴视频链接了,因为随便点一个视频,都要先看广告。

          image.png

          爱奇艺的视频主要请求的是f4v格式,也是分片加载。

          播放一个视频时,请求多个f4v文件。

          也采用Range。但和 B 站不一样的是,B 站的Range属性是在m4s请求的请求头里面,而爱奇艺的看起来是在querystring上,在请求query上带着range参数。

          因为没发现这个请求的header里面有range参数。比如:

          https://v-6fce1712.71edge.com/videos/other/20231113/6b/bb/3f3fe83b89124248c3216156dfe2f4c3.f4v?dis_k=2ba39ee8c55c4d23781e3fb9f91fa7a46&dis_t=1701439831&dis_dz=CNC-BeiJing&dis_st=46&src=iqiyi.com&dis_hit=0&dis_tag=01010000&uuid=72713f52-6569e957-351&cross-domain=1&ssl=1&pv=0.1&cphc=arta&range=0-9000

          3.抖音:

          抖音的方案简单粗暴,访问的链接是这个: https://m.ixigua.com/douyin/share/video/7206914252840370721?aweme_type=107&schema_type=1&utm_source=copy&utm_campaign=client_share&utm_medium=android&app=aweme

          通过查看控制台,我们可以发现,直接请求了一个视频的地址

          image.png

          没有进行分片,但用到了请求range,所以可以看到视频,是边播放边缓冲一部分。

          不过我在开发的时候发现,目前租用的服务云厂商,默认会帮我们实现这项技术。

          因为我把mp4视频上传到云服务器,通过链接进行播放的时候,就是边缓冲边播放的。

          我们可以直接把这个视频地址拿出来,放到浏览器里面能直接播放,这样观察更明显。

          image.png

          但 B 站和爱奇艺却不能这样,因为他们采用的m4sf4v都不是一种通用的视频格式,需要使用专门的软件或工具才能打开和编辑。

          4.小红书:

          测试用的例子链接:https://www.xiaohongshu.com/discovery/item/63b286d1000000001f00b495

          小红书的方案更加简单粗暴,打开控制台,直接告诉你就是请求一个mp4,然后直接播放就完事了。

          image.png

          5.总结

          看完了以上的各家大厂的方案,我们可以看到,基本原理都是边播放边加载,减少直接加载大视频文本的成本。并且通过分片传输,还能动态控制视频码率(清晰度)。做到根据网速,加载不同码率的分片文件,做到动态码率适应。

          同时采用的视频格式,比如f4vm4s,都不是能直接播放的媒体格式,需要一定的处理。增加盗取视频的成本,增加一定的安全性。

          如果没有强要求,也可以直接采用mp4,或者直接用video播放一个视频文件地址。

          二:常见的视频格式与协议

          我们知道视频的常见格式有mp4,同时上面介绍了 B 站播放用的m4s格式,爱奇艺用的f4v格式

          • 除了这些还有哪些视频格式?
          • 为什么有这么多视频格式,有哪些不同点呢?
          • 为什么这些公司会采用这种格式来播放视频呢?

          1. B 站用的m4s

          M4S格式不是一种通用的视频格式,需要使用专门的软件或工具才能打开和编辑。

          M4S 通常会和 MPEG-DASH 流媒体技术一起,通过流式传输的视频的一小部分。播放器会按接收顺序播放这些片段。第一个 M4S 段会包含一些初始化的数据标识。

          MPEG-DASH 是一种自适应比特率流媒体技术,通过将内容分解为一系列不同码率的M4S片段,然后根据当前网络带宽进行自动调整。如果想在在web音视频中采用DASH技术,可以看下 https://github.com/Dash-Industry-Forum/dash.js

          2. 爱奇艺的f4v

          F4V是一种流媒体格式,它是由Adobe公司推出的,继FLV格式之后支持H.264编码的流媒体格式。F4V格式的视频不是一种通用的视频格式,但通常情况下,都可以将文件后缀改为FLV,这样就可以使用支持FLV的播放器进行观看。

          FLV格式跟常见的MP4格式比起来,结构更加简单,所以加载metadata(视频元数据,比如视频时长等信息) 会更快。具体结构我们可以在这里查到:https://en.wikipedia.org/wiki/Flash_Video#Flash_Video_Structure

          比如,这是FLV文件的标准头,定义了从几个比特到几个比特之间,是什么含义。我们知道后,可以用MediaSource进行读取和转码。

          FieldData TypeDefaultDetails
          Signature 签名byte[3]"FLV"始终就是“FLV”
          Version 版本uint81只有 0x01 才有效
          Flags 标志uint8 位掩码0x050x04 是音频,0x01 是视频(所以 0x05 是音频 + 视频)
          Header Sizeuint32_be9用于跳过较新的扩展标头

          MP4格式会稍微复杂一些,具体标准在 ISO/IEC 14496-12 大概有两百多页,这里放不下,对这方面有兴趣的可以自行查看。

          然而这并不表示MP4更差,因为它是一种基础通用标准,所以定义上会留有很多空间,和各种情况,甚至允许在标准之内进行自行发挥和扩展。而FLV格式则更加固定,但优点也是更加简单。

          对于FLV的视频播放,我们可以采用:https://github.com/bilibili/flv.js flvjs主要作用就是用MediaSourceflv转码成mp4从而喂给浏览器进行播放。

          接下来是一些其他的视频格式,简单介绍一下:

          3.AVI

          文件名以.avi结尾,AVI 最初由 Microsoft1992 年开发,是 Windows 的标准视频格式。AVI 文件使用较少的压缩来存储文件,并且比许多其他视频格式占用更多空间,这导致文件大小非常大,每分钟视频大约 2-3 GB

          无损文件不会随着时间的推移而降低质量,无论您打开或保存文件多少次。此外,这允许在不使用任何编解码器的情况下播放。参考资料:Audio Video Interleave

          4.MPEG

          文件名以“.mpg”或“.mpeg”结尾,MPEG 是由 ISO 和 IEC 联合成立的工作组联盟,旨在制定媒体编码标准,包括音频、视频、图形和基因组数据的压缩编码;以及各种应用程序的传输和文件格式。MPEG 格式用于各种多媒体系统。最广为人知的旧 MPEG 媒体格式通常使用 MPEG-1、MPEG-2 和 MPEG-4 AVC 媒体编码,MPEG-2 系统传输流和节目流。较新的系统通常使用 MPEG 基本媒体文件格式和动态流式处理(又名 .MPEG-DASH)。参考资料:Moving Picture Experts Group

          5.MP4

          带有音频和视频的 MPEG-4 文件通常使用标准的 .mp4 扩展名。纯音频 MPEG-4 文件通常具有 .m4a 扩展名,原始 MPEG-4 可视比特流命名为 .m4v。Apple iPhone 使用 MPEG-4 音频作为其铃声,但使用.m4r 扩展名而不是.m4a 扩展名。参考资料:MPEG-4 Part 14

          6.QuickTime

          文件名以“.mov”结尾,QuickTime 能够包含媒体数据的抽象数据引用,并将媒体数据与媒体偏移和轨道编辑列表分离,这意味着 QuickTime 特别适合编辑,因为它能够就地导入和编辑(无需数据复制)。由于 QuickTime 和 MP4 容器格式都可以使用相同的 MPEG-4 格式,因此在仅限 QuickTime 的环境中,它们大多可以互换。MP4 作为国际标准,得到了更多的支持。参考资料:QuickTime File Format

          7.TS

          TS 是 MPEG2-TS 的简称,是一种音视频封装格式。TS 流的后缀通常是.ts、.mpg 或者.mpeg,多数播放器直接支持这种格式的播放。TS 格式主要用于直播的码流结构,具有很好的容错能力。

          三:浏览器对各种视频格式的兼容性

          上面了解常用的视频格式,和适用范围之后,还需要看一下当前浏览器,对各种视频格式的支持程度,然后制定技术方案。

          1. Chrome

          支持的视频格式从官方文档可以查到,主要有以下这些

          • MP4 (QuickTime/ MOV / ISO-BMFF / CMAF)
          • Ogg
          • WebM
          • WAV
          • HLS [Only on Android and only single-origin manifests]

          官方文档如下:https://www.chromium.org/audio-video/

          2. Safari

          支持的视频格式有这些:

          image.png

          官方文档:https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html

          3.Firefox

          支持的视频格式:

          image.png

          官方文档:https://support.mozilla.org/en-US/kb/html5-audio-and-video-firefox

          四:MediaSource 和视频编码,解码,封装介绍

          上面介绍了一些视频格式,和目前浏览器的一些兼容性问题。就能发现,在web上播放音视频其实限制还是很大的。如何解决这些限制,就会用到MediaSource

          视频其实是无数个图片的叠加,如果视频是一秒60帧,大约一秒中需要播放60张图片。这就导致一个几分钟的视频,就会非常大。比如上面介绍的无损格式,avi格式,每分钟视频大约 2-3 GB。这时候视频就需要进行编码。其实就是压缩。

          编码分为视频编码和音频编码,常见的视频编码有:

          • MPEG 系列MPEG-1第二部分、MPEG-2第二部分(等同于H.262)、MPEG-4第二部分、MPEG-4第十部分(等同于H.264,有时候也被叫做“MPEG-4 AVC”或“H.264/AVC”)。
          • H.26x 系列H.261H.262H.263H.264(等同于MPEG-4第十部分)、H.265/HEVCITU-TISO/IEC联合推出)。
          • 其它视频编码WMV系列、RV系列、VC-1DivXXviDX264X265VP8VP9Sorenson VideoAVS

          常见的音频编码有:AACMP3AC-3

          编码之后,还需要将音频和视频合并在一个文件里,这就是封装

          所以相对的,播放一个视频,就需要解封装,解码,音视频同步喂给声卡和显卡进行播放。

          MediaSource做的就是这个工作,读取视频流,转换成浏览器能播放的格式。

          以下是flv.jsparseChunks部分内容。读取buffer,一个字节一个字节的根据标准进行解析。然后转码。

          js
          if (byteStart === 0) {
          +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const t="/ran/assets/bilibili_video_code.DgWtgAEf.webp",p="/ran/assets/bili_demo_url.BQDGtHUp.webp",l="/ran/assets/bilibili_video_m4s.BccuY7bk.webp",k="/ran/assets/aqiyi_demo.s0swGzvF.webp",e="/ran/assets/tiktok_video.DuwKyIdt.webp",d="/ran/assets/tiktik_video_demo.mxxBzLay.webp",E="/ran/assets/red_book.DiBEvryP.webp",r="/ran/assets/safari_support_media.Bafr23bR.webp",g="/ran/assets/firefox_support_media.BLmSeBNy.webp",o="/ran/assets/ms_support.CaZSSiRt.webp",c="/ran/assets/ts_demo.D_l_mv9k.webp",y="/ran/assets/video_format.CRMCTmKB.webp",F="/ran/assets/xgplayer_docs.CpHb1Wan.webp",C="/ran/assets/bili_demo.CI8Ur8IA.webp",u="/ran/assets/rplayer_demo.CoJ7kuJt.webp",x=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/video.md","filePath":"cn/src/article/video.md","lastUpdated":1728921295000}'),B={name:"cn/src/article/video.md"};function m(A,s,b,v,D,f){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

          实现自适应码率 Web 视频加密播放:前后端的挑战与解决方案

          最近又遇到了web视频化的场景,之前也有过调研:H5 视频化调研浅析

          但这次稍微复杂一些,这次解决的是:

          1. 视频播放的技术方案调研

          服务端实现:

          1. 视频转码
          2. 生成不同码率的视频
          3. 进行视频标准加密
          4. 不同码率视频合并,用于动态码率播放

          web端实现

          1. web端播放器的设计
          2. web端播放器的自定义扩展
          3. 可拖拽进度条
          4. 音量控制
          5. 根据当前带宽自适应码率切换
          6. 手动清晰度切换
          7. 倍速播放
          8. 样式自定义覆盖
          9. 标准加密视频播放
          10. 基于原生开发,可在所有框架运行,统一跨框架情况
          11. 各浏览器控件统一

          其中web端源码已添加MIT协议并完全开源,如果看完对大家有帮助的话,欢迎大家star,issue,pr,也希望能友好交流~

          demo 地址:https://chaxus.github.io/ran/src/ranui/player/

          源码地址:https://github.com/chaxus/ran

          demo文档做了国际化,可切换到中文

          任何一个项目,立项肯定先是技术调研,我们先看看一些大公司的视频播放方案

          一:一些知名公司的 web 视频播放方案

          1.B 站

          我们先看看 B 站的,毕竟 B 站的主营业务就是视频弹幕网站,简直专业对口。

          先找一个例子:https://www.bilibili.com/video/BV1FM411N7LJ 访问它。

          image.png

          打开控制台,可以看到,视频在播放的时候,会不断的请求m4s的视频文件。

          毕竟一整个视频文件往往比较大,不可能先请求完视频文件,再进行播放。因此将一个大的视频文件分割成很多小的片段,边加载边播放,是一种更好的方式。

          image.png

          每次请求的m4s文件大概在几十kb到几百kb不等。

          image.png

          那为什么不采用httprange呢,可以请求一个文件的部分内容,而且粒度更细,可以设置字节范围。在http请求的header中,类似这样

          js
          Range: bytes = 3171375 - 3203867;

          我们可以检查这个链接请求https://upos-sz-mirror08c.bilivideo.com/upgcxcode/67/92/1008149267/1008149267-1-30064.m4s的请求头,就能发现,B 站采用的是,即分片加载,同时还用了range的方式。

          2. 爱奇艺:(爱奇艺、土豆、优酷)

          爱奇艺这里就不贴视频链接了,因为随便点一个视频,都要先看广告。

          image.png

          爱奇艺的视频主要请求的是f4v格式,也是分片加载。

          播放一个视频时,请求多个f4v文件。

          也采用Range。但和 B 站不一样的是,B 站的Range属性是在m4s请求的请求头里面,而爱奇艺的看起来是在querystring上,在请求query上带着range参数。

          因为没发现这个请求的header里面有range参数。比如:

          https://v-6fce1712.71edge.com/videos/other/20231113/6b/bb/3f3fe83b89124248c3216156dfe2f4c3.f4v?dis_k=2ba39ee8c55c4d23781e3fb9f91fa7a46&dis_t=1701439831&dis_dz=CNC-BeiJing&dis_st=46&src=iqiyi.com&dis_hit=0&dis_tag=01010000&uuid=72713f52-6569e957-351&cross-domain=1&ssl=1&pv=0.1&cphc=arta&range=0-9000

          3.抖音:

          抖音的方案简单粗暴,访问的链接是这个: https://m.ixigua.com/douyin/share/video/7206914252840370721?aweme_type=107&schema_type=1&utm_source=copy&utm_campaign=client_share&utm_medium=android&app=aweme

          通过查看控制台,我们可以发现,直接请求了一个视频的地址

          image.png

          没有进行分片,但用到了请求range,所以可以看到视频,是边播放边缓冲一部分。

          不过我在开发的时候发现,目前租用的服务云厂商,默认会帮我们实现这项技术。

          因为我把mp4视频上传到云服务器,通过链接进行播放的时候,就是边缓冲边播放的。

          我们可以直接把这个视频地址拿出来,放到浏览器里面能直接播放,这样观察更明显。

          image.png

          但 B 站和爱奇艺却不能这样,因为他们采用的m4sf4v都不是一种通用的视频格式,需要使用专门的软件或工具才能打开和编辑。

          4.小红书:

          测试用的例子链接:https://www.xiaohongshu.com/discovery/item/63b286d1000000001f00b495

          小红书的方案更加简单粗暴,打开控制台,直接告诉你就是请求一个mp4,然后直接播放就完事了。

          image.png

          5.总结

          看完了以上的各家大厂的方案,我们可以看到,基本原理都是边播放边加载,减少直接加载大视频文本的成本。并且通过分片传输,还能动态控制视频码率(清晰度)。做到根据网速,加载不同码率的分片文件,做到动态码率适应。

          同时采用的视频格式,比如f4vm4s,都不是能直接播放的媒体格式,需要一定的处理。增加盗取视频的成本,增加一定的安全性。

          如果没有强要求,也可以直接采用mp4,或者直接用video播放一个视频文件地址。

          二:常见的视频格式与协议

          我们知道视频的常见格式有mp4,同时上面介绍了 B 站播放用的m4s格式,爱奇艺用的f4v格式

          • 除了这些还有哪些视频格式?
          • 为什么有这么多视频格式,有哪些不同点呢?
          • 为什么这些公司会采用这种格式来播放视频呢?

          1. B 站用的m4s

          M4S格式不是一种通用的视频格式,需要使用专门的软件或工具才能打开和编辑。

          M4S 通常会和 MPEG-DASH 流媒体技术一起,通过流式传输的视频的一小部分。播放器会按接收顺序播放这些片段。第一个 M4S 段会包含一些初始化的数据标识。

          MPEG-DASH 是一种自适应比特率流媒体技术,通过将内容分解为一系列不同码率的M4S片段,然后根据当前网络带宽进行自动调整。如果想在在web音视频中采用DASH技术,可以看下 https://github.com/Dash-Industry-Forum/dash.js

          2. 爱奇艺的f4v

          F4V是一种流媒体格式,它是由Adobe公司推出的,继FLV格式之后支持H.264编码的流媒体格式。F4V格式的视频不是一种通用的视频格式,但通常情况下,都可以将文件后缀改为FLV,这样就可以使用支持FLV的播放器进行观看。

          FLV格式跟常见的MP4格式比起来,结构更加简单,所以加载metadata(视频元数据,比如视频时长等信息) 会更快。具体结构我们可以在这里查到:https://en.wikipedia.org/wiki/Flash_Video#Flash_Video_Structure

          比如,这是FLV文件的标准头,定义了从几个比特到几个比特之间,是什么含义。我们知道后,可以用MediaSource进行读取和转码。

          FieldData TypeDefaultDetails
          Signature 签名byte[3]"FLV"始终就是“FLV”
          Version 版本uint81只有 0x01 才有效
          Flags 标志uint8 位掩码0x050x04 是音频,0x01 是视频(所以 0x05 是音频 + 视频)
          Header Sizeuint32_be9用于跳过较新的扩展标头

          MP4格式会稍微复杂一些,具体标准在 ISO/IEC 14496-12 大概有两百多页,这里放不下,对这方面有兴趣的可以自行查看。

          然而这并不表示MP4更差,因为它是一种基础通用标准,所以定义上会留有很多空间,和各种情况,甚至允许在标准之内进行自行发挥和扩展。而FLV格式则更加固定,但优点也是更加简单。

          对于FLV的视频播放,我们可以采用:https://github.com/bilibili/flv.js flvjs主要作用就是用MediaSourceflv转码成mp4从而喂给浏览器进行播放。

          接下来是一些其他的视频格式,简单介绍一下:

          3.AVI

          文件名以.avi结尾,AVI 最初由 Microsoft1992 年开发,是 Windows 的标准视频格式。AVI 文件使用较少的压缩来存储文件,并且比许多其他视频格式占用更多空间,这导致文件大小非常大,每分钟视频大约 2-3 GB

          无损文件不会随着时间的推移而降低质量,无论您打开或保存文件多少次。此外,这允许在不使用任何编解码器的情况下播放。参考资料:Audio Video Interleave

          4.MPEG

          文件名以“.mpg”或“.mpeg”结尾,MPEG 是由 ISO 和 IEC 联合成立的工作组联盟,旨在制定媒体编码标准,包括音频、视频、图形和基因组数据的压缩编码;以及各种应用程序的传输和文件格式。MPEG 格式用于各种多媒体系统。最广为人知的旧 MPEG 媒体格式通常使用 MPEG-1、MPEG-2 和 MPEG-4 AVC 媒体编码,MPEG-2 系统传输流和节目流。较新的系统通常使用 MPEG 基本媒体文件格式和动态流式处理(又名 .MPEG-DASH)。参考资料:Moving Picture Experts Group

          5.MP4

          带有音频和视频的 MPEG-4 文件通常使用标准的 .mp4 扩展名。纯音频 MPEG-4 文件通常具有 .m4a 扩展名,原始 MPEG-4 可视比特流命名为 .m4v。Apple iPhone 使用 MPEG-4 音频作为其铃声,但使用.m4r 扩展名而不是.m4a 扩展名。参考资料:MPEG-4 Part 14

          6.QuickTime

          文件名以“.mov”结尾,QuickTime 能够包含媒体数据的抽象数据引用,并将媒体数据与媒体偏移和轨道编辑列表分离,这意味着 QuickTime 特别适合编辑,因为它能够就地导入和编辑(无需数据复制)。由于 QuickTime 和 MP4 容器格式都可以使用相同的 MPEG-4 格式,因此在仅限 QuickTime 的环境中,它们大多可以互换。MP4 作为国际标准,得到了更多的支持。参考资料:QuickTime File Format

          7.TS

          TS 是 MPEG2-TS 的简称,是一种音视频封装格式。TS 流的后缀通常是.ts、.mpg 或者.mpeg,多数播放器直接支持这种格式的播放。TS 格式主要用于直播的码流结构,具有很好的容错能力。

          三:浏览器对各种视频格式的兼容性

          上面了解常用的视频格式,和适用范围之后,还需要看一下当前浏览器,对各种视频格式的支持程度,然后制定技术方案。

          1. Chrome

          支持的视频格式从官方文档可以查到,主要有以下这些

          • MP4 (QuickTime/ MOV / ISO-BMFF / CMAF)
          • Ogg
          • WebM
          • WAV
          • HLS [Only on Android and only single-origin manifests]

          官方文档如下:https://www.chromium.org/audio-video/

          2. Safari

          支持的视频格式有这些:

          image.png

          官方文档:https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/Device-SpecificConsiderations/Device-SpecificConsiderations.html

          3.Firefox

          支持的视频格式:

          image.png

          官方文档:https://support.mozilla.org/en-US/kb/html5-audio-and-video-firefox

          四:MediaSource 和视频编码,解码,封装介绍

          上面介绍了一些视频格式,和目前浏览器的一些兼容性问题。就能发现,在web上播放音视频其实限制还是很大的。如何解决这些限制,就会用到MediaSource

          视频其实是无数个图片的叠加,如果视频是一秒60帧,大约一秒中需要播放60张图片。这就导致一个几分钟的视频,就会非常大。比如上面介绍的无损格式,avi格式,每分钟视频大约 2-3 GB。这时候视频就需要进行编码。其实就是压缩。

          编码分为视频编码和音频编码,常见的视频编码有:

          • MPEG 系列MPEG-1第二部分、MPEG-2第二部分(等同于H.262)、MPEG-4第二部分、MPEG-4第十部分(等同于H.264,有时候也被叫做“MPEG-4 AVC”或“H.264/AVC”)。
          • H.26x 系列H.261H.262H.263H.264(等同于MPEG-4第十部分)、H.265/HEVCITU-TISO/IEC联合推出)。
          • 其它视频编码WMV系列、RV系列、VC-1DivXXviDX264X265VP8VP9Sorenson VideoAVS

          常见的音频编码有:AACMP3AC-3

          编码之后,还需要将音频和视频合并在一个文件里,这就是封装

          所以相对的,播放一个视频,就需要解封装,解码,音视频同步喂给声卡和显卡进行播放。

          MediaSource做的就是这个工作,读取视频流,转换成浏览器能播放的格式。

          以下是flv.jsparseChunks部分内容。读取buffer,一个字节一个字节的根据标准进行解析。然后转码。

          js
          if (byteStart === 0) {
             // buffer with FLV header
             if (chunk.byteLength > 13) {
               let probeData = FLVDemuxer.probe(chunk);
          diff --git a/assets/cn_src_article_visual.md.Du_v00-A.js b/assets/cn_src_article_visual.md.BO64nAx5.js
          similarity index 99%
          rename from assets/cn_src_article_visual.md.Du_v00-A.js
          rename to assets/cn_src_article_visual.md.BO64nAx5.js
          index 129e67907f..f10c7e6859 100644
          --- a/assets/cn_src_article_visual.md.Du_v00-A.js
          +++ b/assets/cn_src_article_visual.md.BO64nAx5.js
          @@ -1,4 +1,4 @@
          -import{_ as h,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"实现曲线","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/visual.md","filePath":"cn/src/article/visual.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/visual.md"};function p(t,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          在业务需求的持续演进中,遇到了高度定制化图表的需求,为了寻求解决方案,我们首先寻找了一下目前的开源图表库。确实能解决大部分的场景。但在一些定制化设计就难以实现,但 UI 层的定制化又是十分常见的。

          为了完美的复现设计愿景,我们打算自己去实现绘制,然后就发现 canvas,webGL,webGPU 的 API 实在太过于底层。开发起来几乎像是命令式编程。能实现需求,但代码就非常不好维护。

          因此需要设计一个对于当前业务场景的绘制引擎。

          一 系统设计

          系统设计的过程中,我们需要明确使用场景,约束条件,边界情况。描述出最主要实现的功能,将这些功能进行高层级的设计,分类,链接。

          有了具体要实现的功能模块后,我们就再根据功能模块,深入细节,讨论具体的实现。

          功能实现后,通过可扩展的设计原则,将这些重要的功能进行链接。

          最后是一些业务场景的具体实现。

          一个通用的绘制设计引擎,主要需要考虑以下几个方面:

          1. **层级管理:**对于 2D 图形来说,必然需要层级关系的处理,定义元素之间的堆叠顺序,如确保文字总是绘制在图表的上方。层级管理将确保视觉呈现符合预期。
          2. **组的管理:**将多个图形元素组织成一个整体(即“组”)。这样的设计使得对组进行整体移动、缩放或变形时,组内所有元素都能响应,简化了复杂场景下的操作和管理。
          3. **变换矩阵:**对一个图形组执行平移、旋转、缩放等变形操作,从而以动态和灵活的方式调整图形的展示效果。为了实现这些变形操作,变形操作类通常会采用矩阵变换的原理。通过维护一个变换矩阵,并在绘制图形组之前应用该矩阵,可以一次性完成所有变形操作的计算,提高绘制效率。
          4. **事件系统:**允许用户将事件监听器绑定到单个图形元素或整个组上。实现用户交互(如点击、拖动)。
          5. **应用层封装:**构建丰富的基础图形类库,提供便捷的 API 来绘制常见的几何形状,如矩形、圆形、多边形、曲线等。这些基础图形应支持自定义样式和属性,以满足多样化的设计需求。
          6. **扩展设计:**明确整个渲染过程的生命周期,并且允许开发者在对应的生命周期中插入自定义的代码,从而实现对渲染流程,事件处理,资源控制等方面的控制。

          在应用层,我们需要封装绘制引擎提供的底层功能,使其更加贴近业务需求。这包括提供易于使用的 API 接口、优化性能、处理异常和错误等。同时,通过持续的应用层反馈,不断优化和调整绘制引擎,确保其能够更好地服务于业务的发展。

          因此,在绘制引擎架构中,我们会首先实现一个节点类 Vertex,这个类代表了最原始的‘节点’的概念,所有可以被展示到 canvas 画布上的、各种类型的节点都会继承于这个类,这是一个抽象类,我们并不会直接实例化这个类。

          这个类上面挂载了‘节点’的各种通用属性,比如:父元素、透明度、旋转角度、缩放、平移、节点是否可见等。

          ts

          为了进行图形组的管理,会继续实现一个容器类 Container,这个类代表了‘组’的概念,它提供了添加子元素,移除子元素等的方法;后续的要被渲染的一些类 (如 Graphics,Text,Sprite 等) 会继承于这个类;这个类本身不会被渲染 (因为它只是一个‘组’,它本身没有内容可以渲染)。

          这个类继承于 Vertex 类,‘组’也算作‘节点’。

          Graphics 这个类会用来构建一些几何图形元素;它会继承 Container 类。

          在渲染引擎中,一切变换 (平移、旋转、缩放等) 都会转化成变换矩阵 (matrix),因为 canvas 只接受矩阵变换,虽然 canvas 为了开发的便捷,也提供了 ctx.rotate,ctx.scale 等操作,但是 canvas 中的这些操作会直接转换成变换矩阵,而不像 DOM 那样,有锚点的概念,所以 canvas 提供的 rotate,scale 等操作,和 DOM 提供的 rotate,scale 的表现是不一样的。

          Matrix 类将会提供各种各样的与矩阵操作相关的函数 (矩阵相乘,矩阵求逆等),任何变换的叠加都将会转换成 matrix,方便我们调用 canvas 的指令。

          Transform 类就类似 CSS 的 transform,它提供了一些更清晰、更符合人类直觉的变换,而不用直接使用矩阵变换,当然,这些变换最终会转换成矩阵变换。

          线性变换从几何直观有三个要点:

          • 变换前是直线的,变换后依然是直线
          • 直线比例保持不变
          • 变换前是原点的,变换后依然是原点

          比如有一个二维基向量

          ',23),s("r-math",{latex:"\\left[\\begin{matrix}x & 0 \\\\0 & y \\\\ \\end{matrix}\\right]"},null,-1),s("p",null,"旋转矩阵:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} cos(r) & -sin(r) \\\\ sin(r) & cos(r) \\\\ \\end{matrix} \\right]"},null,-1),s("p",null,"浏览器的 skew:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} 1 & tan(x) \\\\ tan(y) & 1 \\\\ \\end{matrix} \\right]"},null,-1),s("p",null,"pixijs 的 skew:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} cos(y) & sin(x) \\\\ sin(y) & cos(x) \\\\ \\end{matrix} \\right]"},null,-1),i('

          平移操作:

          这里就需要仿射变换

          仿射变换从几何直观只有两个要点:

          • 变换前是直线的,变换后依然是直线
          • 直线比例保持不变

          少了原点保持不变这一条。

          因此,平移不再是线性变化了,而是仿射变化。

          每一个矩阵变换都是线性变换,反正则不成立。

          仿射变换不能光通过矩阵乘法来实现,还得有加法。

          主要用途是,通过高纬度的线性变换,模拟低维度的仿射变换。从而把平移操作也数据化。

          实现曲线

          二阶贝塞尔曲线

          ',11),s("r-math",{latex:"B(t) = (1-t)^2 \\mathbf{P_0} + 2t(1-t) \\mathbf{P_1} + t^2 \\mathbf{P_2}, \\quad t \\in [0, 1]"},null,-1),i(`

          起点(P0):这是曲线开始的位置。在绘制过程中,曲线会精确地通过这个点。 控制点(P1):这个点是用来控制曲线形状和弯曲程度的。它不一定在曲线上,但会对曲线的走向产生重要影响。通过调整控制点的位置,可以改变曲线的弯曲程度和方向。 终点(P2):这是曲线结束的位置。同样地,曲线也会精确地通过这个点。

          二 基础图形库:

          常见的基础图形有:

          1. 椭圆
          2. 多边形
          3. 矩形
          4. 圆角矩形

          先实现一个基础类,然后其他的所有图形类都继承这个抽象类:

          ts
          export abstract class Shape {
          +import{_ as h,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"实现曲线","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/visual.md","filePath":"cn/src/article/visual.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/visual.md"};function p(t,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          在业务需求的持续演进中,遇到了高度定制化图表的需求,为了寻求解决方案,我们首先寻找了一下目前的开源图表库。确实能解决大部分的场景。但在一些定制化设计就难以实现,但 UI 层的定制化又是十分常见的。

          为了完美的复现设计愿景,我们打算自己去实现绘制,然后就发现 canvas,webGL,webGPU 的 API 实在太过于底层。开发起来几乎像是命令式编程。能实现需求,但代码就非常不好维护。

          因此需要设计一个对于当前业务场景的绘制引擎。

          一 系统设计

          系统设计的过程中,我们需要明确使用场景,约束条件,边界情况。描述出最主要实现的功能,将这些功能进行高层级的设计,分类,链接。

          有了具体要实现的功能模块后,我们就再根据功能模块,深入细节,讨论具体的实现。

          功能实现后,通过可扩展的设计原则,将这些重要的功能进行链接。

          最后是一些业务场景的具体实现。

          一个通用的绘制设计引擎,主要需要考虑以下几个方面:

          1. **层级管理:**对于 2D 图形来说,必然需要层级关系的处理,定义元素之间的堆叠顺序,如确保文字总是绘制在图表的上方。层级管理将确保视觉呈现符合预期。
          2. **组的管理:**将多个图形元素组织成一个整体(即“组”)。这样的设计使得对组进行整体移动、缩放或变形时,组内所有元素都能响应,简化了复杂场景下的操作和管理。
          3. **变换矩阵:**对一个图形组执行平移、旋转、缩放等变形操作,从而以动态和灵活的方式调整图形的展示效果。为了实现这些变形操作,变形操作类通常会采用矩阵变换的原理。通过维护一个变换矩阵,并在绘制图形组之前应用该矩阵,可以一次性完成所有变形操作的计算,提高绘制效率。
          4. **事件系统:**允许用户将事件监听器绑定到单个图形元素或整个组上。实现用户交互(如点击、拖动)。
          5. **应用层封装:**构建丰富的基础图形类库,提供便捷的 API 来绘制常见的几何形状,如矩形、圆形、多边形、曲线等。这些基础图形应支持自定义样式和属性,以满足多样化的设计需求。
          6. **扩展设计:**明确整个渲染过程的生命周期,并且允许开发者在对应的生命周期中插入自定义的代码,从而实现对渲染流程,事件处理,资源控制等方面的控制。

          在应用层,我们需要封装绘制引擎提供的底层功能,使其更加贴近业务需求。这包括提供易于使用的 API 接口、优化性能、处理异常和错误等。同时,通过持续的应用层反馈,不断优化和调整绘制引擎,确保其能够更好地服务于业务的发展。

          因此,在绘制引擎架构中,我们会首先实现一个节点类 Vertex,这个类代表了最原始的‘节点’的概念,所有可以被展示到 canvas 画布上的、各种类型的节点都会继承于这个类,这是一个抽象类,我们并不会直接实例化这个类。

          这个类上面挂载了‘节点’的各种通用属性,比如:父元素、透明度、旋转角度、缩放、平移、节点是否可见等。

          ts

          为了进行图形组的管理,会继续实现一个容器类 Container,这个类代表了‘组’的概念,它提供了添加子元素,移除子元素等的方法;后续的要被渲染的一些类 (如 Graphics,Text,Sprite 等) 会继承于这个类;这个类本身不会被渲染 (因为它只是一个‘组’,它本身没有内容可以渲染)。

          这个类继承于 Vertex 类,‘组’也算作‘节点’。

          Graphics 这个类会用来构建一些几何图形元素;它会继承 Container 类。

          在渲染引擎中,一切变换 (平移、旋转、缩放等) 都会转化成变换矩阵 (matrix),因为 canvas 只接受矩阵变换,虽然 canvas 为了开发的便捷,也提供了 ctx.rotate,ctx.scale 等操作,但是 canvas 中的这些操作会直接转换成变换矩阵,而不像 DOM 那样,有锚点的概念,所以 canvas 提供的 rotate,scale 等操作,和 DOM 提供的 rotate,scale 的表现是不一样的。

          Matrix 类将会提供各种各样的与矩阵操作相关的函数 (矩阵相乘,矩阵求逆等),任何变换的叠加都将会转换成 matrix,方便我们调用 canvas 的指令。

          Transform 类就类似 CSS 的 transform,它提供了一些更清晰、更符合人类直觉的变换,而不用直接使用矩阵变换,当然,这些变换最终会转换成矩阵变换。

          线性变换从几何直观有三个要点:

          • 变换前是直线的,变换后依然是直线
          • 直线比例保持不变
          • 变换前是原点的,变换后依然是原点

          比如有一个二维基向量

          ',23),s("r-math",{latex:"\\left[\\begin{matrix}x & 0 \\\\0 & y \\\\ \\end{matrix}\\right]"},null,-1),s("p",null,"旋转矩阵:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} cos(r) & -sin(r) \\\\ sin(r) & cos(r) \\\\ \\end{matrix} \\right]"},null,-1),s("p",null,"浏览器的 skew:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} 1 & tan(x) \\\\ tan(y) & 1 \\\\ \\end{matrix} \\right]"},null,-1),s("p",null,"pixijs 的 skew:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} cos(y) & sin(x) \\\\ sin(y) & cos(x) \\\\ \\end{matrix} \\right]"},null,-1),i('

          平移操作:

          这里就需要仿射变换

          仿射变换从几何直观只有两个要点:

          • 变换前是直线的,变换后依然是直线
          • 直线比例保持不变

          少了原点保持不变这一条。

          因此,平移不再是线性变化了,而是仿射变化。

          每一个矩阵变换都是线性变换,反正则不成立。

          仿射变换不能光通过矩阵乘法来实现,还得有加法。

          主要用途是,通过高纬度的线性变换,模拟低维度的仿射变换。从而把平移操作也数据化。

          实现曲线

          二阶贝塞尔曲线

          ',11),s("r-math",{latex:"B(t) = (1-t)^2 \\mathbf{P_0} + 2t(1-t) \\mathbf{P_1} + t^2 \\mathbf{P_2}, \\quad t \\in [0, 1]"},null,-1),i(`

          起点(P0):这是曲线开始的位置。在绘制过程中,曲线会精确地通过这个点。 控制点(P1):这个点是用来控制曲线形状和弯曲程度的。它不一定在曲线上,但会对曲线的走向产生重要影响。通过调整控制点的位置,可以改变曲线的弯曲程度和方向。 终点(P2):这是曲线结束的位置。同样地,曲线也会精确地通过这个点。

          二 基础图形库:

          常见的基础图形有:

          1. 椭圆
          2. 多边形
          3. 矩形
          4. 圆角矩形

          先实现一个基础类,然后其他的所有图形类都继承这个抽象类:

          ts
          export abstract class Shape {
             // 支持的所有几何图形都会继承自这个 Shape 基类
             public abstract type: ShapeType;
             constructor() {}
          diff --git a/assets/cn_src_article_visual.md.Du_v00-A.lean.js b/assets/cn_src_article_visual.md.BO64nAx5.lean.js
          similarity index 99%
          rename from assets/cn_src_article_visual.md.Du_v00-A.lean.js
          rename to assets/cn_src_article_visual.md.BO64nAx5.lean.js
          index 129e67907f..f10c7e6859 100644
          --- a/assets/cn_src_article_visual.md.Du_v00-A.lean.js
          +++ b/assets/cn_src_article_visual.md.BO64nAx5.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as h,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"实现曲线","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/visual.md","filePath":"cn/src/article/visual.md","lastUpdated":1728828157000}'),k={name:"cn/src/article/visual.md"};function p(t,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          在业务需求的持续演进中,遇到了高度定制化图表的需求,为了寻求解决方案,我们首先寻找了一下目前的开源图表库。确实能解决大部分的场景。但在一些定制化设计就难以实现,但 UI 层的定制化又是十分常见的。

          为了完美的复现设计愿景,我们打算自己去实现绘制,然后就发现 canvas,webGL,webGPU 的 API 实在太过于底层。开发起来几乎像是命令式编程。能实现需求,但代码就非常不好维护。

          因此需要设计一个对于当前业务场景的绘制引擎。

          一 系统设计

          系统设计的过程中,我们需要明确使用场景,约束条件,边界情况。描述出最主要实现的功能,将这些功能进行高层级的设计,分类,链接。

          有了具体要实现的功能模块后,我们就再根据功能模块,深入细节,讨论具体的实现。

          功能实现后,通过可扩展的设计原则,将这些重要的功能进行链接。

          最后是一些业务场景的具体实现。

          一个通用的绘制设计引擎,主要需要考虑以下几个方面:

          1. **层级管理:**对于 2D 图形来说,必然需要层级关系的处理,定义元素之间的堆叠顺序,如确保文字总是绘制在图表的上方。层级管理将确保视觉呈现符合预期。
          2. **组的管理:**将多个图形元素组织成一个整体(即“组”)。这样的设计使得对组进行整体移动、缩放或变形时,组内所有元素都能响应,简化了复杂场景下的操作和管理。
          3. **变换矩阵:**对一个图形组执行平移、旋转、缩放等变形操作,从而以动态和灵活的方式调整图形的展示效果。为了实现这些变形操作,变形操作类通常会采用矩阵变换的原理。通过维护一个变换矩阵,并在绘制图形组之前应用该矩阵,可以一次性完成所有变形操作的计算,提高绘制效率。
          4. **事件系统:**允许用户将事件监听器绑定到单个图形元素或整个组上。实现用户交互(如点击、拖动)。
          5. **应用层封装:**构建丰富的基础图形类库,提供便捷的 API 来绘制常见的几何形状,如矩形、圆形、多边形、曲线等。这些基础图形应支持自定义样式和属性,以满足多样化的设计需求。
          6. **扩展设计:**明确整个渲染过程的生命周期,并且允许开发者在对应的生命周期中插入自定义的代码,从而实现对渲染流程,事件处理,资源控制等方面的控制。

          在应用层,我们需要封装绘制引擎提供的底层功能,使其更加贴近业务需求。这包括提供易于使用的 API 接口、优化性能、处理异常和错误等。同时,通过持续的应用层反馈,不断优化和调整绘制引擎,确保其能够更好地服务于业务的发展。

          因此,在绘制引擎架构中,我们会首先实现一个节点类 Vertex,这个类代表了最原始的‘节点’的概念,所有可以被展示到 canvas 画布上的、各种类型的节点都会继承于这个类,这是一个抽象类,我们并不会直接实例化这个类。

          这个类上面挂载了‘节点’的各种通用属性,比如:父元素、透明度、旋转角度、缩放、平移、节点是否可见等。

          ts

          为了进行图形组的管理,会继续实现一个容器类 Container,这个类代表了‘组’的概念,它提供了添加子元素,移除子元素等的方法;后续的要被渲染的一些类 (如 Graphics,Text,Sprite 等) 会继承于这个类;这个类本身不会被渲染 (因为它只是一个‘组’,它本身没有内容可以渲染)。

          这个类继承于 Vertex 类,‘组’也算作‘节点’。

          Graphics 这个类会用来构建一些几何图形元素;它会继承 Container 类。

          在渲染引擎中,一切变换 (平移、旋转、缩放等) 都会转化成变换矩阵 (matrix),因为 canvas 只接受矩阵变换,虽然 canvas 为了开发的便捷,也提供了 ctx.rotate,ctx.scale 等操作,但是 canvas 中的这些操作会直接转换成变换矩阵,而不像 DOM 那样,有锚点的概念,所以 canvas 提供的 rotate,scale 等操作,和 DOM 提供的 rotate,scale 的表现是不一样的。

          Matrix 类将会提供各种各样的与矩阵操作相关的函数 (矩阵相乘,矩阵求逆等),任何变换的叠加都将会转换成 matrix,方便我们调用 canvas 的指令。

          Transform 类就类似 CSS 的 transform,它提供了一些更清晰、更符合人类直觉的变换,而不用直接使用矩阵变换,当然,这些变换最终会转换成矩阵变换。

          线性变换从几何直观有三个要点:

          • 变换前是直线的,变换后依然是直线
          • 直线比例保持不变
          • 变换前是原点的,变换后依然是原点

          比如有一个二维基向量

          ',23),s("r-math",{latex:"\\left[\\begin{matrix}x & 0 \\\\0 & y \\\\ \\end{matrix}\\right]"},null,-1),s("p",null,"旋转矩阵:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} cos(r) & -sin(r) \\\\ sin(r) & cos(r) \\\\ \\end{matrix} \\right]"},null,-1),s("p",null,"浏览器的 skew:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} 1 & tan(x) \\\\ tan(y) & 1 \\\\ \\end{matrix} \\right]"},null,-1),s("p",null,"pixijs 的 skew:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} cos(y) & sin(x) \\\\ sin(y) & cos(x) \\\\ \\end{matrix} \\right]"},null,-1),i('

          平移操作:

          这里就需要仿射变换

          仿射变换从几何直观只有两个要点:

          • 变换前是直线的,变换后依然是直线
          • 直线比例保持不变

          少了原点保持不变这一条。

          因此,平移不再是线性变化了,而是仿射变化。

          每一个矩阵变换都是线性变换,反正则不成立。

          仿射变换不能光通过矩阵乘法来实现,还得有加法。

          主要用途是,通过高纬度的线性变换,模拟低维度的仿射变换。从而把平移操作也数据化。

          实现曲线

          二阶贝塞尔曲线

          ',11),s("r-math",{latex:"B(t) = (1-t)^2 \\mathbf{P_0} + 2t(1-t) \\mathbf{P_1} + t^2 \\mathbf{P_2}, \\quad t \\in [0, 1]"},null,-1),i(`

          起点(P0):这是曲线开始的位置。在绘制过程中,曲线会精确地通过这个点。 控制点(P1):这个点是用来控制曲线形状和弯曲程度的。它不一定在曲线上,但会对曲线的走向产生重要影响。通过调整控制点的位置,可以改变曲线的弯曲程度和方向。 终点(P2):这是曲线结束的位置。同样地,曲线也会精确地通过这个点。

          二 基础图形库:

          常见的基础图形有:

          1. 椭圆
          2. 多边形
          3. 矩形
          4. 圆角矩形

          先实现一个基础类,然后其他的所有图形类都继承这个抽象类:

          ts
          export abstract class Shape {
          +import{_ as h,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"实现曲线","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/article/visual.md","filePath":"cn/src/article/visual.md","lastUpdated":1728921295000}'),k={name:"cn/src/article/visual.md"};function p(t,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          在业务需求的持续演进中,遇到了高度定制化图表的需求,为了寻求解决方案,我们首先寻找了一下目前的开源图表库。确实能解决大部分的场景。但在一些定制化设计就难以实现,但 UI 层的定制化又是十分常见的。

          为了完美的复现设计愿景,我们打算自己去实现绘制,然后就发现 canvas,webGL,webGPU 的 API 实在太过于底层。开发起来几乎像是命令式编程。能实现需求,但代码就非常不好维护。

          因此需要设计一个对于当前业务场景的绘制引擎。

          一 系统设计

          系统设计的过程中,我们需要明确使用场景,约束条件,边界情况。描述出最主要实现的功能,将这些功能进行高层级的设计,分类,链接。

          有了具体要实现的功能模块后,我们就再根据功能模块,深入细节,讨论具体的实现。

          功能实现后,通过可扩展的设计原则,将这些重要的功能进行链接。

          最后是一些业务场景的具体实现。

          一个通用的绘制设计引擎,主要需要考虑以下几个方面:

          1. **层级管理:**对于 2D 图形来说,必然需要层级关系的处理,定义元素之间的堆叠顺序,如确保文字总是绘制在图表的上方。层级管理将确保视觉呈现符合预期。
          2. **组的管理:**将多个图形元素组织成一个整体(即“组”)。这样的设计使得对组进行整体移动、缩放或变形时,组内所有元素都能响应,简化了复杂场景下的操作和管理。
          3. **变换矩阵:**对一个图形组执行平移、旋转、缩放等变形操作,从而以动态和灵活的方式调整图形的展示效果。为了实现这些变形操作,变形操作类通常会采用矩阵变换的原理。通过维护一个变换矩阵,并在绘制图形组之前应用该矩阵,可以一次性完成所有变形操作的计算,提高绘制效率。
          4. **事件系统:**允许用户将事件监听器绑定到单个图形元素或整个组上。实现用户交互(如点击、拖动)。
          5. **应用层封装:**构建丰富的基础图形类库,提供便捷的 API 来绘制常见的几何形状,如矩形、圆形、多边形、曲线等。这些基础图形应支持自定义样式和属性,以满足多样化的设计需求。
          6. **扩展设计:**明确整个渲染过程的生命周期,并且允许开发者在对应的生命周期中插入自定义的代码,从而实现对渲染流程,事件处理,资源控制等方面的控制。

          在应用层,我们需要封装绘制引擎提供的底层功能,使其更加贴近业务需求。这包括提供易于使用的 API 接口、优化性能、处理异常和错误等。同时,通过持续的应用层反馈,不断优化和调整绘制引擎,确保其能够更好地服务于业务的发展。

          因此,在绘制引擎架构中,我们会首先实现一个节点类 Vertex,这个类代表了最原始的‘节点’的概念,所有可以被展示到 canvas 画布上的、各种类型的节点都会继承于这个类,这是一个抽象类,我们并不会直接实例化这个类。

          这个类上面挂载了‘节点’的各种通用属性,比如:父元素、透明度、旋转角度、缩放、平移、节点是否可见等。

          ts

          为了进行图形组的管理,会继续实现一个容器类 Container,这个类代表了‘组’的概念,它提供了添加子元素,移除子元素等的方法;后续的要被渲染的一些类 (如 Graphics,Text,Sprite 等) 会继承于这个类;这个类本身不会被渲染 (因为它只是一个‘组’,它本身没有内容可以渲染)。

          这个类继承于 Vertex 类,‘组’也算作‘节点’。

          Graphics 这个类会用来构建一些几何图形元素;它会继承 Container 类。

          在渲染引擎中,一切变换 (平移、旋转、缩放等) 都会转化成变换矩阵 (matrix),因为 canvas 只接受矩阵变换,虽然 canvas 为了开发的便捷,也提供了 ctx.rotate,ctx.scale 等操作,但是 canvas 中的这些操作会直接转换成变换矩阵,而不像 DOM 那样,有锚点的概念,所以 canvas 提供的 rotate,scale 等操作,和 DOM 提供的 rotate,scale 的表现是不一样的。

          Matrix 类将会提供各种各样的与矩阵操作相关的函数 (矩阵相乘,矩阵求逆等),任何变换的叠加都将会转换成 matrix,方便我们调用 canvas 的指令。

          Transform 类就类似 CSS 的 transform,它提供了一些更清晰、更符合人类直觉的变换,而不用直接使用矩阵变换,当然,这些变换最终会转换成矩阵变换。

          线性变换从几何直观有三个要点:

          • 变换前是直线的,变换后依然是直线
          • 直线比例保持不变
          • 变换前是原点的,变换后依然是原点

          比如有一个二维基向量

          ',23),s("r-math",{latex:"\\left[\\begin{matrix}x & 0 \\\\0 & y \\\\ \\end{matrix}\\right]"},null,-1),s("p",null,"旋转矩阵:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} cos(r) & -sin(r) \\\\ sin(r) & cos(r) \\\\ \\end{matrix} \\right]"},null,-1),s("p",null,"浏览器的 skew:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} 1 & tan(x) \\\\ tan(y) & 1 \\\\ \\end{matrix} \\right]"},null,-1),s("p",null,"pixijs 的 skew:",-1),s("r-math",{latex:"\\left[ \\begin{matrix} cos(y) & sin(x) \\\\ sin(y) & cos(x) \\\\ \\end{matrix} \\right]"},null,-1),i('

          平移操作:

          这里就需要仿射变换

          仿射变换从几何直观只有两个要点:

          • 变换前是直线的,变换后依然是直线
          • 直线比例保持不变

          少了原点保持不变这一条。

          因此,平移不再是线性变化了,而是仿射变化。

          每一个矩阵变换都是线性变换,反正则不成立。

          仿射变换不能光通过矩阵乘法来实现,还得有加法。

          主要用途是,通过高纬度的线性变换,模拟低维度的仿射变换。从而把平移操作也数据化。

          实现曲线

          二阶贝塞尔曲线

          ',11),s("r-math",{latex:"B(t) = (1-t)^2 \\mathbf{P_0} + 2t(1-t) \\mathbf{P_1} + t^2 \\mathbf{P_2}, \\quad t \\in [0, 1]"},null,-1),i(`

          起点(P0):这是曲线开始的位置。在绘制过程中,曲线会精确地通过这个点。 控制点(P1):这个点是用来控制曲线形状和弯曲程度的。它不一定在曲线上,但会对曲线的走向产生重要影响。通过调整控制点的位置,可以改变曲线的弯曲程度和方向。 终点(P2):这是曲线结束的位置。同样地,曲线也会精确地通过这个点。

          二 基础图形库:

          常见的基础图形有:

          1. 椭圆
          2. 多边形
          3. 矩形
          4. 圆角矩形

          先实现一个基础类,然后其他的所有图形类都继承这个抽象类:

          ts
          export abstract class Shape {
             // 支持的所有几何图形都会继承自这个 Shape 基类
             public abstract type: ShapeType;
             constructor() {}
          diff --git a/assets/cn_src_note_centos.md.CQEnE6Ac.js b/assets/cn_src_note_centos.md.DNrgG0Q4.js
          similarity index 99%
          rename from assets/cn_src_note_centos.md.CQEnE6Ac.js
          rename to assets/cn_src_note_centos.md.DNrgG0Q4.js
          index 18f79cb07e..fc4abeed91 100644
          --- a/assets/cn_src_note_centos.md.CQEnE6Ac.js
          +++ b/assets/cn_src_note_centos.md.DNrgG0Q4.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as e}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CentOS","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/centos.md","filePath":"cn/src/note/centos.md","lastUpdated":1728828157000}'),t={name:"cn/src/note/centos.md"};function p(l,s,h,k,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

          CentOS

          查看当前系统的版本:

          sh
          cat /etc/centos-release

          YUM

          YUM 是 Yellowdog Updater, Modified 的缩写,虽然不是 CentOS 开发的,但已成为 CentOS 系统中常用的包管理工具。YUM 作为 RPM 的前端程序,解决了 RPM 软件包之间的依赖性问题,并提供了更加便捷的软件包管理方式。

          YUM 仓库源

          CentOS 8 的官方支持已经结束,但您仍然可以使用 CentOS Stream 8 或其他第三方仓库。如果您正在使用 CentOS 8,并且希望继续使用类似的仓库,可以考虑切换到 CentOS Stream 8。

          1.替换镜像源

          由于众所周知的原因,访问官方镜像会非常慢,所以

          修改 /etc/yum.repos.d/CentOS-AppStream.repo 文件(或相应的仓库配置文件),将 baseurl 或 mirrorlist 指向一个可用的源。

          我个人尝试,发现需要修改三个文件:

          sh
          /etc/yum.repos.d/CentOS-Base.repo
          +import{_ as i,o as a,c as n,a3 as e}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CentOS","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/centos.md","filePath":"cn/src/note/centos.md","lastUpdated":1728921295000}'),t={name:"cn/src/note/centos.md"};function p(l,s,h,k,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

          CentOS

          查看当前系统的版本:

          sh
          cat /etc/centos-release

          YUM

          YUM 是 Yellowdog Updater, Modified 的缩写,虽然不是 CentOS 开发的,但已成为 CentOS 系统中常用的包管理工具。YUM 作为 RPM 的前端程序,解决了 RPM 软件包之间的依赖性问题,并提供了更加便捷的软件包管理方式。

          YUM 仓库源

          CentOS 8 的官方支持已经结束,但您仍然可以使用 CentOS Stream 8 或其他第三方仓库。如果您正在使用 CentOS 8,并且希望继续使用类似的仓库,可以考虑切换到 CentOS Stream 8。

          1.替换镜像源

          由于众所周知的原因,访问官方镜像会非常慢,所以

          修改 /etc/yum.repos.d/CentOS-AppStream.repo 文件(或相应的仓库配置文件),将 baseurl 或 mirrorlist 指向一个可用的源。

          我个人尝试,发现需要修改三个文件:

          sh
          /etc/yum.repos.d/CentOS-Base.repo
           /etc/yum.repos.d/CentOS-AppStream.repo
           /etc/yum.repos.d/CentOS-Extras.repo

          修改文件内容:

          sh
          [baseos]
           name=CentOS-8 - Base
          diff --git a/assets/cn_src_note_centos.md.CQEnE6Ac.lean.js b/assets/cn_src_note_centos.md.DNrgG0Q4.lean.js
          similarity index 99%
          rename from assets/cn_src_note_centos.md.CQEnE6Ac.lean.js
          rename to assets/cn_src_note_centos.md.DNrgG0Q4.lean.js
          index 18f79cb07e..fc4abeed91 100644
          --- a/assets/cn_src_note_centos.md.CQEnE6Ac.lean.js
          +++ b/assets/cn_src_note_centos.md.DNrgG0Q4.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as e}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CentOS","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/centos.md","filePath":"cn/src/note/centos.md","lastUpdated":1728828157000}'),t={name:"cn/src/note/centos.md"};function p(l,s,h,k,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

          CentOS

          查看当前系统的版本:

          sh
          cat /etc/centos-release

          YUM

          YUM 是 Yellowdog Updater, Modified 的缩写,虽然不是 CentOS 开发的,但已成为 CentOS 系统中常用的包管理工具。YUM 作为 RPM 的前端程序,解决了 RPM 软件包之间的依赖性问题,并提供了更加便捷的软件包管理方式。

          YUM 仓库源

          CentOS 8 的官方支持已经结束,但您仍然可以使用 CentOS Stream 8 或其他第三方仓库。如果您正在使用 CentOS 8,并且希望继续使用类似的仓库,可以考虑切换到 CentOS Stream 8。

          1.替换镜像源

          由于众所周知的原因,访问官方镜像会非常慢,所以

          修改 /etc/yum.repos.d/CentOS-AppStream.repo 文件(或相应的仓库配置文件),将 baseurl 或 mirrorlist 指向一个可用的源。

          我个人尝试,发现需要修改三个文件:

          sh
          /etc/yum.repos.d/CentOS-Base.repo
          +import{_ as i,o as a,c as n,a3 as e}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CentOS","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/centos.md","filePath":"cn/src/note/centos.md","lastUpdated":1728921295000}'),t={name:"cn/src/note/centos.md"};function p(l,s,h,k,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

          CentOS

          查看当前系统的版本:

          sh
          cat /etc/centos-release

          YUM

          YUM 是 Yellowdog Updater, Modified 的缩写,虽然不是 CentOS 开发的,但已成为 CentOS 系统中常用的包管理工具。YUM 作为 RPM 的前端程序,解决了 RPM 软件包之间的依赖性问题,并提供了更加便捷的软件包管理方式。

          YUM 仓库源

          CentOS 8 的官方支持已经结束,但您仍然可以使用 CentOS Stream 8 或其他第三方仓库。如果您正在使用 CentOS 8,并且希望继续使用类似的仓库,可以考虑切换到 CentOS Stream 8。

          1.替换镜像源

          由于众所周知的原因,访问官方镜像会非常慢,所以

          修改 /etc/yum.repos.d/CentOS-AppStream.repo 文件(或相应的仓库配置文件),将 baseurl 或 mirrorlist 指向一个可用的源。

          我个人尝试,发现需要修改三个文件:

          sh
          /etc/yum.repos.d/CentOS-Base.repo
           /etc/yum.repos.d/CentOS-AppStream.repo
           /etc/yum.repos.d/CentOS-Extras.repo

          修改文件内容:

          sh
          [baseos]
           name=CentOS-8 - Base
          diff --git a/assets/cn_src_note_docker.md.Cdo71zW_.js b/assets/cn_src_note_docker.md.tDnzoB7w.js
          similarity index 99%
          rename from assets/cn_src_note_docker.md.Cdo71zW_.js
          rename to assets/cn_src_note_docker.md.tDnzoB7w.js
          index 8acb238d2c..f6c352cd94 100644
          --- a/assets/cn_src_note_docker.md.Cdo71zW_.js
          +++ b/assets/cn_src_note_docker.md.tDnzoB7w.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as e,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"docker","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/docker.md","filePath":"cn/src/note/docker.md","lastUpdated":1728828157000}'),n={name:"cn/src/note/docker.md"};function h(t,s,p,k,d,r){return a(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l(`

          docker

          查询 docker 是否在运行:

          1. 输入以下命令来查找 Docker 守护进程的 PID(进程 ID):
          sh
          ps -ef | grep docker

          如果命令返回了包含/usr/local/bin/dockerd(或类似路径)的行,并且 PID 列有数字显示,那么 Docker 守护进程正在运行。

          1. 使用 docker ps 命令

          虽然 docker ps 命令主要用于列出正在运行的容器,但如果 Docker 服务没有运行,该命令会返回一个错误消息。因此,你也可以通过运行该命令并观察输出来判断 Docker 服务是否启动。

          如果 Docker 服务正在运行,该命令将列出所有正在运行的容器(如果没有运行的容器,则可能只显示表头)。如果 Docker 服务没有运行,你将看到一个错误消息,如“Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?”

          1. 使用 docker info 命令

          docker info 命令提供 Docker 系统的详细信息,包括容器数量、镜像数量、Docker 版本等。如果 Docker 服务正在运行,该命令将正常输出这些信息。

          如果 Docker 服务正在运行,你将看到一系列关于 Docker 系统的信息。如果 Docker 服务没有运行,你将看到一个错误消息,与 docker ps 命令类似。

          安装 docker 的网站:https://hub.docker.com/

          images

          Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作容器的模板。Docker 根据 image 文件生成的容器实例。同一个 image 文件,可以生成多个同时运行的容器实例

          image 是二进制文件。实际开发过程中,一个 image 文件往往通过继承另一个 image 文件,再加上一些个性化的设置而成。

          shell
          # 搜索镜像
          +import{_ as i,o as a,c as e,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"docker","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/docker.md","filePath":"cn/src/note/docker.md","lastUpdated":1728921295000}'),n={name:"cn/src/note/docker.md"};function h(t,s,p,k,d,r){return a(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l(`

          docker

          查询 docker 是否在运行:

          1. 输入以下命令来查找 Docker 守护进程的 PID(进程 ID):
          sh
          ps -ef | grep docker

          如果命令返回了包含/usr/local/bin/dockerd(或类似路径)的行,并且 PID 列有数字显示,那么 Docker 守护进程正在运行。

          1. 使用 docker ps 命令

          虽然 docker ps 命令主要用于列出正在运行的容器,但如果 Docker 服务没有运行,该命令会返回一个错误消息。因此,你也可以通过运行该命令并观察输出来判断 Docker 服务是否启动。

          如果 Docker 服务正在运行,该命令将列出所有正在运行的容器(如果没有运行的容器,则可能只显示表头)。如果 Docker 服务没有运行,你将看到一个错误消息,如“Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?”

          1. 使用 docker info 命令

          docker info 命令提供 Docker 系统的详细信息,包括容器数量、镜像数量、Docker 版本等。如果 Docker 服务正在运行,该命令将正常输出这些信息。

          如果 Docker 服务正在运行,你将看到一系列关于 Docker 系统的信息。如果 Docker 服务没有运行,你将看到一个错误消息,与 docker ps 命令类似。

          安装 docker 的网站:https://hub.docker.com/

          images

          Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作容器的模板。Docker 根据 image 文件生成的容器实例。同一个 image 文件,可以生成多个同时运行的容器实例

          image 是二进制文件。实际开发过程中,一个 image 文件往往通过继承另一个 image 文件,再加上一些个性化的设置而成。

          shell
          # 搜索镜像
           $ docker search [keywords]
           # 列出本机所有的image文件
           $docker image ls
          diff --git a/assets/cn_src_note_docker.md.Cdo71zW_.lean.js b/assets/cn_src_note_docker.md.tDnzoB7w.lean.js
          similarity index 99%
          rename from assets/cn_src_note_docker.md.Cdo71zW_.lean.js
          rename to assets/cn_src_note_docker.md.tDnzoB7w.lean.js
          index 8acb238d2c..f6c352cd94 100644
          --- a/assets/cn_src_note_docker.md.Cdo71zW_.lean.js
          +++ b/assets/cn_src_note_docker.md.tDnzoB7w.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as e,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"docker","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/docker.md","filePath":"cn/src/note/docker.md","lastUpdated":1728828157000}'),n={name:"cn/src/note/docker.md"};function h(t,s,p,k,d,r){return a(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l(`

          docker

          查询 docker 是否在运行:

          1. 输入以下命令来查找 Docker 守护进程的 PID(进程 ID):
          sh
          ps -ef | grep docker

          如果命令返回了包含/usr/local/bin/dockerd(或类似路径)的行,并且 PID 列有数字显示,那么 Docker 守护进程正在运行。

          1. 使用 docker ps 命令

          虽然 docker ps 命令主要用于列出正在运行的容器,但如果 Docker 服务没有运行,该命令会返回一个错误消息。因此,你也可以通过运行该命令并观察输出来判断 Docker 服务是否启动。

          如果 Docker 服务正在运行,该命令将列出所有正在运行的容器(如果没有运行的容器,则可能只显示表头)。如果 Docker 服务没有运行,你将看到一个错误消息,如“Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?”

          1. 使用 docker info 命令

          docker info 命令提供 Docker 系统的详细信息,包括容器数量、镜像数量、Docker 版本等。如果 Docker 服务正在运行,该命令将正常输出这些信息。

          如果 Docker 服务正在运行,你将看到一系列关于 Docker 系统的信息。如果 Docker 服务没有运行,你将看到一个错误消息,与 docker ps 命令类似。

          安装 docker 的网站:https://hub.docker.com/

          images

          Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作容器的模板。Docker 根据 image 文件生成的容器实例。同一个 image 文件,可以生成多个同时运行的容器实例

          image 是二进制文件。实际开发过程中,一个 image 文件往往通过继承另一个 image 文件,再加上一些个性化的设置而成。

          shell
          # 搜索镜像
          +import{_ as i,o as a,c as e,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"docker","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/docker.md","filePath":"cn/src/note/docker.md","lastUpdated":1728921295000}'),n={name:"cn/src/note/docker.md"};function h(t,s,p,k,d,r){return a(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l(`

          docker

          查询 docker 是否在运行:

          1. 输入以下命令来查找 Docker 守护进程的 PID(进程 ID):
          sh
          ps -ef | grep docker

          如果命令返回了包含/usr/local/bin/dockerd(或类似路径)的行,并且 PID 列有数字显示,那么 Docker 守护进程正在运行。

          1. 使用 docker ps 命令

          虽然 docker ps 命令主要用于列出正在运行的容器,但如果 Docker 服务没有运行,该命令会返回一个错误消息。因此,你也可以通过运行该命令并观察输出来判断 Docker 服务是否启动。

          如果 Docker 服务正在运行,该命令将列出所有正在运行的容器(如果没有运行的容器,则可能只显示表头)。如果 Docker 服务没有运行,你将看到一个错误消息,如“Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?”

          1. 使用 docker info 命令

          docker info 命令提供 Docker 系统的详细信息,包括容器数量、镜像数量、Docker 版本等。如果 Docker 服务正在运行,该命令将正常输出这些信息。

          如果 Docker 服务正在运行,你将看到一系列关于 Docker 系统的信息。如果 Docker 服务没有运行,你将看到一个错误消息,与 docker ps 命令类似。

          安装 docker 的网站:https://hub.docker.com/

          images

          Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作容器的模板。Docker 根据 image 文件生成的容器实例。同一个 image 文件,可以生成多个同时运行的容器实例

          image 是二进制文件。实际开发过程中,一个 image 文件往往通过继承另一个 image 文件,再加上一些个性化的设置而成。

          shell
          # 搜索镜像
           $ docker search [keywords]
           # 列出本机所有的image文件
           $docker image ls
          diff --git a/assets/cn_src_note_libreoffice2wasm.md.D2SYnyUq.js b/assets/cn_src_note_libreoffice2wasm.md.DGtQ0t2p.js
          similarity index 99%
          rename from assets/cn_src_note_libreoffice2wasm.md.D2SYnyUq.js
          rename to assets/cn_src_note_libreoffice2wasm.md.DGtQ0t2p.js
          index ce069cd36d..4c55b538a0 100644
          --- a/assets/cn_src_note_libreoffice2wasm.md.D2SYnyUq.js
          +++ b/assets/cn_src_note_libreoffice2wasm.md.DGtQ0t2p.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as e,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"克隆 Binaryen 仓库","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/libreoffice2wasm.md","filePath":"cn/src/note/libreoffice2wasm.md","lastUpdated":1728828157000}'),n={name:"cn/src/note/libreoffice2wasm.md"};function t(p,s,h,k,d,r){return a(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l(`

          项目地址:

          sh
          git clone https://git.libreoffice.org/core

          github 地址:https://github.com/LibreOffice/core/blob/master/static/README.wasm.md

          容器化环境

          由于是 c/c++ 的项目,编译过程需要很多系统级别配置。如果当前设备不支持的话,不建议强行去适配。可以进行容器化处理。

          比如用一个最常见的服务器系统:

          sh
          docker image pull ubuntu

          下载完成后,就可以去构建一个服务了:

          sh
          docker container run -p 30105:30105 --name=alit -itd ubuntu /bin/bash

          构建并启动成功后,可以通过docker container ls去查看运行情况:

          sh
          CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS                      NAMES
          +import{_ as i,o as a,c as e,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"克隆 Binaryen 仓库","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/libreoffice2wasm.md","filePath":"cn/src/note/libreoffice2wasm.md","lastUpdated":1728921295000}'),n={name:"cn/src/note/libreoffice2wasm.md"};function t(p,s,h,k,d,r){return a(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l(`

          项目地址:

          sh
          git clone https://git.libreoffice.org/core

          github 地址:https://github.com/LibreOffice/core/blob/master/static/README.wasm.md

          容器化环境

          由于是 c/c++ 的项目,编译过程需要很多系统级别配置。如果当前设备不支持的话,不建议强行去适配。可以进行容器化处理。

          比如用一个最常见的服务器系统:

          sh
          docker image pull ubuntu

          下载完成后,就可以去构建一个服务了:

          sh
          docker container run -p 30105:30105 --name=alit -itd ubuntu /bin/bash

          构建并启动成功后,可以通过docker container ls去查看运行情况:

          sh
          CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS                      NAMES
           efd831ab0ba8   ubuntu    "/bin/bash"   5 seconds ago   Up 4 seconds   0.0.0.0:30105->30105/tcp   alit

          再将项目移动到容器中:

          sh
          docker cp ./core alit:/home
           # 总的来说,项目还是非常大的
           # Successfully copied 3.59GB to alit:/home

          进入容器,进行操作。

          sh
          docker exec -it alit /bin/bash

          这样,就可以把开发构建环境和电脑系统隔离开,防止一些系统级别不安全的操作了。

          安装必要的依赖:

          sh
          dnf install -y git cmake python3 nodejs
          diff --git a/assets/cn_src_note_libreoffice2wasm.md.D2SYnyUq.lean.js b/assets/cn_src_note_libreoffice2wasm.md.DGtQ0t2p.lean.js
          similarity index 99%
          rename from assets/cn_src_note_libreoffice2wasm.md.D2SYnyUq.lean.js
          rename to assets/cn_src_note_libreoffice2wasm.md.DGtQ0t2p.lean.js
          index ce069cd36d..4c55b538a0 100644
          --- a/assets/cn_src_note_libreoffice2wasm.md.D2SYnyUq.lean.js
          +++ b/assets/cn_src_note_libreoffice2wasm.md.DGtQ0t2p.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as e,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"克隆 Binaryen 仓库","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/libreoffice2wasm.md","filePath":"cn/src/note/libreoffice2wasm.md","lastUpdated":1728828157000}'),n={name:"cn/src/note/libreoffice2wasm.md"};function t(p,s,h,k,d,r){return a(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l(`

          项目地址:

          sh
          git clone https://git.libreoffice.org/core

          github 地址:https://github.com/LibreOffice/core/blob/master/static/README.wasm.md

          容器化环境

          由于是 c/c++ 的项目,编译过程需要很多系统级别配置。如果当前设备不支持的话,不建议强行去适配。可以进行容器化处理。

          比如用一个最常见的服务器系统:

          sh
          docker image pull ubuntu

          下载完成后,就可以去构建一个服务了:

          sh
          docker container run -p 30105:30105 --name=alit -itd ubuntu /bin/bash

          构建并启动成功后,可以通过docker container ls去查看运行情况:

          sh
          CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS                      NAMES
          +import{_ as i,o as a,c as e,a3 as l}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"克隆 Binaryen 仓库","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/libreoffice2wasm.md","filePath":"cn/src/note/libreoffice2wasm.md","lastUpdated":1728921295000}'),n={name:"cn/src/note/libreoffice2wasm.md"};function t(p,s,h,k,d,r){return a(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[l(`

          项目地址:

          sh
          git clone https://git.libreoffice.org/core

          github 地址:https://github.com/LibreOffice/core/blob/master/static/README.wasm.md

          容器化环境

          由于是 c/c++ 的项目,编译过程需要很多系统级别配置。如果当前设备不支持的话,不建议强行去适配。可以进行容器化处理。

          比如用一个最常见的服务器系统:

          sh
          docker image pull ubuntu

          下载完成后,就可以去构建一个服务了:

          sh
          docker container run -p 30105:30105 --name=alit -itd ubuntu /bin/bash

          构建并启动成功后,可以通过docker container ls去查看运行情况:

          sh
          CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS                      NAMES
           efd831ab0ba8   ubuntu    "/bin/bash"   5 seconds ago   Up 4 seconds   0.0.0.0:30105->30105/tcp   alit

          再将项目移动到容器中:

          sh
          docker cp ./core alit:/home
           # 总的来说,项目还是非常大的
           # Successfully copied 3.59GB to alit:/home

          进入容器,进行操作。

          sh
          docker exec -it alit /bin/bash

          这样,就可以把开发构建环境和电脑系统隔离开,防止一些系统级别不安全的操作了。

          安装必要的依赖:

          sh
          dnf install -y git cmake python3 nodejs
          diff --git a/assets/cn_src_note_ubuntu.md.DgjTInOe.js b/assets/cn_src_note_ubuntu.md.pqpeIfp6.js
          similarity index 98%
          rename from assets/cn_src_note_ubuntu.md.DgjTInOe.js
          rename to assets/cn_src_note_ubuntu.md.pqpeIfp6.js
          index f4e7fc9260..7013d87121 100644
          --- a/assets/cn_src_note_ubuntu.md.DgjTInOe.js
          +++ b/assets/cn_src_note_ubuntu.md.pqpeIfp6.js
          @@ -1,3 +1,3 @@
          -import{_ as i,o as a,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"ubuntu","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/ubuntu.md","filePath":"cn/src/note/ubuntu.md","lastUpdated":1728828157000}'),h={name:"cn/src/note/ubuntu.md"};function l(k,s,e,p,F,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          ubuntu

          sh
          apt update
          +import{_ as i,o as a,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"ubuntu","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/ubuntu.md","filePath":"cn/src/note/ubuntu.md","lastUpdated":1728921295000}'),h={name:"cn/src/note/ubuntu.md"};function l(k,s,e,p,F,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          ubuntu

          sh
          apt update
           
           apt install openjdk-11-jdk  wget curl junit4 ant libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev libgtk-3-dev libglib2.0-dev libatk1.0-dev libcairo2-dev zip flex uuid-runtime bison libxrandr-dev libxrender-dev libxext-dev libnss3-dev libnspr4-dev libkrb5-dev python3 python3-pip libxml2-utils xsltproc libxslt1-dev gperf libfontconfig1-dev libcups2-dev gcc make autoconf pkg-config automake
          `,2)]))}const u=i(h,[["render",l]]);export{g as __pageData,u as default}; diff --git a/assets/cn_src_note_ubuntu.md.DgjTInOe.lean.js b/assets/cn_src_note_ubuntu.md.pqpeIfp6.lean.js similarity index 98% rename from assets/cn_src_note_ubuntu.md.DgjTInOe.lean.js rename to assets/cn_src_note_ubuntu.md.pqpeIfp6.lean.js index f4e7fc9260..7013d87121 100644 --- a/assets/cn_src_note_ubuntu.md.DgjTInOe.lean.js +++ b/assets/cn_src_note_ubuntu.md.pqpeIfp6.lean.js @@ -1,3 +1,3 @@ -import{_ as i,o as a,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"ubuntu","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/ubuntu.md","filePath":"cn/src/note/ubuntu.md","lastUpdated":1728828157000}'),h={name:"cn/src/note/ubuntu.md"};function l(k,s,e,p,F,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          ubuntu

          sh
          apt update
          +import{_ as i,o as a,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"ubuntu","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/note/ubuntu.md","filePath":"cn/src/note/ubuntu.md","lastUpdated":1728921295000}'),h={name:"cn/src/note/ubuntu.md"};function l(k,s,e,p,F,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          ubuntu

          sh
          apt update
           
           apt install openjdk-11-jdk  wget curl junit4 ant libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev libgtk-3-dev libglib2.0-dev libatk1.0-dev libcairo2-dev zip flex uuid-runtime bison libxrandr-dev libxrender-dev libxext-dev libnss3-dev libnspr4-dev libkrb5-dev python3 python3-pip libxml2-utils xsltproc libxslt1-dev gperf libfontconfig1-dev libcups2-dev gcc make autoconf pkg-config automake
          `,2)]))}const u=i(h,[["render",l]]);export{g as __pageData,u as default}; diff --git a/assets/cn_src_ranui_button_index.md.CGOk0U0f.js b/assets/cn_src_ranui_button_index.md.BoAZB7ta.js similarity index 99% rename from assets/cn_src_ranui_button_index.md.CGOk0U0f.js rename to assets/cn_src_ranui_button_index.md.BoAZB7ta.js index 8e2c101305..51ef489856 100644 --- a/assets/cn_src_ranui_button_index.md.CGOk0U0f.js +++ b/assets/cn_src_ranui_button_index.md.BoAZB7ta.js @@ -1,4 +1,4 @@ -import{_ as a,o as n,c as l,a3 as s,j as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Button 按钮","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/button/index.md","filePath":"cn/src/ranui/button/index.md","lastUpdated":1728828157000}'),h={name:"cn/src/ranui/button/index.md"};function p(e,i,k,r,d,E){return n(),l("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s(`

          Button 按钮

          按钮用于开始一个即时操作。

          代码演示

          Button
          xml
           <r-button >Button</r-button>

          属性

          类型type

          按钮有四种类型

          主要按钮
          警告按钮
          文本按钮
          默认按钮
          xml
           <r-button type="primary">主要按钮</r-button>
          +import{_ as a,o as n,c as l,a3 as s,j as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Button 按钮","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/button/index.md","filePath":"cn/src/ranui/button/index.md","lastUpdated":1728921295000}'),h={name:"cn/src/ranui/button/index.md"};function p(e,i,k,r,d,E){return n(),l("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s(`

          Button 按钮

          按钮用于开始一个即时操作。

          代码演示

          Button
          xml
           <r-button >Button</r-button>

          属性

          类型type

          按钮有四种类型

          主要按钮
          警告按钮
          文本按钮
          默认按钮
          xml
           <r-button type="primary">主要按钮</r-button>
            <r-button type="warning">警告按钮</r-button>
            <r-button type="text">文本按钮</r-button>
            <r-button >默认按钮</r-button>

          不可用状态disabled

          添加 disabled 属性即可让按钮处于不可用状态,同时按钮样式也会改变。

          主要按钮
          警告按钮
          文本按钮
          默认按钮
          xml
           <r-button type="primary" disabled>主要按钮</r-button>
          diff --git a/assets/cn_src_ranui_button_index.md.CGOk0U0f.lean.js b/assets/cn_src_ranui_button_index.md.BoAZB7ta.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_button_index.md.CGOk0U0f.lean.js
          rename to assets/cn_src_ranui_button_index.md.BoAZB7ta.lean.js
          index 8e2c101305..51ef489856 100644
          --- a/assets/cn_src_ranui_button_index.md.CGOk0U0f.lean.js
          +++ b/assets/cn_src_ranui_button_index.md.BoAZB7ta.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as a,o as n,c as l,a3 as s,j as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Button 按钮","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/button/index.md","filePath":"cn/src/ranui/button/index.md","lastUpdated":1728828157000}'),h={name:"cn/src/ranui/button/index.md"};function p(e,i,k,r,d,E){return n(),l("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s(`

          Button 按钮

          按钮用于开始一个即时操作。

          代码演示

          Button
          xml
           <r-button >Button</r-button>

          属性

          类型type

          按钮有四种类型

          主要按钮
          警告按钮
          文本按钮
          默认按钮
          xml
           <r-button type="primary">主要按钮</r-button>
          +import{_ as a,o as n,c as l,a3 as s,j as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Button 按钮","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/button/index.md","filePath":"cn/src/ranui/button/index.md","lastUpdated":1728921295000}'),h={name:"cn/src/ranui/button/index.md"};function p(e,i,k,r,d,E){return n(),l("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s(`

          Button 按钮

          按钮用于开始一个即时操作。

          代码演示

          Button
          xml
           <r-button >Button</r-button>

          属性

          类型type

          按钮有四种类型

          主要按钮
          警告按钮
          文本按钮
          默认按钮
          xml
           <r-button type="primary">主要按钮</r-button>
            <r-button type="warning">警告按钮</r-button>
            <r-button type="text">文本按钮</r-button>
            <r-button >默认按钮</r-button>

          不可用状态disabled

          添加 disabled 属性即可让按钮处于不可用状态,同时按钮样式也会改变。

          主要按钮
          警告按钮
          文本按钮
          默认按钮
          xml
           <r-button type="primary" disabled>主要按钮</r-button>
          diff --git a/assets/cn_src_ranui_checkbox_index.md.ZHU13zPM.js b/assets/cn_src_ranui_checkbox_index.md.C3KmEc2G.js
          similarity index 99%
          rename from assets/cn_src_ranui_checkbox_index.md.ZHU13zPM.js
          rename to assets/cn_src_ranui_checkbox_index.md.C3KmEc2G.js
          index 2d34ff2795..383a24d561 100644
          --- a/assets/cn_src_ranui_checkbox_index.md.ZHU13zPM.js
          +++ b/assets/cn_src_ranui_checkbox_index.md.C3KmEc2G.js
          @@ -1,2 +1,2 @@
          -import{_ as e,o as h,c as t,a3 as i,j as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CheckBox 多选框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/checkbox/index.md","filePath":"cn/src/ranui/checkbox/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranui/checkbox/index.md"};function n(k,s,c,p,d,r){return h(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[i('

          CheckBox 多选框

          代码演示

          xml
           <r-checkbox ></r-checkbox>

          属性

          checked

          xml
           <r-checkbox checked="true"></r-checkbox>\n <r-checkbox checked="false"></r-checkbox>

          disabled

          xml
           <r-checkbox checked="true" disabled></r-checkbox>\n <r-checkbox checked="false" disabled></r-checkbox>

          事件event

          改变的时候触发。

          onchange

          ',16),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),i(`
          xml
           <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
          +import{_ as e,o as h,c as t,a3 as i,j as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CheckBox 多选框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/checkbox/index.md","filePath":"cn/src/ranui/checkbox/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranui/checkbox/index.md"};function n(k,s,c,p,d,r){return h(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[i('

          CheckBox 多选框

          代码演示

          xml
           <r-checkbox ></r-checkbox>

          属性

          checked

          xml
           <r-checkbox checked="true"></r-checkbox>\n <r-checkbox checked="false"></r-checkbox>

          disabled

          xml
           <r-checkbox checked="true" disabled></r-checkbox>\n <r-checkbox checked="false" disabled></r-checkbox>

          事件event

          改变的时候触发。

          onchange

          ',16),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),i(`
          xml
           <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
            <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
          `,1)]))}const g=e(l,[["render",n]]);export{E as __pageData,g as default}; diff --git a/assets/cn_src_ranui_checkbox_index.md.ZHU13zPM.lean.js b/assets/cn_src_ranui_checkbox_index.md.C3KmEc2G.lean.js similarity index 99% rename from assets/cn_src_ranui_checkbox_index.md.ZHU13zPM.lean.js rename to assets/cn_src_ranui_checkbox_index.md.C3KmEc2G.lean.js index 2d34ff2795..383a24d561 100644 --- a/assets/cn_src_ranui_checkbox_index.md.ZHU13zPM.lean.js +++ b/assets/cn_src_ranui_checkbox_index.md.C3KmEc2G.lean.js @@ -1,2 +1,2 @@ -import{_ as e,o as h,c as t,a3 as i,j as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CheckBox 多选框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/checkbox/index.md","filePath":"cn/src/ranui/checkbox/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranui/checkbox/index.md"};function n(k,s,c,p,d,r){return h(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[i('

          CheckBox 多选框

          代码演示

          xml
           <r-checkbox ></r-checkbox>

          属性

          checked

          xml
           <r-checkbox checked="true"></r-checkbox>\n <r-checkbox checked="false"></r-checkbox>

          disabled

          xml
           <r-checkbox checked="true" disabled></r-checkbox>\n <r-checkbox checked="false" disabled></r-checkbox>

          事件event

          改变的时候触发。

          onchange

          ',16),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),i(`
          xml
           <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
          +import{_ as e,o as h,c as t,a3 as i,j as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CheckBox 多选框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/checkbox/index.md","filePath":"cn/src/ranui/checkbox/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranui/checkbox/index.md"};function n(k,s,c,p,d,r){return h(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[i('

          CheckBox 多选框

          代码演示

          xml
           <r-checkbox ></r-checkbox>

          属性

          checked

          xml
           <r-checkbox checked="true"></r-checkbox>\n <r-checkbox checked="false"></r-checkbox>

          disabled

          xml
           <r-checkbox checked="true" disabled></r-checkbox>\n <r-checkbox checked="false" disabled></r-checkbox>

          事件event

          改变的时候触发。

          onchange

          ',16),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),i(`
          xml
           <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
            <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
          `,1)]))}const g=e(l,[["render",n]]);export{E as __pageData,g as default}; diff --git a/assets/cn_src_ranui_icon_index.md.NbG8FVyF.js b/assets/cn_src_ranui_icon_index.md.BB3PfUZM.js similarity index 99% rename from assets/cn_src_ranui_icon_index.md.NbG8FVyF.js rename to assets/cn_src_ranui_icon_index.md.BB3PfUZM.js index 28246289d6..be42f0a7d5 100644 --- a/assets/cn_src_ranui_icon_index.md.NbG8FVyF.js +++ b/assets/cn_src_ranui_icon_index.md.BB3PfUZM.js @@ -1,4 +1,4 @@ -import{_ as p,o as E,c as r,a3 as e,j as n}from"./chunks/framework.BYE6xntm.js";const o=()=>{setTimeout(()=>{const l=["add-user","book","check-circle","close-circle","eye-close","eye","info-circle","loading","lock","message","power-off","setting","team","unlock","user"];if(typeof document<"u"){const a=document.getElementById("icon-list"),s=document.createElement("div");s.style.setProperty("display","grid"),s.style.setProperty("grid-template-columns","repeat(3, 200px)"),s.style.setProperty("grid-template-rows","repeat(3, 200px);"),l.forEach(h=>{const i=document.createElement("div");i.style.setProperty("display","flex"),i.style.setProperty("align-items","center"),i.style.setProperty("margin","15px"),i.style.setProperty("justify-content","center"),i.style.setProperty("flex-flow","column nowrap");const t=document.createElement("r-icon");t.setAttribute("name",h),t.setAttribute("size","50"),i.appendChild(t);const k=document.createElement("span");k.innerHTML=h,i.appendChild(k),s==null||s.appendChild(i)}),a==null||a.appendChild(s)}},0)};o();const y=JSON.parse('{"title":"Icon 图标","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/icon/index.md","filePath":"cn/src/ranui/icon/index.md","lastUpdated":1728828157000}'),d={name:"cn/src/ranui/icon/index.md"};function g(l,a,s,h,i,t){return E(),r("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

          Icon 图标

          语义化的矢量图形

          代码演示

          xml
           <r-icon name="lock"  ></r-icon>
          +import{_ as p,o as E,c as r,a3 as e,j as n}from"./chunks/framework.BYE6xntm.js";const o=()=>{setTimeout(()=>{const l=["add-user","book","check-circle","close-circle","eye-close","eye","info-circle","loading","lock","message","power-off","setting","team","unlock","user"];if(typeof document<"u"){const a=document.getElementById("icon-list"),s=document.createElement("div");s.style.setProperty("display","grid"),s.style.setProperty("grid-template-columns","repeat(3, 200px)"),s.style.setProperty("grid-template-rows","repeat(3, 200px);"),l.forEach(h=>{const i=document.createElement("div");i.style.setProperty("display","flex"),i.style.setProperty("align-items","center"),i.style.setProperty("margin","15px"),i.style.setProperty("justify-content","center"),i.style.setProperty("flex-flow","column nowrap");const t=document.createElement("r-icon");t.setAttribute("name",h),t.setAttribute("size","50"),i.appendChild(t);const k=document.createElement("span");k.innerHTML=h,i.appendChild(k),s==null||s.appendChild(i)}),a==null||a.appendChild(s)}},0)};o();const y=JSON.parse('{"title":"Icon 图标","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/icon/index.md","filePath":"cn/src/ranui/icon/index.md","lastUpdated":1728921295000}'),d={name:"cn/src/ranui/icon/index.md"};function g(l,a,s,h,i,t){return E(),r("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

          Icon 图标

          语义化的矢量图形

          代码演示

          xml
           <r-icon name="lock"  ></r-icon>
            <r-icon name="eye"  ></r-icon>
            <r-icon name="user"  ></r-icon>

          属性

          名称name

          根据名称选择不同的图标

          html
          <r-icon name="lock"></r-icon>
           <r-icon name="eye"></r-icon>
          diff --git a/assets/cn_src_ranui_icon_index.md.NbG8FVyF.lean.js b/assets/cn_src_ranui_icon_index.md.BB3PfUZM.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_icon_index.md.NbG8FVyF.lean.js
          rename to assets/cn_src_ranui_icon_index.md.BB3PfUZM.lean.js
          index 28246289d6..be42f0a7d5 100644
          --- a/assets/cn_src_ranui_icon_index.md.NbG8FVyF.lean.js
          +++ b/assets/cn_src_ranui_icon_index.md.BB3PfUZM.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as p,o as E,c as r,a3 as e,j as n}from"./chunks/framework.BYE6xntm.js";const o=()=>{setTimeout(()=>{const l=["add-user","book","check-circle","close-circle","eye-close","eye","info-circle","loading","lock","message","power-off","setting","team","unlock","user"];if(typeof document<"u"){const a=document.getElementById("icon-list"),s=document.createElement("div");s.style.setProperty("display","grid"),s.style.setProperty("grid-template-columns","repeat(3, 200px)"),s.style.setProperty("grid-template-rows","repeat(3, 200px);"),l.forEach(h=>{const i=document.createElement("div");i.style.setProperty("display","flex"),i.style.setProperty("align-items","center"),i.style.setProperty("margin","15px"),i.style.setProperty("justify-content","center"),i.style.setProperty("flex-flow","column nowrap");const t=document.createElement("r-icon");t.setAttribute("name",h),t.setAttribute("size","50"),i.appendChild(t);const k=document.createElement("span");k.innerHTML=h,i.appendChild(k),s==null||s.appendChild(i)}),a==null||a.appendChild(s)}},0)};o();const y=JSON.parse('{"title":"Icon 图标","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/icon/index.md","filePath":"cn/src/ranui/icon/index.md","lastUpdated":1728828157000}'),d={name:"cn/src/ranui/icon/index.md"};function g(l,a,s,h,i,t){return E(),r("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

          Icon 图标

          语义化的矢量图形

          代码演示

          xml
           <r-icon name="lock"  ></r-icon>
          +import{_ as p,o as E,c as r,a3 as e,j as n}from"./chunks/framework.BYE6xntm.js";const o=()=>{setTimeout(()=>{const l=["add-user","book","check-circle","close-circle","eye-close","eye","info-circle","loading","lock","message","power-off","setting","team","unlock","user"];if(typeof document<"u"){const a=document.getElementById("icon-list"),s=document.createElement("div");s.style.setProperty("display","grid"),s.style.setProperty("grid-template-columns","repeat(3, 200px)"),s.style.setProperty("grid-template-rows","repeat(3, 200px);"),l.forEach(h=>{const i=document.createElement("div");i.style.setProperty("display","flex"),i.style.setProperty("align-items","center"),i.style.setProperty("margin","15px"),i.style.setProperty("justify-content","center"),i.style.setProperty("flex-flow","column nowrap");const t=document.createElement("r-icon");t.setAttribute("name",h),t.setAttribute("size","50"),i.appendChild(t);const k=document.createElement("span");k.innerHTML=h,i.appendChild(k),s==null||s.appendChild(i)}),a==null||a.appendChild(s)}},0)};o();const y=JSON.parse('{"title":"Icon 图标","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/icon/index.md","filePath":"cn/src/ranui/icon/index.md","lastUpdated":1728921295000}'),d={name:"cn/src/ranui/icon/index.md"};function g(l,a,s,h,i,t){return E(),r("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

          Icon 图标

          语义化的矢量图形

          代码演示

          xml
           <r-icon name="lock"  ></r-icon>
            <r-icon name="eye"  ></r-icon>
            <r-icon name="user"  ></r-icon>

          属性

          名称name

          根据名称选择不同的图标

          html
          <r-icon name="lock"></r-icon>
           <r-icon name="eye"></r-icon>
          diff --git a/assets/cn_src_ranui_image_index.md.DowaFgBv.js b/assets/cn_src_ranui_image_index.md.C-xnLYah.js
          similarity index 98%
          rename from assets/cn_src_ranui_image_index.md.DowaFgBv.js
          rename to assets/cn_src_ranui_image_index.md.C-xnLYah.js
          index 15742ffc5d..9ce88c9f44 100644
          --- a/assets/cn_src_ranui_image_index.md.DowaFgBv.js
          +++ b/assets/cn_src_ranui_image_index.md.C-xnLYah.js
          @@ -1 +1 @@
          -import{_ as a,o as E,c as i,a3 as Q,j as e}from"./chunks/framework.BYE6xntm.js";const B=JSON.parse('{"title":"Image 图片","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/image/index.md","filePath":"cn/src/ranui/image/index.md","lastUpdated":1728828157000}'),g={name:"cn/src/ranui/image/index.md"};function s(n,A,t,h,o,l){return E(),i("div",{"data-pagefind-body":!0},A[0]||(A[0]=[Q('

          Image 图片

          代码演示

          xml
           <r-img src="" fallback=""></r-img>

          属性

          图片加载地址src

          图片的地址

          图片加载失败fallback

          src配置的图片加载失败,兜底的图片地址,下面是默认加载失败图片

          ',8),e("r-img",{fallback:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="},null,-1)]))}const r=a(g,[["render",s]]);export{B as __pageData,r as default}; +import{_ as a,o as E,c as i,a3 as Q,j as e}from"./chunks/framework.BYE6xntm.js";const B=JSON.parse('{"title":"Image 图片","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/image/index.md","filePath":"cn/src/ranui/image/index.md","lastUpdated":1728921295000}'),g={name:"cn/src/ranui/image/index.md"};function s(n,A,t,h,o,l){return E(),i("div",{"data-pagefind-body":!0},A[0]||(A[0]=[Q('

          Image 图片

          代码演示

          xml
           <r-img src="" fallback=""></r-img>

          属性

          图片加载地址src

          图片的地址

          图片加载失败fallback

          src配置的图片加载失败,兜底的图片地址,下面是默认加载失败图片

          ',8),e("r-img",{fallback:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="},null,-1)]))}const r=a(g,[["render",s]]);export{B as __pageData,r as default}; diff --git a/assets/cn_src_ranui_image_index.md.DowaFgBv.lean.js b/assets/cn_src_ranui_image_index.md.C-xnLYah.lean.js similarity index 98% rename from assets/cn_src_ranui_image_index.md.DowaFgBv.lean.js rename to assets/cn_src_ranui_image_index.md.C-xnLYah.lean.js index 15742ffc5d..9ce88c9f44 100644 --- a/assets/cn_src_ranui_image_index.md.DowaFgBv.lean.js +++ b/assets/cn_src_ranui_image_index.md.C-xnLYah.lean.js @@ -1 +1 @@ -import{_ as a,o as E,c as i,a3 as Q,j as e}from"./chunks/framework.BYE6xntm.js";const B=JSON.parse('{"title":"Image 图片","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/image/index.md","filePath":"cn/src/ranui/image/index.md","lastUpdated":1728828157000}'),g={name:"cn/src/ranui/image/index.md"};function s(n,A,t,h,o,l){return E(),i("div",{"data-pagefind-body":!0},A[0]||(A[0]=[Q('

          Image 图片

          代码演示

          xml
           <r-img src="" fallback=""></r-img>

          属性

          图片加载地址src

          图片的地址

          图片加载失败fallback

          src配置的图片加载失败,兜底的图片地址,下面是默认加载失败图片

          ',8),e("r-img",{fallback:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="},null,-1)]))}const r=a(g,[["render",s]]);export{B as __pageData,r as default}; +import{_ as a,o as E,c as i,a3 as Q,j as e}from"./chunks/framework.BYE6xntm.js";const B=JSON.parse('{"title":"Image 图片","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/image/index.md","filePath":"cn/src/ranui/image/index.md","lastUpdated":1728921295000}'),g={name:"cn/src/ranui/image/index.md"};function s(n,A,t,h,o,l){return E(),i("div",{"data-pagefind-body":!0},A[0]||(A[0]=[Q('

          Image 图片

          代码演示

          xml
           <r-img src="" fallback=""></r-img>

          属性

          图片加载地址src

          图片的地址

          图片加载失败fallback

          src配置的图片加载失败,兜底的图片地址,下面是默认加载失败图片

          ',8),e("r-img",{fallback:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="},null,-1)]))}const r=a(g,[["render",s]]);export{B as __pageData,r as default}; diff --git a/assets/cn_src_ranui_index.md.DHsUGsLz.js b/assets/cn_src_ranui_index.md.CrHo0ngz.js similarity index 99% rename from assets/cn_src_ranui_index.md.DHsUGsLz.js rename to assets/cn_src_ranui_index.md.CrHo0ngz.js index 90f1fe3b6a..1f2df8e855 100644 --- a/assets/cn_src_ranui_index.md.DHsUGsLz.js +++ b/assets/cn_src_ranui_index.md.CrHo0ngz.js @@ -1,4 +1,4 @@ -import{_ as t}from"./chunks/customElements.qitHOM3M.js";import{_ as n,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"ranui","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/index.md","filePath":"cn/src/ranui/index.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranui/index.md"};function p(k,a,r,E,d,g){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          ranui

          基于 Web Components开发方案

          特点

          1. 跨框架兼容: 与 React, Vue, Preact, SolidJS, Svelte 等兼容。可以和遵循 W3C 标准的任何 JavaScript 项目集成。
          2. 原生体验: 易于入门,像使用本地 div 标签,简化项目大小和减少学习成本。
          3. 模块化设计: 可选导入和全量导入,以增强可维护性和可伸缩性。
          4. 交互式丰富文档: 提供详细的交互式文档,并附有有效的示例子。
          5. 支持类型校验: 基于 TypeScript 构建,具有类型支持,确保代码的健壮性和可维护性。
          6. 持久和稳定: 与框架 (React/vue) 无关,避免破坏性的更新,并确保持续的项目运行。

          安装

          使用 npm:

          console
          npm install ranui --save

          引入方式

          支持按需导入,以显著减少包体积大小

          js
          import 'ranui/button';

          如果遇到样式问题,可以选择手动导入样式文件

          js
          import 'ranui/style';

          如果遇到类型问题,可以选择手动导入类型文件

          ts
          import 'ranui/types';

          或者

          ts
          import 'ranui/dist/typings';

          也支持全量导入

          ts
          import 'ranui';
          • ES module
          js
          import 'ranui';

          或者

          js
          import 'ranui/button';
          • UMD, IIFE, CJS
          html
          <script src="./ranui/dist/umd/index.umd.cjs"></script>

          使用方式

          它是基于Web Components的组件,你可以不用关注框架就可以使用它。

          在大多数情况下,您可以像使用本地 div 标签一样使用它

          下面是一些例子:

          • html
          • js
          • jsx
          • vue
          • tsx

          html

          html
          <script src="./ranui/dist/umd/index.umd.cjs"></script>
          +import{_ as t}from"./chunks/customElements.qitHOM3M.js";import{_ as n,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"ranui","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/index.md","filePath":"cn/src/ranui/index.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranui/index.md"};function p(k,a,r,E,d,g){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          ranui

          基于 Web Components开发方案

          特点

          1. 跨框架兼容: 与 React, Vue, Preact, SolidJS, Svelte 等兼容。可以和遵循 W3C 标准的任何 JavaScript 项目集成。
          2. 原生体验: 易于入门,像使用本地 div 标签,简化项目大小和减少学习成本。
          3. 模块化设计: 可选导入和全量导入,以增强可维护性和可伸缩性。
          4. 交互式丰富文档: 提供详细的交互式文档,并附有有效的示例子。
          5. 支持类型校验: 基于 TypeScript 构建,具有类型支持,确保代码的健壮性和可维护性。
          6. 持久和稳定: 与框架 (React/vue) 无关,避免破坏性的更新,并确保持续的项目运行。

          安装

          使用 npm:

          console
          npm install ranui --save

          引入方式

          支持按需导入,以显著减少包体积大小

          js
          import 'ranui/button';

          如果遇到样式问题,可以选择手动导入样式文件

          js
          import 'ranui/style';

          如果遇到类型问题,可以选择手动导入类型文件

          ts
          import 'ranui/types';

          或者

          ts
          import 'ranui/dist/typings';

          也支持全量导入

          ts
          import 'ranui';
          • ES module
          js
          import 'ranui';

          或者

          js
          import 'ranui/button';
          • UMD, IIFE, CJS
          html
          <script src="./ranui/dist/umd/index.umd.cjs"></script>

          使用方式

          它是基于Web Components的组件,你可以不用关注框架就可以使用它。

          在大多数情况下,您可以像使用本地 div 标签一样使用它

          下面是一些例子:

          • html
          • js
          • jsx
          • vue
          • tsx

          html

          html
          <script src="./ranui/dist/umd/index.umd.cjs"></script>
           
           <body>
             <r-button>Button</r-button>
          diff --git a/assets/cn_src_ranui_index.md.DHsUGsLz.lean.js b/assets/cn_src_ranui_index.md.CrHo0ngz.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_index.md.DHsUGsLz.lean.js
          rename to assets/cn_src_ranui_index.md.CrHo0ngz.lean.js
          index 90f1fe3b6a..1f2df8e855 100644
          --- a/assets/cn_src_ranui_index.md.DHsUGsLz.lean.js
          +++ b/assets/cn_src_ranui_index.md.CrHo0ngz.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as t}from"./chunks/customElements.qitHOM3M.js";import{_ as n,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"ranui","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/index.md","filePath":"cn/src/ranui/index.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranui/index.md"};function p(k,a,r,E,d,g){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          ranui

          基于 Web Components开发方案

          特点

          1. 跨框架兼容: 与 React, Vue, Preact, SolidJS, Svelte 等兼容。可以和遵循 W3C 标准的任何 JavaScript 项目集成。
          2. 原生体验: 易于入门,像使用本地 div 标签,简化项目大小和减少学习成本。
          3. 模块化设计: 可选导入和全量导入,以增强可维护性和可伸缩性。
          4. 交互式丰富文档: 提供详细的交互式文档,并附有有效的示例子。
          5. 支持类型校验: 基于 TypeScript 构建,具有类型支持,确保代码的健壮性和可维护性。
          6. 持久和稳定: 与框架 (React/vue) 无关,避免破坏性的更新,并确保持续的项目运行。

          安装

          使用 npm:

          console
          npm install ranui --save

          引入方式

          支持按需导入,以显著减少包体积大小

          js
          import 'ranui/button';

          如果遇到样式问题,可以选择手动导入样式文件

          js
          import 'ranui/style';

          如果遇到类型问题,可以选择手动导入类型文件

          ts
          import 'ranui/types';

          或者

          ts
          import 'ranui/dist/typings';

          也支持全量导入

          ts
          import 'ranui';
          • ES module
          js
          import 'ranui';

          或者

          js
          import 'ranui/button';
          • UMD, IIFE, CJS
          html
          <script src="./ranui/dist/umd/index.umd.cjs"></script>

          使用方式

          它是基于Web Components的组件,你可以不用关注框架就可以使用它。

          在大多数情况下,您可以像使用本地 div 标签一样使用它

          下面是一些例子:

          • html
          • js
          • jsx
          • vue
          • tsx

          html

          html
          <script src="./ranui/dist/umd/index.umd.cjs"></script>
          +import{_ as t}from"./chunks/customElements.qitHOM3M.js";import{_ as n,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"ranui","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/index.md","filePath":"cn/src/ranui/index.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranui/index.md"};function p(k,a,r,E,d,g){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          ranui

          基于 Web Components开发方案

          特点

          1. 跨框架兼容: 与 React, Vue, Preact, SolidJS, Svelte 等兼容。可以和遵循 W3C 标准的任何 JavaScript 项目集成。
          2. 原生体验: 易于入门,像使用本地 div 标签,简化项目大小和减少学习成本。
          3. 模块化设计: 可选导入和全量导入,以增强可维护性和可伸缩性。
          4. 交互式丰富文档: 提供详细的交互式文档,并附有有效的示例子。
          5. 支持类型校验: 基于 TypeScript 构建,具有类型支持,确保代码的健壮性和可维护性。
          6. 持久和稳定: 与框架 (React/vue) 无关,避免破坏性的更新,并确保持续的项目运行。

          安装

          使用 npm:

          console
          npm install ranui --save

          引入方式

          支持按需导入,以显著减少包体积大小

          js
          import 'ranui/button';

          如果遇到样式问题,可以选择手动导入样式文件

          js
          import 'ranui/style';

          如果遇到类型问题,可以选择手动导入类型文件

          ts
          import 'ranui/types';

          或者

          ts
          import 'ranui/dist/typings';

          也支持全量导入

          ts
          import 'ranui';
          • ES module
          js
          import 'ranui';

          或者

          js
          import 'ranui/button';
          • UMD, IIFE, CJS
          html
          <script src="./ranui/dist/umd/index.umd.cjs"></script>

          使用方式

          它是基于Web Components的组件,你可以不用关注框架就可以使用它。

          在大多数情况下,您可以像使用本地 div 标签一样使用它

          下面是一些例子:

          • html
          • js
          • jsx
          • vue
          • tsx

          html

          html
          <script src="./ranui/dist/umd/index.umd.cjs"></script>
           
           <body>
             <r-button>Button</r-button>
          diff --git a/assets/cn_src_ranui_input_index.md.BcdnxU38.js b/assets/cn_src_ranui_input_index.md.DottgzSq.js
          similarity index 99%
          rename from assets/cn_src_ranui_input_index.md.BcdnxU38.js
          rename to assets/cn_src_ranui_input_index.md.DottgzSq.js
          index e421959807..17bd6413eb 100644
          --- a/assets/cn_src_ranui_input_index.md.BcdnxU38.js
          +++ b/assets/cn_src_ranui_input_index.md.DottgzSq.js
          @@ -1,4 +1,4 @@
          -import{_ as t}from"./chunks/input-input.MnARRJC6.js";import{_ as n,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"Input 输入框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/input/index.md","filePath":"cn/src/ranui/input/index.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranui/input/index.md"};function p(k,a,d,r,E,o){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          Input 输入框

          通过鼠标或键盘输入内容,是最基础的表单域的包装。

          代码演示

          输入框:
          xml
          <r-input></r-input>

          属性

          标签label

          提供类似于 Metiral Design 的输入体验。

          html
          <r-input label="user"></r-input>

          占位placeholder

          与原生placeholder一致。

          html
          <r-input placeholder="user"></r-input>

          禁用disabled

          通过disabled可以禁用输入框,禁用后该按钮上的事件失效。

          html
          <r-input label="user" disabled></r-input>

          value

          设置或返回输入框的value属性值。

          类型type

          目前支持passwordnumber这几种类型,设置后会出现额外的ui控件。

          密码输入框

          支持密码明文和密文切换。

          html
          <r-input icon="lock" type="password"></r-input>

          图标icon

          可以设置一个icon来表示标签标识。

          html
          <r-input icon="user"></r-input>

          数字输入框

          数字输入框,类似于原生input[type=number],支持minmaxstep属性,支持键盘上下键切换数字。

          html
          <r-input type="number" min="-10" max="10" step="0.5"></r-input>

          name 属性名

          跟 form 组件联动的时候有效,form 提交时收集的字段名字

          status 状态

          • error

          默认色值: #ff4d4f

          ',40),s("div",null,[s("r-input",{status:"error"})],-1),i('
          xml
          <r-input status="error"></r-input>
          • warning

          默认色值: #ff7875

          ',3),s("div",null,[s("r-input",{status:"warning"})],-1),i('
          xml
          <r-input  status="warning"></r-input>

          事件event

          常见的回调事件。

          onchange

          文本改变的时候触发。

          ',5),s("r-input",{onchange:"console.log(this.value)"},null,-1),i(`
          html
          <r-input onchange="func(this.value)"></r-input>
          js
          const input = document.createElement('r-input');
          +import{_ as t}from"./chunks/input-input.MnARRJC6.js";import{_ as n,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"Input 输入框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/input/index.md","filePath":"cn/src/ranui/input/index.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranui/input/index.md"};function p(k,a,d,r,E,o){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          Input 输入框

          通过鼠标或键盘输入内容,是最基础的表单域的包装。

          代码演示

          输入框:
          xml
          <r-input></r-input>

          属性

          标签label

          提供类似于 Metiral Design 的输入体验。

          html
          <r-input label="user"></r-input>

          占位placeholder

          与原生placeholder一致。

          html
          <r-input placeholder="user"></r-input>

          禁用disabled

          通过disabled可以禁用输入框,禁用后该按钮上的事件失效。

          html
          <r-input label="user" disabled></r-input>

          value

          设置或返回输入框的value属性值。

          类型type

          目前支持passwordnumber这几种类型,设置后会出现额外的ui控件。

          密码输入框

          支持密码明文和密文切换。

          html
          <r-input icon="lock" type="password"></r-input>

          图标icon

          可以设置一个icon来表示标签标识。

          html
          <r-input icon="user"></r-input>

          数字输入框

          数字输入框,类似于原生input[type=number],支持minmaxstep属性,支持键盘上下键切换数字。

          html
          <r-input type="number" min="-10" max="10" step="0.5"></r-input>

          name 属性名

          跟 form 组件联动的时候有效,form 提交时收集的字段名字

          status 状态

          • error

          默认色值: #ff4d4f

          ',40),s("div",null,[s("r-input",{status:"error"})],-1),i('
          xml
          <r-input status="error"></r-input>
          • warning

          默认色值: #ff7875

          ',3),s("div",null,[s("r-input",{status:"warning"})],-1),i('
          xml
          <r-input  status="warning"></r-input>

          事件event

          常见的回调事件。

          onchange

          文本改变的时候触发。

          ',5),s("r-input",{onchange:"console.log(this.value)"},null,-1),i(`
          html
          <r-input onchange="func(this.value)"></r-input>
          js
          const input = document.createElement('r-input');
           input.setAttribute('label', 'home');
           const func = (e) => {
             console.log(e);
          diff --git a/assets/cn_src_ranui_input_index.md.BcdnxU38.lean.js b/assets/cn_src_ranui_input_index.md.DottgzSq.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_input_index.md.BcdnxU38.lean.js
          rename to assets/cn_src_ranui_input_index.md.DottgzSq.lean.js
          index e421959807..17bd6413eb 100644
          --- a/assets/cn_src_ranui_input_index.md.BcdnxU38.lean.js
          +++ b/assets/cn_src_ranui_input_index.md.DottgzSq.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as t}from"./chunks/input-input.MnARRJC6.js";import{_ as n,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"Input 输入框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/input/index.md","filePath":"cn/src/ranui/input/index.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranui/input/index.md"};function p(k,a,d,r,E,o){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          Input 输入框

          通过鼠标或键盘输入内容,是最基础的表单域的包装。

          代码演示

          输入框:
          xml
          <r-input></r-input>

          属性

          标签label

          提供类似于 Metiral Design 的输入体验。

          html
          <r-input label="user"></r-input>

          占位placeholder

          与原生placeholder一致。

          html
          <r-input placeholder="user"></r-input>

          禁用disabled

          通过disabled可以禁用输入框,禁用后该按钮上的事件失效。

          html
          <r-input label="user" disabled></r-input>

          value

          设置或返回输入框的value属性值。

          类型type

          目前支持passwordnumber这几种类型,设置后会出现额外的ui控件。

          密码输入框

          支持密码明文和密文切换。

          html
          <r-input icon="lock" type="password"></r-input>

          图标icon

          可以设置一个icon来表示标签标识。

          html
          <r-input icon="user"></r-input>

          数字输入框

          数字输入框,类似于原生input[type=number],支持minmaxstep属性,支持键盘上下键切换数字。

          html
          <r-input type="number" min="-10" max="10" step="0.5"></r-input>

          name 属性名

          跟 form 组件联动的时候有效,form 提交时收集的字段名字

          status 状态

          • error

          默认色值: #ff4d4f

          ',40),s("div",null,[s("r-input",{status:"error"})],-1),i('
          xml
          <r-input status="error"></r-input>
          • warning

          默认色值: #ff7875

          ',3),s("div",null,[s("r-input",{status:"warning"})],-1),i('
          xml
          <r-input  status="warning"></r-input>

          事件event

          常见的回调事件。

          onchange

          文本改变的时候触发。

          ',5),s("r-input",{onchange:"console.log(this.value)"},null,-1),i(`
          html
          <r-input onchange="func(this.value)"></r-input>
          js
          const input = document.createElement('r-input');
          +import{_ as t}from"./chunks/input-input.MnARRJC6.js";import{_ as n,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"Input 输入框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/input/index.md","filePath":"cn/src/ranui/input/index.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranui/input/index.md"};function p(k,a,d,r,E,o){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          Input 输入框

          通过鼠标或键盘输入内容,是最基础的表单域的包装。

          代码演示

          输入框:
          xml
          <r-input></r-input>

          属性

          标签label

          提供类似于 Metiral Design 的输入体验。

          html
          <r-input label="user"></r-input>

          占位placeholder

          与原生placeholder一致。

          html
          <r-input placeholder="user"></r-input>

          禁用disabled

          通过disabled可以禁用输入框,禁用后该按钮上的事件失效。

          html
          <r-input label="user" disabled></r-input>

          value

          设置或返回输入框的value属性值。

          类型type

          目前支持passwordnumber这几种类型,设置后会出现额外的ui控件。

          密码输入框

          支持密码明文和密文切换。

          html
          <r-input icon="lock" type="password"></r-input>

          图标icon

          可以设置一个icon来表示标签标识。

          html
          <r-input icon="user"></r-input>

          数字输入框

          数字输入框,类似于原生input[type=number],支持minmaxstep属性,支持键盘上下键切换数字。

          html
          <r-input type="number" min="-10" max="10" step="0.5"></r-input>

          name 属性名

          跟 form 组件联动的时候有效,form 提交时收集的字段名字

          status 状态

          • error

          默认色值: #ff4d4f

          ',40),s("div",null,[s("r-input",{status:"error"})],-1),i('
          xml
          <r-input status="error"></r-input>
          • warning

          默认色值: #ff7875

          ',3),s("div",null,[s("r-input",{status:"warning"})],-1),i('
          xml
          <r-input  status="warning"></r-input>

          事件event

          常见的回调事件。

          onchange

          文本改变的时候触发。

          ',5),s("r-input",{onchange:"console.log(this.value)"},null,-1),i(`
          html
          <r-input onchange="func(this.value)"></r-input>
          js
          const input = document.createElement('r-input');
           input.setAttribute('label', 'home');
           const func = (e) => {
             console.log(e);
          diff --git a/assets/cn_src_ranui_loading_index.md.CA72DxYe.js b/assets/cn_src_ranui_loading_index.md.CO9CpYNH.js
          similarity index 97%
          rename from assets/cn_src_ranui_loading_index.md.CA72DxYe.js
          rename to assets/cn_src_ranui_loading_index.md.CO9CpYNH.js
          index 8cfd1695dd..e1fd943eb0 100644
          --- a/assets/cn_src_ranui_loading_index.md.CA72DxYe.js
          +++ b/assets/cn_src_ranui_loading_index.md.CO9CpYNH.js
          @@ -1,4 +1,4 @@
          -import{_ as a}from"./chunks/loading.vue_vue_type_style_index_0_lang.DqjXTuVA.js";import{o as s,c as t,a3 as n,G as l}from"./chunks/framework.BYE6xntm.js";import"./chunks/index.h_46bJa8.js";const o=JSON.parse('{"title":"Loading","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/loading/index.md","filePath":"cn/src/ranui/loading/index.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranui/loading/index.md"},g=Object.assign(e,{setup(h){return(d,i)=>(s(),t("div",{"data-pagefind-body":!0},[i[0]||(i[0]=n(`

          Loading

          一些好看的 loading

          Code demo

          xml
          <r-loading name="circle"></r-loading>

          属性

          name

          这里有很多好看的 loading,可供选择

          xml
          <r-loading name="double-bounce"></r-loading>
          +import{_ as a}from"./chunks/loading.vue_vue_type_style_index_0_lang.DqjXTuVA.js";import{o as s,c as t,a3 as n,G as l}from"./chunks/framework.BYE6xntm.js";import"./chunks/index.h_46bJa8.js";const o=JSON.parse('{"title":"Loading","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/loading/index.md","filePath":"cn/src/ranui/loading/index.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranui/loading/index.md"},g=Object.assign(e,{setup(h){return(d,i)=>(s(),t("div",{"data-pagefind-body":!0},[i[0]||(i[0]=n(`

          Loading

          一些好看的 loading

          Code demo

          xml
          <r-loading name="circle"></r-loading>

          属性

          name

          这里有很多好看的 loading,可供选择

          xml
          <r-loading name="double-bounce"></r-loading>
           <r-loading name="rotate"></r-loading>
           <r-loading name="stretch"></r-loading>
           <r-loading name="cube"></r-loading>

          Loading list

          `,14)),l(a)]))}});export{o as __pageData,g as default}; diff --git a/assets/cn_src_ranui_loading_index.md.CA72DxYe.lean.js b/assets/cn_src_ranui_loading_index.md.CO9CpYNH.lean.js similarity index 97% rename from assets/cn_src_ranui_loading_index.md.CA72DxYe.lean.js rename to assets/cn_src_ranui_loading_index.md.CO9CpYNH.lean.js index 8cfd1695dd..e1fd943eb0 100644 --- a/assets/cn_src_ranui_loading_index.md.CA72DxYe.lean.js +++ b/assets/cn_src_ranui_loading_index.md.CO9CpYNH.lean.js @@ -1,4 +1,4 @@ -import{_ as a}from"./chunks/loading.vue_vue_type_style_index_0_lang.DqjXTuVA.js";import{o as s,c as t,a3 as n,G as l}from"./chunks/framework.BYE6xntm.js";import"./chunks/index.h_46bJa8.js";const o=JSON.parse('{"title":"Loading","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/loading/index.md","filePath":"cn/src/ranui/loading/index.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranui/loading/index.md"},g=Object.assign(e,{setup(h){return(d,i)=>(s(),t("div",{"data-pagefind-body":!0},[i[0]||(i[0]=n(`

          Loading

          一些好看的 loading

          Code demo

          xml
          <r-loading name="circle"></r-loading>

          属性

          name

          这里有很多好看的 loading,可供选择

          xml
          <r-loading name="double-bounce"></r-loading>
          +import{_ as a}from"./chunks/loading.vue_vue_type_style_index_0_lang.DqjXTuVA.js";import{o as s,c as t,a3 as n,G as l}from"./chunks/framework.BYE6xntm.js";import"./chunks/index.h_46bJa8.js";const o=JSON.parse('{"title":"Loading","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/loading/index.md","filePath":"cn/src/ranui/loading/index.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranui/loading/index.md"},g=Object.assign(e,{setup(h){return(d,i)=>(s(),t("div",{"data-pagefind-body":!0},[i[0]||(i[0]=n(`

          Loading

          一些好看的 loading

          Code demo

          xml
          <r-loading name="circle"></r-loading>

          属性

          name

          这里有很多好看的 loading,可供选择

          xml
          <r-loading name="double-bounce"></r-loading>
           <r-loading name="rotate"></r-loading>
           <r-loading name="stretch"></r-loading>
           <r-loading name="cube"></r-loading>

          Loading list

          `,14)),l(a)]))}});export{o as __pageData,g as default}; diff --git a/assets/cn_src_ranui_math_index.md.VRI2riCL.js b/assets/cn_src_ranui_math_index.md.DmcvA4-2.js similarity index 97% rename from assets/cn_src_ranui_math_index.md.VRI2riCL.js rename to assets/cn_src_ranui_math_index.md.DmcvA4-2.js index 66addab495..0eeccba44b 100644 --- a/assets/cn_src_ranui_math_index.md.VRI2riCL.js +++ b/assets/cn_src_ranui_math_index.md.DmcvA4-2.js @@ -1 +1 @@ -import{_ as e,o as l,c as n,j as a,a as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"math 数学公式","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/math/index.md","filePath":"cn/src/ranui/math/index.md","lastUpdated":1728828157000}'),h={name:"cn/src/ranui/math/index.md"};function r(d,t,p,k,o,c){return l(),n("div",{"data-pagefind-body":!0},t[0]||(t[0]=[a("h1",{id:"math-数学公式",tabindex:"-1"},[s("math 数学公式 "),a("a",{class:"header-anchor",href:"#math-数学公式","aria-label":'Permalink to "math 数学公式"'},"​")],-1),a("p",null,[s("在 "),a("code",null,"HTML"),s(" 页面中高质量展示 "),a("code",null,"LaTeX"),s(" 数学公式")],-1),a("h2",{id:"代码演示",tabindex:"-1"},[s("代码演示 "),a("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),a("r-math",{latex:"\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"},null,-1),i('
          xml
          <r-math latex="\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"></r-math>

          属性

          latex string

          ',3),a("r-math",{latex:"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"},null,-1),i('
          xml
            <r-math latex="x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"></r-math>
          ',1)]))}const m=e(h,[["render",r]]);export{E as __pageData,m as default}; +import{_ as e,o as l,c as n,j as a,a as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"math 数学公式","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/math/index.md","filePath":"cn/src/ranui/math/index.md","lastUpdated":1728921295000}'),h={name:"cn/src/ranui/math/index.md"};function r(d,t,p,k,o,c){return l(),n("div",{"data-pagefind-body":!0},t[0]||(t[0]=[a("h1",{id:"math-数学公式",tabindex:"-1"},[s("math 数学公式 "),a("a",{class:"header-anchor",href:"#math-数学公式","aria-label":'Permalink to "math 数学公式"'},"​")],-1),a("p",null,[s("在 "),a("code",null,"HTML"),s(" 页面中高质量展示 "),a("code",null,"LaTeX"),s(" 数学公式")],-1),a("h2",{id:"代码演示",tabindex:"-1"},[s("代码演示 "),a("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),a("r-math",{latex:"\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"},null,-1),i('
          xml
          <r-math latex="\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"></r-math>

          属性

          latex string

          ',3),a("r-math",{latex:"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"},null,-1),i('
          xml
            <r-math latex="x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"></r-math>
          ',1)]))}const m=e(h,[["render",r]]);export{E as __pageData,m as default}; diff --git a/assets/cn_src_ranui_math_index.md.VRI2riCL.lean.js b/assets/cn_src_ranui_math_index.md.DmcvA4-2.lean.js similarity index 97% rename from assets/cn_src_ranui_math_index.md.VRI2riCL.lean.js rename to assets/cn_src_ranui_math_index.md.DmcvA4-2.lean.js index 66addab495..0eeccba44b 100644 --- a/assets/cn_src_ranui_math_index.md.VRI2riCL.lean.js +++ b/assets/cn_src_ranui_math_index.md.DmcvA4-2.lean.js @@ -1 +1 @@ -import{_ as e,o as l,c as n,j as a,a as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"math 数学公式","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/math/index.md","filePath":"cn/src/ranui/math/index.md","lastUpdated":1728828157000}'),h={name:"cn/src/ranui/math/index.md"};function r(d,t,p,k,o,c){return l(),n("div",{"data-pagefind-body":!0},t[0]||(t[0]=[a("h1",{id:"math-数学公式",tabindex:"-1"},[s("math 数学公式 "),a("a",{class:"header-anchor",href:"#math-数学公式","aria-label":'Permalink to "math 数学公式"'},"​")],-1),a("p",null,[s("在 "),a("code",null,"HTML"),s(" 页面中高质量展示 "),a("code",null,"LaTeX"),s(" 数学公式")],-1),a("h2",{id:"代码演示",tabindex:"-1"},[s("代码演示 "),a("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),a("r-math",{latex:"\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"},null,-1),i('
          xml
          <r-math latex="\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"></r-math>

          属性

          latex string

          ',3),a("r-math",{latex:"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"},null,-1),i('
          xml
            <r-math latex="x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"></r-math>
          ',1)]))}const m=e(h,[["render",r]]);export{E as __pageData,m as default}; +import{_ as e,o as l,c as n,j as a,a as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"math 数学公式","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/math/index.md","filePath":"cn/src/ranui/math/index.md","lastUpdated":1728921295000}'),h={name:"cn/src/ranui/math/index.md"};function r(d,t,p,k,o,c){return l(),n("div",{"data-pagefind-body":!0},t[0]||(t[0]=[a("h1",{id:"math-数学公式",tabindex:"-1"},[s("math 数学公式 "),a("a",{class:"header-anchor",href:"#math-数学公式","aria-label":'Permalink to "math 数学公式"'},"​")],-1),a("p",null,[s("在 "),a("code",null,"HTML"),s(" 页面中高质量展示 "),a("code",null,"LaTeX"),s(" 数学公式")],-1),a("h2",{id:"代码演示",tabindex:"-1"},[s("代码演示 "),a("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),a("r-math",{latex:"\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"},null,-1),i('
          xml
          <r-math latex="\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"></r-math>

          属性

          latex string

          ',3),a("r-math",{latex:"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"},null,-1),i('
          xml
            <r-math latex="x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"></r-math>
          ',1)]))}const m=e(h,[["render",r]]);export{E as __pageData,m as default}; diff --git a/assets/cn_src_ranui_message_index.md.C38PI1jt.js b/assets/cn_src_ranui_message_index.md.DQuTGF50.js similarity index 99% rename from assets/cn_src_ranui_message_index.md.C38PI1jt.js rename to assets/cn_src_ranui_message_index.md.DQuTGF50.js index d0d4e8c51c..5097541fc6 100644 --- a/assets/cn_src_ranui_message_index.md.C38PI1jt.js +++ b/assets/cn_src_ranui_message_index.md.DQuTGF50.js @@ -1,4 +1,4 @@ -import{_ as e,o as n,c as h,j as s,a,a3 as t}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"message 全局提示","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/message/index.md","filePath":"cn/src/ranui/message/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranui/message/index.md"};function k(p,i,r,d,o,g){return n(),h("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"message-全局提示",tabindex:"-1"},[a("message 全局提示 "),s("a",{class:"header-anchor",href:"#message-全局提示","aria-label":'Permalink to "message 全局提示"'},"​")],-1),s("p",null,"全局展示操作反馈信息。",-1),s("h2",{id:"代码演示",tabindex:"-1"},[a("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{type:"primary",onclick:"message.info('这是一条提示')"},"点击触发全局提示")],-1),t('
          xml
          <r-button type="primary" onclick="message.info('这是一条提示')">点击触发全局提示</r-button>

          属性

          类型type

          不同的提示类型

          ',4),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.info('这是一条提示')"},"信息提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.warning('这是一条提示')"},"警告提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.error('这是一条提示')"},"错误提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.success('这是一条提示')"},"成功提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.toast('这是一条提示')"},"toast提示")],-1),t(`
          html
          <r-button onclick="message.info('这是一条提示')">信息提示</r-button>
          +import{_ as e,o as n,c as h,j as s,a,a3 as t}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"message 全局提示","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/message/index.md","filePath":"cn/src/ranui/message/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranui/message/index.md"};function k(p,i,r,d,o,g){return n(),h("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"message-全局提示",tabindex:"-1"},[a("message 全局提示 "),s("a",{class:"header-anchor",href:"#message-全局提示","aria-label":'Permalink to "message 全局提示"'},"​")],-1),s("p",null,"全局展示操作反馈信息。",-1),s("h2",{id:"代码演示",tabindex:"-1"},[a("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{type:"primary",onclick:"message.info('这是一条提示')"},"点击触发全局提示")],-1),t('
          xml
          <r-button type="primary" onclick="message.info('这是一条提示')">点击触发全局提示</r-button>

          属性

          类型type

          不同的提示类型

          ',4),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.info('这是一条提示')"},"信息提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.warning('这是一条提示')"},"警告提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.error('这是一条提示')"},"错误提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.success('这是一条提示')"},"成功提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.toast('这是一条提示')"},"toast提示")],-1),t(`
          html
          <r-button onclick="message.info('这是一条提示')">信息提示</r-button>
           <r-button onclick="message.warning('这是一条提示')">警告提示</r-button>
           <r-button onclick="message.error('这是一条提示')">错误提示</r-button>
           <r-button onclick="message.success('这是一条提示')">成功提示</r-button>
          diff --git a/assets/cn_src_ranui_message_index.md.C38PI1jt.lean.js b/assets/cn_src_ranui_message_index.md.DQuTGF50.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_message_index.md.C38PI1jt.lean.js
          rename to assets/cn_src_ranui_message_index.md.DQuTGF50.lean.js
          index d0d4e8c51c..5097541fc6 100644
          --- a/assets/cn_src_ranui_message_index.md.C38PI1jt.lean.js
          +++ b/assets/cn_src_ranui_message_index.md.DQuTGF50.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as e,o as n,c as h,j as s,a,a3 as t}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"message 全局提示","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/message/index.md","filePath":"cn/src/ranui/message/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranui/message/index.md"};function k(p,i,r,d,o,g){return n(),h("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"message-全局提示",tabindex:"-1"},[a("message 全局提示 "),s("a",{class:"header-anchor",href:"#message-全局提示","aria-label":'Permalink to "message 全局提示"'},"​")],-1),s("p",null,"全局展示操作反馈信息。",-1),s("h2",{id:"代码演示",tabindex:"-1"},[a("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{type:"primary",onclick:"message.info('这是一条提示')"},"点击触发全局提示")],-1),t('
          xml
          <r-button type="primary" onclick="message.info('这是一条提示')">点击触发全局提示</r-button>

          属性

          类型type

          不同的提示类型

          ',4),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.info('这是一条提示')"},"信息提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.warning('这是一条提示')"},"警告提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.error('这是一条提示')"},"错误提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.success('这是一条提示')"},"成功提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.toast('这是一条提示')"},"toast提示")],-1),t(`
          html
          <r-button onclick="message.info('这是一条提示')">信息提示</r-button>
          +import{_ as e,o as n,c as h,j as s,a,a3 as t}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"message 全局提示","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/message/index.md","filePath":"cn/src/ranui/message/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranui/message/index.md"};function k(p,i,r,d,o,g){return n(),h("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"message-全局提示",tabindex:"-1"},[a("message 全局提示 "),s("a",{class:"header-anchor",href:"#message-全局提示","aria-label":'Permalink to "message 全局提示"'},"​")],-1),s("p",null,"全局展示操作反馈信息。",-1),s("h2",{id:"代码演示",tabindex:"-1"},[a("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{type:"primary",onclick:"message.info('这是一条提示')"},"点击触发全局提示")],-1),t('
          xml
          <r-button type="primary" onclick="message.info('这是一条提示')">点击触发全局提示</r-button>

          属性

          类型type

          不同的提示类型

          ',4),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.info('这是一条提示')"},"信息提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.warning('这是一条提示')"},"警告提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.error('这是一条提示')"},"错误提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.success('这是一条提示')"},"成功提示")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.toast('这是一条提示')"},"toast提示")],-1),t(`
          html
          <r-button onclick="message.info('这是一条提示')">信息提示</r-button>
           <r-button onclick="message.warning('这是一条提示')">警告提示</r-button>
           <r-button onclick="message.error('这是一条提示')">错误提示</r-button>
           <r-button onclick="message.success('这是一条提示')">成功提示</r-button>
          diff --git a/assets/cn_src_ranui_modal_index.md.I-C9OtVX.js b/assets/cn_src_ranui_modal_index.md.C7YyXb2j.js
          similarity index 84%
          rename from assets/cn_src_ranui_modal_index.md.I-C9OtVX.js
          rename to assets/cn_src_ranui_modal_index.md.C7YyXb2j.js
          index 785253dffd..cd88cff9eb 100644
          --- a/assets/cn_src_ranui_modal_index.md.I-C9OtVX.js
          +++ b/assets/cn_src_ranui_modal_index.md.C7YyXb2j.js
          @@ -1 +1 @@
          -import{_ as e,o as a,c as t}from"./chunks/framework.BYE6xntm.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/modal/index.md","filePath":"cn/src/ranui/modal/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranui/modal/index.md"};function r(c,o,s,d,i,m){return a(),t("div")}const _=e(n,[["render",r]]);export{l as __pageData,_ as default};
          +import{_ as e,o as a,c as t}from"./chunks/framework.BYE6xntm.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/modal/index.md","filePath":"cn/src/ranui/modal/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranui/modal/index.md"};function r(c,o,s,d,i,m){return a(),t("div")}const _=e(n,[["render",r]]);export{l as __pageData,_ as default};
          diff --git a/assets/cn_src_ranui_modal_index.md.I-C9OtVX.lean.js b/assets/cn_src_ranui_modal_index.md.C7YyXb2j.lean.js
          similarity index 84%
          rename from assets/cn_src_ranui_modal_index.md.I-C9OtVX.lean.js
          rename to assets/cn_src_ranui_modal_index.md.C7YyXb2j.lean.js
          index 785253dffd..cd88cff9eb 100644
          --- a/assets/cn_src_ranui_modal_index.md.I-C9OtVX.lean.js
          +++ b/assets/cn_src_ranui_modal_index.md.C7YyXb2j.lean.js
          @@ -1 +1 @@
          -import{_ as e,o as a,c as t}from"./chunks/framework.BYE6xntm.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/modal/index.md","filePath":"cn/src/ranui/modal/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranui/modal/index.md"};function r(c,o,s,d,i,m){return a(),t("div")}const _=e(n,[["render",r]]);export{l as __pageData,_ as default};
          +import{_ as e,o as a,c as t}from"./chunks/framework.BYE6xntm.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/modal/index.md","filePath":"cn/src/ranui/modal/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranui/modal/index.md"};function r(c,o,s,d,i,m){return a(),t("div")}const _=e(n,[["render",r]]);export{l as __pageData,_ as default};
          diff --git a/assets/cn_src_ranui_player_index.md.CuAqghFD.js b/assets/cn_src_ranui_player_index.md.PhEE5Km4.js
          similarity index 99%
          rename from assets/cn_src_ranui_player_index.md.CuAqghFD.js
          rename to assets/cn_src_ranui_player_index.md.PhEE5Km4.js
          index 991f6d325e..e4a2d9d58a 100644
          --- a/assets/cn_src_ranui_player_index.md.CuAqghFD.js
          +++ b/assets/cn_src_ranui_player_index.md.PhEE5Km4.js
          @@ -1 +1 @@
          -import{_ as e,o as d,c as a,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"r-player 视频播放器","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/player/index.md","filePath":"cn/src/ranui/player/index.md","lastUpdated":1728828157000}'),i={name:"cn/src/ranui/player/index.md"};function l(o,t,n,s,h,c){return d(),a("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          r-player 视频播放器

          基于hlsjsweb components,让原生的标签r-player拥有统一的视频控件。 不采用new Player(options)的方式挂载到指定dom,视图的归视图,逻辑的归逻辑,所见及所得,更加直观。

          1. 可拖拽进度条
          2. 音量控制
          3. 根据当前带宽自适应码率切换
          4. 手动清晰度切换
          5. 倍速播放
          6. 样式自定义覆盖
          7. hls协议标准加密视频播放
          8. 基于原生开发,可在所有框架运行,统一跨框架情况
          9. 各浏览器控件统一

          代码演示

          xml
            <r-player src="/ran/hls/example.m3u8"></r-player>

          属性

          src

          视频的资源地址

          volume

          设置初始音量,默认 0.5

          currentTime

          设置初始播放时间,默认从头开始播放

          playbackRate

          设置倍速,默认 1.0

          debug

          控制台会打印输出一些信息

          事件event

          onchange

          监听任何播放器发生的变化,返回的值如下。

          可通过这个方法获得播放器的实例

          活着通过type判断不同的事件类型,进行不同的操作

          属性说明类型
          type发生变化的事件类型string
          data事件的值Object
          currentTime播放的当前时间number
          duration视频的总时长number
          tag播放器的实例Element

          其中type类型有

          名称说明
          canplay浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容。
          canplaythrough浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束。
          completeOfflineAudioContext 渲染完成。
          durationchangeduration 属性的值改变时触发。
          emptied媒体内容变为空;例如,当这个 media 已经加载完成(或者部分加载完成),则发送此事件,并调用 load() 方法重新加载它。
          ended视频停止播放,因为 media 已经到达结束点。
          loadedmetadata已加载元数据。
          progress在浏览器加载资源时周期性触发。
          ratechange播放速率发生变化。
          seeked跳帧(seek)操作完成。
          seeking跳帧(seek)操作开始。
          stalled用户代理(user agent)正在尝试获取媒体数据,但数据意外未出现。
          suspend媒体数据加载已暂停。
          loadeddatamedia 中的首帧已经完成加载。
          timeupdatecurrentTime 属性指定的时间发生变化。
          volumechange音量发生变化。
          waiting由于暂时缺少数据,播放已停止。
          play播放已开始。
          playing由于缺乏数据而暂停或延迟后,播放准备开始。
          pause播放已暂停。
          volume音量发生变化。
          fullscreen触发全屏事件
          ',25)]))}const m=e(i,[["render",l]]);export{u as __pageData,m as default}; +import{_ as e,o as d,c as a,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"r-player 视频播放器","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/player/index.md","filePath":"cn/src/ranui/player/index.md","lastUpdated":1728921295000}'),i={name:"cn/src/ranui/player/index.md"};function l(o,t,n,s,h,c){return d(),a("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          r-player 视频播放器

          基于hlsjsweb components,让原生的标签r-player拥有统一的视频控件。 不采用new Player(options)的方式挂载到指定dom,视图的归视图,逻辑的归逻辑,所见及所得,更加直观。

          1. 可拖拽进度条
          2. 音量控制
          3. 根据当前带宽自适应码率切换
          4. 手动清晰度切换
          5. 倍速播放
          6. 样式自定义覆盖
          7. hls协议标准加密视频播放
          8. 基于原生开发,可在所有框架运行,统一跨框架情况
          9. 各浏览器控件统一

          代码演示

          xml
            <r-player src="/ran/hls/example.m3u8"></r-player>

          属性

          src

          视频的资源地址

          volume

          设置初始音量,默认 0.5

          currentTime

          设置初始播放时间,默认从头开始播放

          playbackRate

          设置倍速,默认 1.0

          debug

          控制台会打印输出一些信息

          事件event

          onchange

          监听任何播放器发生的变化,返回的值如下。

          可通过这个方法获得播放器的实例

          活着通过type判断不同的事件类型,进行不同的操作

          属性说明类型
          type发生变化的事件类型string
          data事件的值Object
          currentTime播放的当前时间number
          duration视频的总时长number
          tag播放器的实例Element

          其中type类型有

          名称说明
          canplay浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容。
          canplaythrough浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束。
          completeOfflineAudioContext 渲染完成。
          durationchangeduration 属性的值改变时触发。
          emptied媒体内容变为空;例如,当这个 media 已经加载完成(或者部分加载完成),则发送此事件,并调用 load() 方法重新加载它。
          ended视频停止播放,因为 media 已经到达结束点。
          loadedmetadata已加载元数据。
          progress在浏览器加载资源时周期性触发。
          ratechange播放速率发生变化。
          seeked跳帧(seek)操作完成。
          seeking跳帧(seek)操作开始。
          stalled用户代理(user agent)正在尝试获取媒体数据,但数据意外未出现。
          suspend媒体数据加载已暂停。
          loadeddatamedia 中的首帧已经完成加载。
          timeupdatecurrentTime 属性指定的时间发生变化。
          volumechange音量发生变化。
          waiting由于暂时缺少数据,播放已停止。
          play播放已开始。
          playing由于缺乏数据而暂停或延迟后,播放准备开始。
          pause播放已暂停。
          volume音量发生变化。
          fullscreen触发全屏事件
          ',25)]))}const m=e(i,[["render",l]]);export{u as __pageData,m as default}; diff --git a/assets/cn_src_ranui_player_index.md.CuAqghFD.lean.js b/assets/cn_src_ranui_player_index.md.PhEE5Km4.lean.js similarity index 99% rename from assets/cn_src_ranui_player_index.md.CuAqghFD.lean.js rename to assets/cn_src_ranui_player_index.md.PhEE5Km4.lean.js index 991f6d325e..e4a2d9d58a 100644 --- a/assets/cn_src_ranui_player_index.md.CuAqghFD.lean.js +++ b/assets/cn_src_ranui_player_index.md.PhEE5Km4.lean.js @@ -1 +1 @@ -import{_ as e,o as d,c as a,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"r-player 视频播放器","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/player/index.md","filePath":"cn/src/ranui/player/index.md","lastUpdated":1728828157000}'),i={name:"cn/src/ranui/player/index.md"};function l(o,t,n,s,h,c){return d(),a("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          r-player 视频播放器

          基于hlsjsweb components,让原生的标签r-player拥有统一的视频控件。 不采用new Player(options)的方式挂载到指定dom,视图的归视图,逻辑的归逻辑,所见及所得,更加直观。

          1. 可拖拽进度条
          2. 音量控制
          3. 根据当前带宽自适应码率切换
          4. 手动清晰度切换
          5. 倍速播放
          6. 样式自定义覆盖
          7. hls协议标准加密视频播放
          8. 基于原生开发,可在所有框架运行,统一跨框架情况
          9. 各浏览器控件统一

          代码演示

          xml
            <r-player src="/ran/hls/example.m3u8"></r-player>

          属性

          src

          视频的资源地址

          volume

          设置初始音量,默认 0.5

          currentTime

          设置初始播放时间,默认从头开始播放

          playbackRate

          设置倍速,默认 1.0

          debug

          控制台会打印输出一些信息

          事件event

          onchange

          监听任何播放器发生的变化,返回的值如下。

          可通过这个方法获得播放器的实例

          活着通过type判断不同的事件类型,进行不同的操作

          属性说明类型
          type发生变化的事件类型string
          data事件的值Object
          currentTime播放的当前时间number
          duration视频的总时长number
          tag播放器的实例Element

          其中type类型有

          名称说明
          canplay浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容。
          canplaythrough浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束。
          completeOfflineAudioContext 渲染完成。
          durationchangeduration 属性的值改变时触发。
          emptied媒体内容变为空;例如,当这个 media 已经加载完成(或者部分加载完成),则发送此事件,并调用 load() 方法重新加载它。
          ended视频停止播放,因为 media 已经到达结束点。
          loadedmetadata已加载元数据。
          progress在浏览器加载资源时周期性触发。
          ratechange播放速率发生变化。
          seeked跳帧(seek)操作完成。
          seeking跳帧(seek)操作开始。
          stalled用户代理(user agent)正在尝试获取媒体数据,但数据意外未出现。
          suspend媒体数据加载已暂停。
          loadeddatamedia 中的首帧已经完成加载。
          timeupdatecurrentTime 属性指定的时间发生变化。
          volumechange音量发生变化。
          waiting由于暂时缺少数据,播放已停止。
          play播放已开始。
          playing由于缺乏数据而暂停或延迟后,播放准备开始。
          pause播放已暂停。
          volume音量发生变化。
          fullscreen触发全屏事件
          ',25)]))}const m=e(i,[["render",l]]);export{u as __pageData,m as default}; +import{_ as e,o as d,c as a,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"r-player 视频播放器","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/player/index.md","filePath":"cn/src/ranui/player/index.md","lastUpdated":1728921295000}'),i={name:"cn/src/ranui/player/index.md"};function l(o,t,n,s,h,c){return d(),a("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          r-player 视频播放器

          基于hlsjsweb components,让原生的标签r-player拥有统一的视频控件。 不采用new Player(options)的方式挂载到指定dom,视图的归视图,逻辑的归逻辑,所见及所得,更加直观。

          1. 可拖拽进度条
          2. 音量控制
          3. 根据当前带宽自适应码率切换
          4. 手动清晰度切换
          5. 倍速播放
          6. 样式自定义覆盖
          7. hls协议标准加密视频播放
          8. 基于原生开发,可在所有框架运行,统一跨框架情况
          9. 各浏览器控件统一

          代码演示

          xml
            <r-player src="/ran/hls/example.m3u8"></r-player>

          属性

          src

          视频的资源地址

          volume

          设置初始音量,默认 0.5

          currentTime

          设置初始播放时间,默认从头开始播放

          playbackRate

          设置倍速,默认 1.0

          debug

          控制台会打印输出一些信息

          事件event

          onchange

          监听任何播放器发生的变化,返回的值如下。

          可通过这个方法获得播放器的实例

          活着通过type判断不同的事件类型,进行不同的操作

          属性说明类型
          type发生变化的事件类型string
          data事件的值Object
          currentTime播放的当前时间number
          duration视频的总时长number
          tag播放器的实例Element

          其中type类型有

          名称说明
          canplay浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容。
          canplaythrough浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束。
          completeOfflineAudioContext 渲染完成。
          durationchangeduration 属性的值改变时触发。
          emptied媒体内容变为空;例如,当这个 media 已经加载完成(或者部分加载完成),则发送此事件,并调用 load() 方法重新加载它。
          ended视频停止播放,因为 media 已经到达结束点。
          loadedmetadata已加载元数据。
          progress在浏览器加载资源时周期性触发。
          ratechange播放速率发生变化。
          seeked跳帧(seek)操作完成。
          seeking跳帧(seek)操作开始。
          stalled用户代理(user agent)正在尝试获取媒体数据,但数据意外未出现。
          suspend媒体数据加载已暂停。
          loadeddatamedia 中的首帧已经完成加载。
          timeupdatecurrentTime 属性指定的时间发生变化。
          volumechange音量发生变化。
          waiting由于暂时缺少数据,播放已停止。
          play播放已开始。
          playing由于缺乏数据而暂停或延迟后,播放准备开始。
          pause播放已暂停。
          volume音量发生变化。
          fullscreen触发全屏事件
          ',25)]))}const m=e(i,[["render",l]]);export{u as __pageData,m as default}; diff --git a/assets/cn_src_ranui_popover_index.md.DRuLc3Ni.js b/assets/cn_src_ranui_popover_index.md.BNd4uUYL.js similarity index 99% rename from assets/cn_src_ranui_popover_index.md.DRuLc3Ni.js rename to assets/cn_src_ranui_popover_index.md.BNd4uUYL.js index 248dc47279..0e07c59d1b 100644 --- a/assets/cn_src_ranui_popover_index.md.DRuLc3Ni.js +++ b/assets/cn_src_ranui_popover_index.md.BNd4uUYL.js @@ -1,4 +1,4 @@ -import{_ as t,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Popover 气泡卡片","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/popover/index.md","filePath":"cn/src/ranui/popover/index.md","lastUpdated":1728828157000}'),h={name:"cn/src/ranui/popover/index.md"};function p(k,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Popover 气泡卡片

          点击/鼠标移入元素,弹出气泡式的卡片浮层。

          代码演示

          popover
          this is content
          xml
          <r-popover>
          +import{_ as t,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Popover 气泡卡片","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/popover/index.md","filePath":"cn/src/ranui/popover/index.md","lastUpdated":1728921295000}'),h={name:"cn/src/ranui/popover/index.md"};function p(k,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Popover 气泡卡片

          点击/鼠标移入元素,弹出气泡式的卡片浮层。

          代码演示

          popover
          this is content
          xml
          <r-popover>
               <r-button>popover</r-button>
               <r-content>
                 <div>this is content</div>
          diff --git a/assets/cn_src_ranui_popover_index.md.DRuLc3Ni.lean.js b/assets/cn_src_ranui_popover_index.md.BNd4uUYL.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_popover_index.md.DRuLc3Ni.lean.js
          rename to assets/cn_src_ranui_popover_index.md.BNd4uUYL.lean.js
          index 248dc47279..0e07c59d1b 100644
          --- a/assets/cn_src_ranui_popover_index.md.DRuLc3Ni.lean.js
          +++ b/assets/cn_src_ranui_popover_index.md.BNd4uUYL.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as t,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Popover 气泡卡片","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/popover/index.md","filePath":"cn/src/ranui/popover/index.md","lastUpdated":1728828157000}'),h={name:"cn/src/ranui/popover/index.md"};function p(k,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Popover 气泡卡片

          点击/鼠标移入元素,弹出气泡式的卡片浮层。

          代码演示

          popover
          this is content
          xml
          <r-popover>
          +import{_ as t,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Popover 气泡卡片","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/popover/index.md","filePath":"cn/src/ranui/popover/index.md","lastUpdated":1728921295000}'),h={name:"cn/src/ranui/popover/index.md"};function p(k,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Popover 气泡卡片

          点击/鼠标移入元素,弹出气泡式的卡片浮层。

          代码演示

          popover
          this is content
          xml
          <r-popover>
               <r-button>popover</r-button>
               <r-content>
                 <div>this is content</div>
          diff --git a/assets/cn_src_ranui_preview_index.md.BsAShiRh.js b/assets/cn_src_ranui_preview_index.md.CjuF-KUm.js
          similarity index 99%
          rename from assets/cn_src_ranui_preview_index.md.BsAShiRh.js
          rename to assets/cn_src_ranui_preview_index.md.CjuF-KUm.js
          index 699ced7737..e1c38635aa 100644
          --- a/assets/cn_src_ranui_preview_index.md.BsAShiRh.js
          +++ b/assets/cn_src_ranui_preview_index.md.CjuF-KUm.js
          @@ -1,4 +1,4 @@
          -import{_ as h,o as t,c as n,a3 as a,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"preview 文件预览","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/preview/index.md","filePath":"cn/src/ranui/preview/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranui/preview/index.md"};function k(p,i,e,E,r,d){return t(),n("div",{"data-pagefind-body":!0},i[0]||(i[0]=[a('

          preview 文件预览

          支持docxpptxpdf,xlsx文件的预览

          代码演示

          ',3),s("div",{style:{width:"100px","margin-top":"10px"}},[s("r-preview",{id:"fhdjskafk"}),s("r-button",{type:"primary",onclick:"uploadFile('fhdjskafk')"},"choose file to preview")],-1),a(`
          html
          <r-preview id="preview"></r-preview>
          +import{_ as h,o as t,c as n,a3 as a,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"preview 文件预览","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/preview/index.md","filePath":"cn/src/ranui/preview/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranui/preview/index.md"};function k(p,i,e,E,r,d){return t(),n("div",{"data-pagefind-body":!0},i[0]||(i[0]=[a('

          preview 文件预览

          支持docxpptxpdf,xlsx文件的预览

          代码演示

          ',3),s("div",{style:{width:"100px","margin-top":"10px"}},[s("r-preview",{id:"fhdjskafk"}),s("r-button",{type:"primary",onclick:"uploadFile('fhdjskafk')"},"choose file to preview")],-1),a(`
          html
          <r-preview id="preview"></r-preview>
           <r-button type="primary" onclick="uploadFile()">choose file to preview</r-button>
           
           <script>
          diff --git a/assets/cn_src_ranui_preview_index.md.BsAShiRh.lean.js b/assets/cn_src_ranui_preview_index.md.CjuF-KUm.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_preview_index.md.BsAShiRh.lean.js
          rename to assets/cn_src_ranui_preview_index.md.CjuF-KUm.lean.js
          index 699ced7737..e1c38635aa 100644
          --- a/assets/cn_src_ranui_preview_index.md.BsAShiRh.lean.js
          +++ b/assets/cn_src_ranui_preview_index.md.CjuF-KUm.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as h,o as t,c as n,a3 as a,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"preview 文件预览","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/preview/index.md","filePath":"cn/src/ranui/preview/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranui/preview/index.md"};function k(p,i,e,E,r,d){return t(),n("div",{"data-pagefind-body":!0},i[0]||(i[0]=[a('

          preview 文件预览

          支持docxpptxpdf,xlsx文件的预览

          代码演示

          ',3),s("div",{style:{width:"100px","margin-top":"10px"}},[s("r-preview",{id:"fhdjskafk"}),s("r-button",{type:"primary",onclick:"uploadFile('fhdjskafk')"},"choose file to preview")],-1),a(`
          html
          <r-preview id="preview"></r-preview>
          +import{_ as h,o as t,c as n,a3 as a,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"preview 文件预览","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/preview/index.md","filePath":"cn/src/ranui/preview/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranui/preview/index.md"};function k(p,i,e,E,r,d){return t(),n("div",{"data-pagefind-body":!0},i[0]||(i[0]=[a('

          preview 文件预览

          支持docxpptxpdf,xlsx文件的预览

          代码演示

          ',3),s("div",{style:{width:"100px","margin-top":"10px"}},[s("r-preview",{id:"fhdjskafk"}),s("r-button",{type:"primary",onclick:"uploadFile('fhdjskafk')"},"choose file to preview")],-1),a(`
          html
          <r-preview id="preview"></r-preview>
           <r-button type="primary" onclick="uploadFile()">choose file to preview</r-button>
           
           <script>
          diff --git a/assets/cn_src_ranui_progress_index.md.m21IXa5G.js b/assets/cn_src_ranui_progress_index.md.CLS6wwle.js
          similarity index 99%
          rename from assets/cn_src_ranui_progress_index.md.m21IXa5G.js
          rename to assets/cn_src_ranui_progress_index.md.CLS6wwle.js
          index 4034816233..6e01063b70 100644
          --- a/assets/cn_src_ranui_progress_index.md.m21IXa5G.js
          +++ b/assets/cn_src_ranui_progress_index.md.CLS6wwle.js
          @@ -1 +1 @@
          -import{_ as t,o as h,c as e,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"progress 进度条","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/progress/index.md","filePath":"cn/src/ranui/progress/index.md","lastUpdated":1728828157000}'),p={name:"cn/src/ranui/progress/index.md"};function l(n,a,k,r,d,E){return h(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          progress 进度条

          可交互的进度条

          代码演示

          xml
          <r-progress type="drag" ></r-progress>

          属性

          总进度total

          设置进度条总进度,允许百分比和数字。

          ',8),s("r-progress",{percent:"30",total:"1000"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"70",total:"100"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"10%",total:"100%"},null,-1),i('
          html
          <r-progress percent="30" total="1000"></r-progress>\n<r-progress percent="70" total="100"></r-progress>\n<r-progress percent="10%" total="100%"></r-progress>

          当前进度percent

          设置进度条的当前进度,可以设置百分比和数字,percent不能超过total。如果不设置total,默认total100%也就是1

          ',3),s("r-progress",{type:"primary",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"70%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"100%"},null,-1),i('
          html
          <r-progress type="primary" percent="30%"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>\n<r-progress type="primary" percent="100%"></r-progress>

          进度条的点dot

          默认展示,设置成false可隐藏

          ',3),s("r-progress",{type:"drag",percent:"30%",dot:"false"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%",dot:"true"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
          html
          <r-progress type="drag" percent="30%" dot="false"></r-progress>\n<r-progress type="primary" percent="40%" dot="true"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>

          类型type

          • primary: 默认的进度条,不设置type属性是默认
          • drag: 可拖动,可点击的进度条(拖动需要设置dottrue
          ',3),s("r-progress",{type:"drag",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
          html
          <r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

          方法

          change

          percenttotal属性发生变化时,触发change事件。

          属性说明类型
          value当前进度string|number
          percent当前进度string|number
          total总进度string|number
          ',5)]))}const y=t(p,[["render",l]]);export{g as __pageData,y as default}; +import{_ as t,o as h,c as e,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"progress 进度条","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/progress/index.md","filePath":"cn/src/ranui/progress/index.md","lastUpdated":1728921295000}'),p={name:"cn/src/ranui/progress/index.md"};function l(n,a,k,r,d,E){return h(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          progress 进度条

          可交互的进度条

          代码演示

          xml
          <r-progress type="drag" ></r-progress>

          属性

          总进度total

          设置进度条总进度,允许百分比和数字。

          ',8),s("r-progress",{percent:"30",total:"1000"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"70",total:"100"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"10%",total:"100%"},null,-1),i('
          html
          <r-progress percent="30" total="1000"></r-progress>\n<r-progress percent="70" total="100"></r-progress>\n<r-progress percent="10%" total="100%"></r-progress>

          当前进度percent

          设置进度条的当前进度,可以设置百分比和数字,percent不能超过total。如果不设置total,默认total100%也就是1

          ',3),s("r-progress",{type:"primary",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"70%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"100%"},null,-1),i('
          html
          <r-progress type="primary" percent="30%"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>\n<r-progress type="primary" percent="100%"></r-progress>

          进度条的点dot

          默认展示,设置成false可隐藏

          ',3),s("r-progress",{type:"drag",percent:"30%",dot:"false"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%",dot:"true"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
          html
          <r-progress type="drag" percent="30%" dot="false"></r-progress>\n<r-progress type="primary" percent="40%" dot="true"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>

          类型type

          • primary: 默认的进度条,不设置type属性是默认
          • drag: 可拖动,可点击的进度条(拖动需要设置dottrue
          ',3),s("r-progress",{type:"drag",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
          html
          <r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

          方法

          change

          percenttotal属性发生变化时,触发change事件。

          属性说明类型
          value当前进度string|number
          percent当前进度string|number
          total总进度string|number
          ',5)]))}const y=t(p,[["render",l]]);export{g as __pageData,y as default}; diff --git a/assets/cn_src_ranui_progress_index.md.m21IXa5G.lean.js b/assets/cn_src_ranui_progress_index.md.CLS6wwle.lean.js similarity index 99% rename from assets/cn_src_ranui_progress_index.md.m21IXa5G.lean.js rename to assets/cn_src_ranui_progress_index.md.CLS6wwle.lean.js index 4034816233..6e01063b70 100644 --- a/assets/cn_src_ranui_progress_index.md.m21IXa5G.lean.js +++ b/assets/cn_src_ranui_progress_index.md.CLS6wwle.lean.js @@ -1 +1 @@ -import{_ as t,o as h,c as e,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"progress 进度条","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/progress/index.md","filePath":"cn/src/ranui/progress/index.md","lastUpdated":1728828157000}'),p={name:"cn/src/ranui/progress/index.md"};function l(n,a,k,r,d,E){return h(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          progress 进度条

          可交互的进度条

          代码演示

          xml
          <r-progress type="drag" ></r-progress>

          属性

          总进度total

          设置进度条总进度,允许百分比和数字。

          ',8),s("r-progress",{percent:"30",total:"1000"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"70",total:"100"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"10%",total:"100%"},null,-1),i('
          html
          <r-progress percent="30" total="1000"></r-progress>\n<r-progress percent="70" total="100"></r-progress>\n<r-progress percent="10%" total="100%"></r-progress>

          当前进度percent

          设置进度条的当前进度,可以设置百分比和数字,percent不能超过total。如果不设置total,默认total100%也就是1

          ',3),s("r-progress",{type:"primary",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"70%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"100%"},null,-1),i('
          html
          <r-progress type="primary" percent="30%"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>\n<r-progress type="primary" percent="100%"></r-progress>

          进度条的点dot

          默认展示,设置成false可隐藏

          ',3),s("r-progress",{type:"drag",percent:"30%",dot:"false"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%",dot:"true"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
          html
          <r-progress type="drag" percent="30%" dot="false"></r-progress>\n<r-progress type="primary" percent="40%" dot="true"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>

          类型type

          • primary: 默认的进度条,不设置type属性是默认
          • drag: 可拖动,可点击的进度条(拖动需要设置dottrue
          ',3),s("r-progress",{type:"drag",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
          html
          <r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

          方法

          change

          percenttotal属性发生变化时,触发change事件。

          属性说明类型
          value当前进度string|number
          percent当前进度string|number
          total总进度string|number
          ',5)]))}const y=t(p,[["render",l]]);export{g as __pageData,y as default}; +import{_ as t,o as h,c as e,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"progress 进度条","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/progress/index.md","filePath":"cn/src/ranui/progress/index.md","lastUpdated":1728921295000}'),p={name:"cn/src/ranui/progress/index.md"};function l(n,a,k,r,d,E){return h(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          progress 进度条

          可交互的进度条

          代码演示

          xml
          <r-progress type="drag" ></r-progress>

          属性

          总进度total

          设置进度条总进度,允许百分比和数字。

          ',8),s("r-progress",{percent:"30",total:"1000"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"70",total:"100"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"10%",total:"100%"},null,-1),i('
          html
          <r-progress percent="30" total="1000"></r-progress>\n<r-progress percent="70" total="100"></r-progress>\n<r-progress percent="10%" total="100%"></r-progress>

          当前进度percent

          设置进度条的当前进度,可以设置百分比和数字,percent不能超过total。如果不设置total,默认total100%也就是1

          ',3),s("r-progress",{type:"primary",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"70%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"100%"},null,-1),i('
          html
          <r-progress type="primary" percent="30%"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>\n<r-progress type="primary" percent="100%"></r-progress>

          进度条的点dot

          默认展示,设置成false可隐藏

          ',3),s("r-progress",{type:"drag",percent:"30%",dot:"false"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%",dot:"true"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
          html
          <r-progress type="drag" percent="30%" dot="false"></r-progress>\n<r-progress type="primary" percent="40%" dot="true"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>

          类型type

          • primary: 默认的进度条,不设置type属性是默认
          • drag: 可拖动,可点击的进度条(拖动需要设置dottrue
          ',3),s("r-progress",{type:"drag",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
          html
          <r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

          方法

          change

          percenttotal属性发生变化时,触发change事件。

          属性说明类型
          value当前进度string|number
          percent当前进度string|number
          total总进度string|number
          ',5)]))}const y=t(p,[["render",l]]);export{g as __pageData,y as default}; diff --git a/assets/cn_src_ranui_radar_index.md.A6jKbspG.js b/assets/cn_src_ranui_radar_index.md.BVnDbAlC.js similarity index 99% rename from assets/cn_src_ranui_radar_index.md.A6jKbspG.js rename to assets/cn_src_ranui_radar_index.md.BVnDbAlC.js index 3252d88a30..80c74d362a 100644 --- a/assets/cn_src_ranui_radar_index.md.A6jKbspG.js +++ b/assets/cn_src_ranui_radar_index.md.BVnDbAlC.js @@ -1,4 +1,4 @@ -import{_ as l,o as e,c as o,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"Radar 雷达图","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/radar/index.md","filePath":"cn/src/ranui/radar/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranui/radar/index.md"};function h(p,a,k,u,r,q){return e(),o("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"radar-雷达图",tabindex:"-1"},[t("Radar 雷达图 "),s("a",{class:"header-anchor",href:"#radar-雷达图","aria-label":'Permalink to "Radar 雷达图"'},"​")],-1),s("p",null,"以二维形式综合对比多组数据的差异,常用于比较 2 组或更多组数据集",-1),s("h2",{id:"代码演示",tabindex:"-1"},[t("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("r-radar",{style:{width:"300px",height:"300px",display:"block"},abilitys:'[{"abilityName":"生命","scoreRate":"10"},{"abilityName":"攻击","scoreRate":"90"},{"abilityName":"防御","scoreRate":"20"},{"abilityName":"元素精通","scoreRate":"50"},{"abilityName":"暴击率","scoreRate":"80"},{"abilityName":"暴击伤害","scoreRate":"50"}]'},null,-1),i(`
          xml
          <r-radar
          +import{_ as l,o as e,c as o,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"Radar 雷达图","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/radar/index.md","filePath":"cn/src/ranui/radar/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranui/radar/index.md"};function h(p,a,k,u,r,q){return e(),o("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"radar-雷达图",tabindex:"-1"},[t("Radar 雷达图 "),s("a",{class:"header-anchor",href:"#radar-雷达图","aria-label":'Permalink to "Radar 雷达图"'},"​")],-1),s("p",null,"以二维形式综合对比多组数据的差异,常用于比较 2 组或更多组数据集",-1),s("h2",{id:"代码演示",tabindex:"-1"},[t("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("r-radar",{style:{width:"300px",height:"300px",display:"block"},abilitys:'[{"abilityName":"生命","scoreRate":"10"},{"abilityName":"攻击","scoreRate":"90"},{"abilityName":"防御","scoreRate":"20"},{"abilityName":"元素精通","scoreRate":"50"},{"abilityName":"暴击率","scoreRate":"80"},{"abilityName":"暴击伤害","scoreRate":"50"}]'},null,-1),i(`
          xml
          <r-radar
               abilitys='[{"abilityName":"生命","scoreRate":"10"},{"abilityName":"攻击","scoreRate":"90"},{"abilityName":"防御","scoreRate":"20"},{"abilityName":"元素精通","scoreRate":"50"},{"abilityName":"暴击率","scoreRate":"80"},{"abilityName":"暴击伤害","scoreRate":"50"}]'
               style="width:300px;height:300px;display: block;"
           >
          diff --git a/assets/cn_src_ranui_radar_index.md.A6jKbspG.lean.js b/assets/cn_src_ranui_radar_index.md.BVnDbAlC.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_radar_index.md.A6jKbspG.lean.js
          rename to assets/cn_src_ranui_radar_index.md.BVnDbAlC.lean.js
          index 3252d88a30..80c74d362a 100644
          --- a/assets/cn_src_ranui_radar_index.md.A6jKbspG.lean.js
          +++ b/assets/cn_src_ranui_radar_index.md.BVnDbAlC.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as l,o as e,c as o,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"Radar 雷达图","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/radar/index.md","filePath":"cn/src/ranui/radar/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranui/radar/index.md"};function h(p,a,k,u,r,q){return e(),o("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"radar-雷达图",tabindex:"-1"},[t("Radar 雷达图 "),s("a",{class:"header-anchor",href:"#radar-雷达图","aria-label":'Permalink to "Radar 雷达图"'},"​")],-1),s("p",null,"以二维形式综合对比多组数据的差异,常用于比较 2 组或更多组数据集",-1),s("h2",{id:"代码演示",tabindex:"-1"},[t("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("r-radar",{style:{width:"300px",height:"300px",display:"block"},abilitys:'[{"abilityName":"生命","scoreRate":"10"},{"abilityName":"攻击","scoreRate":"90"},{"abilityName":"防御","scoreRate":"20"},{"abilityName":"元素精通","scoreRate":"50"},{"abilityName":"暴击率","scoreRate":"80"},{"abilityName":"暴击伤害","scoreRate":"50"}]'},null,-1),i(`
          xml
          <r-radar
          +import{_ as l,o as e,c as o,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"Radar 雷达图","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/radar/index.md","filePath":"cn/src/ranui/radar/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranui/radar/index.md"};function h(p,a,k,u,r,q){return e(),o("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"radar-雷达图",tabindex:"-1"},[t("Radar 雷达图 "),s("a",{class:"header-anchor",href:"#radar-雷达图","aria-label":'Permalink to "Radar 雷达图"'},"​")],-1),s("p",null,"以二维形式综合对比多组数据的差异,常用于比较 2 组或更多组数据集",-1),s("h2",{id:"代码演示",tabindex:"-1"},[t("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("r-radar",{style:{width:"300px",height:"300px",display:"block"},abilitys:'[{"abilityName":"生命","scoreRate":"10"},{"abilityName":"攻击","scoreRate":"90"},{"abilityName":"防御","scoreRate":"20"},{"abilityName":"元素精通","scoreRate":"50"},{"abilityName":"暴击率","scoreRate":"80"},{"abilityName":"暴击伤害","scoreRate":"50"}]'},null,-1),i(`
          xml
          <r-radar
               abilitys='[{"abilityName":"生命","scoreRate":"10"},{"abilityName":"攻击","scoreRate":"90"},{"abilityName":"防御","scoreRate":"20"},{"abilityName":"元素精通","scoreRate":"50"},{"abilityName":"暴击率","scoreRate":"80"},{"abilityName":"暴击伤害","scoreRate":"50"}]'
               style="width:300px;height:300px;display: block;"
           >
          diff --git a/assets/cn_src_ranui_select_index.md.CmisBOzA.js b/assets/cn_src_ranui_select_index.md.BygieB1y.js
          similarity index 99%
          rename from assets/cn_src_ranui_select_index.md.CmisBOzA.js
          rename to assets/cn_src_ranui_select_index.md.BygieB1y.js
          index c70aa2678e..8e628e8f94 100644
          --- a/assets/cn_src_ranui_select_index.md.CmisBOzA.js
          +++ b/assets/cn_src_ranui_select_index.md.BygieB1y.js
          @@ -1,4 +1,4 @@
          -import{_ as h,o as l,c as n,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Select 下拉选择框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/select/index.md","filePath":"cn/src/ranui/select/index.md","lastUpdated":1728828157000}'),k={name:"cn/src/ranui/select/index.md"};function p(e,a,E,r,d,o){return l(),n("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"select-下拉选择框",tabindex:"-1"},[t("Select 下拉选择框 "),s("a",{class:"header-anchor",href:"#select-下拉选择框","aria-label":'Permalink to "Select 下拉选择框"'},"​")],-1),s("p",null,"一个普通的下拉选择器。",-1),s("h2",{id:"代码演示",tabindex:"-1"},[t("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("r-select",{style:{width:"120px",height:"40px"},defaultValue:"185"},[s("r-option",{value:"185"},"Mike"),s("r-option",{value:"186"},"Tom"),s("r-option",{value:"187"},"Lucy")],-1),i(`
          xml
          <r-select style="width: 120px; height: 40px" defaultValue="185">
          +import{_ as h,o as l,c as n,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Select 下拉选择框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/select/index.md","filePath":"cn/src/ranui/select/index.md","lastUpdated":1728921295000}'),k={name:"cn/src/ranui/select/index.md"};function p(e,a,E,r,d,o){return l(),n("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"select-下拉选择框",tabindex:"-1"},[t("Select 下拉选择框 "),s("a",{class:"header-anchor",href:"#select-下拉选择框","aria-label":'Permalink to "Select 下拉选择框"'},"​")],-1),s("p",null,"一个普通的下拉选择器。",-1),s("h2",{id:"代码演示",tabindex:"-1"},[t("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("r-select",{style:{width:"120px",height:"40px"},defaultValue:"185"},[s("r-option",{value:"185"},"Mike"),s("r-option",{value:"186"},"Tom"),s("r-option",{value:"187"},"Lucy")],-1),i(`
          xml
          <r-select style="width: 120px; height: 40px" defaultValue="185">
                 <r-option value="185">Mike</r-option>
                 <r-option value="186">Tom</r-option>
                 <r-option value="187">Lucy</r-option>
          diff --git a/assets/cn_src_ranui_select_index.md.CmisBOzA.lean.js b/assets/cn_src_ranui_select_index.md.BygieB1y.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_select_index.md.CmisBOzA.lean.js
          rename to assets/cn_src_ranui_select_index.md.BygieB1y.lean.js
          index c70aa2678e..8e628e8f94 100644
          --- a/assets/cn_src_ranui_select_index.md.CmisBOzA.lean.js
          +++ b/assets/cn_src_ranui_select_index.md.BygieB1y.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as h,o as l,c as n,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Select 下拉选择框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/select/index.md","filePath":"cn/src/ranui/select/index.md","lastUpdated":1728828157000}'),k={name:"cn/src/ranui/select/index.md"};function p(e,a,E,r,d,o){return l(),n("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"select-下拉选择框",tabindex:"-1"},[t("Select 下拉选择框 "),s("a",{class:"header-anchor",href:"#select-下拉选择框","aria-label":'Permalink to "Select 下拉选择框"'},"​")],-1),s("p",null,"一个普通的下拉选择器。",-1),s("h2",{id:"代码演示",tabindex:"-1"},[t("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("r-select",{style:{width:"120px",height:"40px"},defaultValue:"185"},[s("r-option",{value:"185"},"Mike"),s("r-option",{value:"186"},"Tom"),s("r-option",{value:"187"},"Lucy")],-1),i(`
          xml
          <r-select style="width: 120px; height: 40px" defaultValue="185">
          +import{_ as h,o as l,c as n,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Select 下拉选择框","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/select/index.md","filePath":"cn/src/ranui/select/index.md","lastUpdated":1728921295000}'),k={name:"cn/src/ranui/select/index.md"};function p(e,a,E,r,d,o){return l(),n("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"select-下拉选择框",tabindex:"-1"},[t("Select 下拉选择框 "),s("a",{class:"header-anchor",href:"#select-下拉选择框","aria-label":'Permalink to "Select 下拉选择框"'},"​")],-1),s("p",null,"一个普通的下拉选择器。",-1),s("h2",{id:"代码演示",tabindex:"-1"},[t("代码演示 "),s("a",{class:"header-anchor",href:"#代码演示","aria-label":'Permalink to "代码演示"'},"​")],-1),s("r-select",{style:{width:"120px",height:"40px"},defaultValue:"185"},[s("r-option",{value:"185"},"Mike"),s("r-option",{value:"186"},"Tom"),s("r-option",{value:"187"},"Lucy")],-1),i(`
          xml
          <r-select style="width: 120px; height: 40px" defaultValue="185">
                 <r-option value="185">Mike</r-option>
                 <r-option value="186">Tom</r-option>
                 <r-option value="187">Lucy</r-option>
          diff --git a/assets/cn_src_ranui_skeleton_index.md.t-ZVwoSq.js b/assets/cn_src_ranui_skeleton_index.md.PVahOUCW.js
          similarity index 96%
          rename from assets/cn_src_ranui_skeleton_index.md.t-ZVwoSq.js
          rename to assets/cn_src_ranui_skeleton_index.md.PVahOUCW.js
          index 73e5e5b391..16c1d2ce9f 100644
          --- a/assets/cn_src_ranui_skeleton_index.md.t-ZVwoSq.js
          +++ b/assets/cn_src_ranui_skeleton_index.md.PVahOUCW.js
          @@ -1 +1 @@
          -import{_ as t,o as s,c as a,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"skeleton 骨架屏","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/skeleton/index.md","filePath":"cn/src/ranui/skeleton/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranui/skeleton/index.md"};function l(r,e,o,d,p,k){return s(),a("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

          skeleton 骨架屏

          在需要等待加载内容的位置提供一个占位图形组合。

          代码演示

          骨架长度跟随父级元素的长度

          xml
          <r-skeleton ></r-skeleton>
          ',9)]))}const g=t(n,[["render",l]]);export{c as __pageData,g as default}; +import{_ as t,o as s,c as a,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"skeleton 骨架屏","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/skeleton/index.md","filePath":"cn/src/ranui/skeleton/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranui/skeleton/index.md"};function l(r,e,o,d,p,k){return s(),a("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

          skeleton 骨架屏

          在需要等待加载内容的位置提供一个占位图形组合。

          代码演示

          骨架长度跟随父级元素的长度

          xml
          <r-skeleton ></r-skeleton>
          ',9)]))}const g=t(n,[["render",l]]);export{c as __pageData,g as default}; diff --git a/assets/cn_src_ranui_skeleton_index.md.t-ZVwoSq.lean.js b/assets/cn_src_ranui_skeleton_index.md.PVahOUCW.lean.js similarity index 96% rename from assets/cn_src_ranui_skeleton_index.md.t-ZVwoSq.lean.js rename to assets/cn_src_ranui_skeleton_index.md.PVahOUCW.lean.js index 73e5e5b391..16c1d2ce9f 100644 --- a/assets/cn_src_ranui_skeleton_index.md.t-ZVwoSq.lean.js +++ b/assets/cn_src_ranui_skeleton_index.md.PVahOUCW.lean.js @@ -1 +1 @@ -import{_ as t,o as s,c as a,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"skeleton 骨架屏","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/skeleton/index.md","filePath":"cn/src/ranui/skeleton/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranui/skeleton/index.md"};function l(r,e,o,d,p,k){return s(),a("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

          skeleton 骨架屏

          在需要等待加载内容的位置提供一个占位图形组合。

          代码演示

          骨架长度跟随父级元素的长度

          xml
          <r-skeleton ></r-skeleton>
          ',9)]))}const g=t(n,[["render",l]]);export{c as __pageData,g as default}; +import{_ as t,o as s,c as a,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"skeleton 骨架屏","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/skeleton/index.md","filePath":"cn/src/ranui/skeleton/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranui/skeleton/index.md"};function l(r,e,o,d,p,k){return s(),a("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

          skeleton 骨架屏

          在需要等待加载内容的位置提供一个占位图形组合。

          代码演示

          骨架长度跟随父级元素的长度

          xml
          <r-skeleton ></r-skeleton>
          ',9)]))}const g=t(n,[["render",l]]);export{c as __pageData,g as default}; diff --git a/assets/cn_src_ranui_tab_index.md.D3FaivVj.js b/assets/cn_src_ranui_tab_index.md.CPn99LR8.js similarity index 99% rename from assets/cn_src_ranui_tab_index.md.D3FaivVj.js rename to assets/cn_src_ranui_tab_index.md.CPn99LR8.js index 9d3540063a..420b5e0d08 100644 --- a/assets/cn_src_ranui_tab_index.md.D3FaivVj.js +++ b/assets/cn_src_ranui_tab_index.md.CPn99LR8.js @@ -1,4 +1,4 @@ -import{_ as t,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Tab 图标","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/tab/index.md","filePath":"cn/src/ranui/tab/index.md","lastUpdated":1728828157000}'),k={name:"cn/src/ranui/tab/index.md"};function n(p,a,E,e,r,d){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Tab 图标

          标签页,其中r-tab需要和r-tabs搭配使用

          代码演示

          111112222233333
          xml
          <r-tabs >
          +import{_ as t,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Tab 图标","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/tab/index.md","filePath":"cn/src/ranui/tab/index.md","lastUpdated":1728921295000}'),k={name:"cn/src/ranui/tab/index.md"};function n(p,a,E,e,r,d){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Tab 图标

          标签页,其中r-tab需要和r-tabs搭配使用

          代码演示

          111112222233333
          xml
          <r-tabs >
                 <r-tab label="tab1">11111</r-tab>
                 <r-tab label="tab2">22222</r-tab>
                 <r-tab label="tab3">33333</r-tab>
          diff --git a/assets/cn_src_ranui_tab_index.md.D3FaivVj.lean.js b/assets/cn_src_ranui_tab_index.md.CPn99LR8.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_tab_index.md.D3FaivVj.lean.js
          rename to assets/cn_src_ranui_tab_index.md.CPn99LR8.lean.js
          index 9d3540063a..420b5e0d08 100644
          --- a/assets/cn_src_ranui_tab_index.md.D3FaivVj.lean.js
          +++ b/assets/cn_src_ranui_tab_index.md.CPn99LR8.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as t,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Tab 图标","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/tab/index.md","filePath":"cn/src/ranui/tab/index.md","lastUpdated":1728828157000}'),k={name:"cn/src/ranui/tab/index.md"};function n(p,a,E,e,r,d){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Tab 图标

          标签页,其中r-tab需要和r-tabs搭配使用

          代码演示

          111112222233333
          xml
          <r-tabs >
          +import{_ as t,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Tab 图标","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/tab/index.md","filePath":"cn/src/ranui/tab/index.md","lastUpdated":1728921295000}'),k={name:"cn/src/ranui/tab/index.md"};function n(p,a,E,e,r,d){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Tab 图标

          标签页,其中r-tab需要和r-tabs搭配使用

          代码演示

          111112222233333
          xml
          <r-tabs >
                 <r-tab label="tab1">11111</r-tab>
                 <r-tab label="tab2">22222</r-tab>
                 <r-tab label="tab3">33333</r-tab>
          diff --git a/assets/cn_src_ranui_tabs_index.md.D-Z5zQWG.js b/assets/cn_src_ranui_tabs_index.md.7O7hxEi8.js
          similarity index 99%
          rename from assets/cn_src_ranui_tabs_index.md.D-Z5zQWG.js
          rename to assets/cn_src_ranui_tabs_index.md.7O7hxEi8.js
          index 823eb1d1f5..5a54a107a4 100644
          --- a/assets/cn_src_ranui_tabs_index.md.D-Z5zQWG.js
          +++ b/assets/cn_src_ranui_tabs_index.md.7O7hxEi8.js
          @@ -1,4 +1,4 @@
          -import{_ as t,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/tabs/index.md","filePath":"cn/src/ranui/tabs/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranui/tabs/index.md"};function k(e,a,p,E,r,d){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Tab

          代码展示

          tab1tab2tab3
          xml
          <r-tabs>
          +import{_ as t,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/tabs/index.md","filePath":"cn/src/ranui/tabs/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranui/tabs/index.md"};function k(e,a,p,E,r,d){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Tab

          代码展示

          tab1tab2tab3
          xml
          <r-tabs>
               <r-tab label="tab1">tab1</r-tab>
               <r-tab label="tab2">tab2</r-tab>
               <r-tab label="tab3">tab3</r-tab>
          diff --git a/assets/cn_src_ranui_tabs_index.md.D-Z5zQWG.lean.js b/assets/cn_src_ranui_tabs_index.md.7O7hxEi8.lean.js
          similarity index 99%
          rename from assets/cn_src_ranui_tabs_index.md.D-Z5zQWG.lean.js
          rename to assets/cn_src_ranui_tabs_index.md.7O7hxEi8.lean.js
          index 823eb1d1f5..5a54a107a4 100644
          --- a/assets/cn_src_ranui_tabs_index.md.D-Z5zQWG.lean.js
          +++ b/assets/cn_src_ranui_tabs_index.md.7O7hxEi8.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as t,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/tabs/index.md","filePath":"cn/src/ranui/tabs/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranui/tabs/index.md"};function k(e,a,p,E,r,d){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Tab

          代码展示

          tab1tab2tab3
          xml
          <r-tabs>
          +import{_ as t,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranui/tabs/index.md","filePath":"cn/src/ranui/tabs/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranui/tabs/index.md"};function k(e,a,p,E,r,d){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          Tab

          代码展示

          tab1tab2tab3
          xml
          <r-tabs>
               <r-tab label="tab1">tab1</r-tab>
               <r-tab label="tab2">tab2</r-tab>
               <r-tab label="tab3">tab3</r-tab>
          diff --git a/assets/cn_src_ranuts_binaryTree_index.md.By-o1AjL.js b/assets/cn_src_ranuts_binaryTree_index.md.DrXBmpfQ.js
          similarity index 99%
          rename from assets/cn_src_ranuts_binaryTree_index.md.By-o1AjL.js
          rename to assets/cn_src_ranuts_binaryTree_index.md.DrXBmpfQ.js
          index 36ff0da7a6..b738c172a3 100644
          --- a/assets/cn_src_ranuts_binaryTree_index.md.By-o1AjL.js
          +++ b/assets/cn_src_ranuts_binaryTree_index.md.DrXBmpfQ.js
          @@ -1 +1 @@
          -import{_ as e}from"./chunks/balanceTree.CCEoBiag.js";import{_ as r,o as i,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"二叉树的定义","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/binaryTree/index.md","filePath":"cn/src/ranuts/binaryTree/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranuts/binaryTree/index.md"};function o(n,a,d,s,c,u){return i(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[h('

          二叉树的定义

          在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

          二叉树的性质

          • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
          • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
          • 包含 n 个结点的二叉树的高度至少为(log2n)+1
          • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
          • 二叉树的总结点数 n = n1 + n2 + n0
          • 总连线数等于总节点数减一(B = n - 1)
          • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

          二叉树的类型

          满二叉树

          一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

          完全二叉树

          一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

          二叉搜索树

          二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

          平衡二叉树

          平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

          B 树

          B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

          B+树

          B+树是 B 树的变体,也是一种多路搜索树。

          B*树

          B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

          红黑树

          红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

          遍历

          前序遍历

          后序遍历

          中序遍历

          层序遍历

          常见算法题

          镜像二叉树

          重建二叉树

          二叉树深度

          二叉树节点总数

          判断二叉树子结构

          输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

          参考文档

          1. 维基百科二叉树
          2. 百度百科满二叉树
          ',36)]))}const m=r(l,[["render",o]]);export{p as __pageData,m as default}; +import{_ as e}from"./chunks/balanceTree.CCEoBiag.js";import{_ as r,o as i,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"二叉树的定义","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/binaryTree/index.md","filePath":"cn/src/ranuts/binaryTree/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranuts/binaryTree/index.md"};function o(n,a,d,s,c,u){return i(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[h('

          二叉树的定义

          在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

          二叉树的性质

          • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
          • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
          • 包含 n 个结点的二叉树的高度至少为(log2n)+1
          • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
          • 二叉树的总结点数 n = n1 + n2 + n0
          • 总连线数等于总节点数减一(B = n - 1)
          • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

          二叉树的类型

          满二叉树

          一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

          完全二叉树

          一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

          二叉搜索树

          二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

          平衡二叉树

          平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

          B 树

          B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

          B+树

          B+树是 B 树的变体,也是一种多路搜索树。

          B*树

          B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

          红黑树

          红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

          遍历

          前序遍历

          后序遍历

          中序遍历

          层序遍历

          常见算法题

          镜像二叉树

          重建二叉树

          二叉树深度

          二叉树节点总数

          判断二叉树子结构

          输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

          参考文档

          1. 维基百科二叉树
          2. 百度百科满二叉树
          ',36)]))}const m=r(l,[["render",o]]);export{p as __pageData,m as default}; diff --git a/assets/cn_src_ranuts_binaryTree_index.md.By-o1AjL.lean.js b/assets/cn_src_ranuts_binaryTree_index.md.DrXBmpfQ.lean.js similarity index 99% rename from assets/cn_src_ranuts_binaryTree_index.md.By-o1AjL.lean.js rename to assets/cn_src_ranuts_binaryTree_index.md.DrXBmpfQ.lean.js index 36ff0da7a6..b738c172a3 100644 --- a/assets/cn_src_ranuts_binaryTree_index.md.By-o1AjL.lean.js +++ b/assets/cn_src_ranuts_binaryTree_index.md.DrXBmpfQ.lean.js @@ -1 +1 @@ -import{_ as e}from"./chunks/balanceTree.CCEoBiag.js";import{_ as r,o as i,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"二叉树的定义","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/binaryTree/index.md","filePath":"cn/src/ranuts/binaryTree/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranuts/binaryTree/index.md"};function o(n,a,d,s,c,u){return i(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[h('

          二叉树的定义

          在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

          二叉树的性质

          • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
          • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
          • 包含 n 个结点的二叉树的高度至少为(log2n)+1
          • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
          • 二叉树的总结点数 n = n1 + n2 + n0
          • 总连线数等于总节点数减一(B = n - 1)
          • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

          二叉树的类型

          满二叉树

          一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

          完全二叉树

          一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

          二叉搜索树

          二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

          平衡二叉树

          平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

          B 树

          B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

          B+树

          B+树是 B 树的变体,也是一种多路搜索树。

          B*树

          B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

          红黑树

          红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

          遍历

          前序遍历

          后序遍历

          中序遍历

          层序遍历

          常见算法题

          镜像二叉树

          重建二叉树

          二叉树深度

          二叉树节点总数

          判断二叉树子结构

          输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

          参考文档

          1. 维基百科二叉树
          2. 百度百科满二叉树
          ',36)]))}const m=r(l,[["render",o]]);export{p as __pageData,m as default}; +import{_ as e}from"./chunks/balanceTree.CCEoBiag.js";import{_ as r,o as i,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"二叉树的定义","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/binaryTree/index.md","filePath":"cn/src/ranuts/binaryTree/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranuts/binaryTree/index.md"};function o(n,a,d,s,c,u){return i(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[h('

          二叉树的定义

          在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

          二叉树的性质

          • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
          • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
          • 包含 n 个结点的二叉树的高度至少为(log2n)+1
          • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
          • 二叉树的总结点数 n = n1 + n2 + n0
          • 总连线数等于总节点数减一(B = n - 1)
          • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

          二叉树的类型

          满二叉树

          一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

          完全二叉树

          一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

          二叉搜索树

          二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

          平衡二叉树

          平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

          B 树

          B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

          B+树

          B+树是 B 树的变体,也是一种多路搜索树。

          B*树

          B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

          红黑树

          红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

          遍历

          前序遍历

          后序遍历

          中序遍历

          层序遍历

          常见算法题

          镜像二叉树

          重建二叉树

          二叉树深度

          二叉树节点总数

          判断二叉树子结构

          输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

          参考文档

          1. 维基百科二叉树
          2. 百度百科满二叉树
          ',36)]))}const m=r(l,[["render",o]]);export{p as __pageData,m as default}; diff --git a/assets/cn_src_ranuts_bundler_index.md.gFLefqgx.js b/assets/cn_src_ranuts_bundler_index.md.CNoHThyX.js similarity index 92% rename from assets/cn_src_ranuts_bundler_index.md.gFLefqgx.js rename to assets/cn_src_ranuts_bundler_index.md.CNoHThyX.js index cb0533ce70..5077bef784 100644 --- a/assets/cn_src_ranuts_bundler_index.md.gFLefqgx.js +++ b/assets/cn_src_ranuts_bundler_index.md.CNoHThyX.js @@ -1,4 +1,4 @@ -import{_ as s}from"./chunks/bundle.BxrzsuA1.js";import{_ as a,o as e,c as p,a3 as t}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse('{"title":"Bundler","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/bundler/index.md","filePath":"cn/src/ranuts/bundler/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranuts/bundler/index.md"};function r(i,n,d,o,c,u){return e(),p("div",{"data-pagefind-body":!0},n[0]||(n[0]=[t(`

          Bundler

          Bundler的使用: 传入 options 参数

          function build(options: Options):Promise<Build> {
          +import{_ as s}from"./chunks/bundle.BxrzsuA1.js";import{_ as a,o as e,c as p,a3 as t}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse('{"title":"Bundler","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/bundler/index.md","filePath":"cn/src/ranuts/bundler/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranuts/bundler/index.md"};function r(i,n,d,o,c,u){return e(),p("div",{"data-pagefind-body":!0},n[0]||(n[0]=[t(`

          Bundler

          Bundler的使用: 传入 options 参数

          function build(options: Options):Promise<Build> {
             const bundle = new Bundle({
               entry: options.input
             });
          diff --git a/assets/cn_src_ranuts_bundler_index.md.gFLefqgx.lean.js b/assets/cn_src_ranuts_bundler_index.md.CNoHThyX.lean.js
          similarity index 92%
          rename from assets/cn_src_ranuts_bundler_index.md.gFLefqgx.lean.js
          rename to assets/cn_src_ranuts_bundler_index.md.CNoHThyX.lean.js
          index cb0533ce70..5077bef784 100644
          --- a/assets/cn_src_ranuts_bundler_index.md.gFLefqgx.lean.js
          +++ b/assets/cn_src_ranuts_bundler_index.md.CNoHThyX.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as s}from"./chunks/bundle.BxrzsuA1.js";import{_ as a,o as e,c as p,a3 as t}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse('{"title":"Bundler","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/bundler/index.md","filePath":"cn/src/ranuts/bundler/index.md","lastUpdated":1728828157000}'),l={name:"cn/src/ranuts/bundler/index.md"};function r(i,n,d,o,c,u){return e(),p("div",{"data-pagefind-body":!0},n[0]||(n[0]=[t(`

          Bundler

          Bundler的使用: 传入 options 参数

          function build(options: Options):Promise<Build> {
          +import{_ as s}from"./chunks/bundle.BxrzsuA1.js";import{_ as a,o as e,c as p,a3 as t}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse('{"title":"Bundler","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/bundler/index.md","filePath":"cn/src/ranuts/bundler/index.md","lastUpdated":1728921295000}'),l={name:"cn/src/ranuts/bundler/index.md"};function r(i,n,d,o,c,u){return e(),p("div",{"data-pagefind-body":!0},n[0]||(n[0]=[t(`

          Bundler

          Bundler的使用: 传入 options 参数

          function build(options: Options):Promise<Build> {
             const bundle = new Bundle({
               entry: options.input
             });
          diff --git a/assets/cn_src_ranuts_file_appendFile.md.Kjwfv66v.js b/assets/cn_src_ranuts_file_appendFile.md.BDgZPn7V.js
          similarity index 96%
          rename from assets/cn_src_ranuts_file_appendFile.md.Kjwfv66v.js
          rename to assets/cn_src_ranuts_file_appendFile.md.BDgZPn7V.js
          index 0acd3263af..4199a6aa53 100644
          --- a/assets/cn_src_ranuts_file_appendFile.md.Kjwfv66v.js
          +++ b/assets/cn_src_ranuts_file_appendFile.md.BDgZPn7V.js
          @@ -1 +1 @@
          -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"AppendFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/appendFile.md","filePath":"cn/src/ranuts/file/appendFile.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/file/appendFile.md"};function o(i,t,l,h,s,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          AppendFile

          追加一些数据到文件内

          API

          Return

          • Promise
          参数说明类型描述
          success是否追加成功booleantrue 追加成功 false 追加失败
          data追加失败的原因,添加成功后的文件内容any

          Options

          参数说明类型默认值
          path文件路径,需要追加的文件stringundefined
          content需要追加的内容string

          Example

          ',9)]))}const b=e(n,[["render",o]]);export{u as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"AppendFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/appendFile.md","filePath":"cn/src/ranuts/file/appendFile.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/file/appendFile.md"};function o(i,t,l,h,s,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          AppendFile

          追加一些数据到文件内

          API

          Return

          • Promise
          参数说明类型描述
          success是否追加成功booleantrue 追加成功 false 追加失败
          data追加失败的原因,添加成功后的文件内容any

          Options

          参数说明类型默认值
          path文件路径,需要追加的文件stringundefined
          content需要追加的内容string

          Example

          ',9)]))}const b=e(n,[["render",o]]);export{u as __pageData,b as default}; diff --git a/assets/cn_src_ranuts_file_appendFile.md.Kjwfv66v.lean.js b/assets/cn_src_ranuts_file_appendFile.md.BDgZPn7V.lean.js similarity index 96% rename from assets/cn_src_ranuts_file_appendFile.md.Kjwfv66v.lean.js rename to assets/cn_src_ranuts_file_appendFile.md.BDgZPn7V.lean.js index 0acd3263af..4199a6aa53 100644 --- a/assets/cn_src_ranuts_file_appendFile.md.Kjwfv66v.lean.js +++ b/assets/cn_src_ranuts_file_appendFile.md.BDgZPn7V.lean.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"AppendFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/appendFile.md","filePath":"cn/src/ranuts/file/appendFile.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/file/appendFile.md"};function o(i,t,l,h,s,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          AppendFile

          追加一些数据到文件内

          API

          Return

          • Promise
          参数说明类型描述
          success是否追加成功booleantrue 追加成功 false 追加失败
          data追加失败的原因,添加成功后的文件内容any

          Options

          参数说明类型默认值
          path文件路径,需要追加的文件stringundefined
          content需要追加的内容string

          Example

          ',9)]))}const b=e(n,[["render",o]]);export{u as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"AppendFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/appendFile.md","filePath":"cn/src/ranuts/file/appendFile.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/file/appendFile.md"};function o(i,t,l,h,s,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          AppendFile

          追加一些数据到文件内

          API

          Return

          • Promise
          参数说明类型描述
          success是否追加成功booleantrue 追加成功 false 追加失败
          data追加失败的原因,添加成功后的文件内容any

          Options

          参数说明类型默认值
          path文件路径,需要追加的文件stringundefined
          content需要追加的内容string

          Example

          ',9)]))}const b=e(n,[["render",o]]);export{u as __pageData,b as default}; diff --git a/assets/cn_src_ranuts_file_fileInfo.md.Dho5Tv6s.js b/assets/cn_src_ranuts_file_fileInfo.md.KotpDHQJ.js similarity index 96% rename from assets/cn_src_ranuts_file_fileInfo.md.Dho5Tv6s.js rename to assets/cn_src_ranuts_file_fileInfo.md.KotpDHQJ.js index 94dd9f9359..0e41b95917 100644 --- a/assets/cn_src_ranuts_file_fileInfo.md.Dho5Tv6s.js +++ b/assets/cn_src_ranuts_file_fileInfo.md.KotpDHQJ.js @@ -1 +1 @@ -import{_ as e,o as a,c as r,a3 as d}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"QueryFileInfo","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/fileInfo.md","filePath":"cn/src/ranuts/file/fileInfo.md","lastUpdated":1728828157000}'),o={name:"cn/src/ranuts/file/fileInfo.md"};function i(n,t,l,h,s,c){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[d('

          QueryFileInfo

          查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

          API

          Return

          • Promise
          参数说明类型描述
          success是否检查成功booleantrue 成功 false 失败
          data文件的信息,或者错误的原因Stats

          Options

          参数说明类型默认值
          path文件路径,需要检查的文件路径stringundefined

          Example

          ',9)]))}const p=e(o,[["render",i]]);export{u as __pageData,p as default}; +import{_ as e,o as a,c as r,a3 as d}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"QueryFileInfo","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/fileInfo.md","filePath":"cn/src/ranuts/file/fileInfo.md","lastUpdated":1728921295000}'),o={name:"cn/src/ranuts/file/fileInfo.md"};function i(n,t,l,h,s,c){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[d('

          QueryFileInfo

          查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

          API

          Return

          • Promise
          参数说明类型描述
          success是否检查成功booleantrue 成功 false 失败
          data文件的信息,或者错误的原因Stats

          Options

          参数说明类型默认值
          path文件路径,需要检查的文件路径stringundefined

          Example

          ',9)]))}const p=e(o,[["render",i]]);export{u as __pageData,p as default}; diff --git a/assets/cn_src_ranuts_file_fileInfo.md.Dho5Tv6s.lean.js b/assets/cn_src_ranuts_file_fileInfo.md.KotpDHQJ.lean.js similarity index 96% rename from assets/cn_src_ranuts_file_fileInfo.md.Dho5Tv6s.lean.js rename to assets/cn_src_ranuts_file_fileInfo.md.KotpDHQJ.lean.js index 94dd9f9359..0e41b95917 100644 --- a/assets/cn_src_ranuts_file_fileInfo.md.Dho5Tv6s.lean.js +++ b/assets/cn_src_ranuts_file_fileInfo.md.KotpDHQJ.lean.js @@ -1 +1 @@ -import{_ as e,o as a,c as r,a3 as d}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"QueryFileInfo","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/fileInfo.md","filePath":"cn/src/ranuts/file/fileInfo.md","lastUpdated":1728828157000}'),o={name:"cn/src/ranuts/file/fileInfo.md"};function i(n,t,l,h,s,c){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[d('

          QueryFileInfo

          查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

          API

          Return

          • Promise
          参数说明类型描述
          success是否检查成功booleantrue 成功 false 失败
          data文件的信息,或者错误的原因Stats

          Options

          参数说明类型默认值
          path文件路径,需要检查的文件路径stringundefined

          Example

          ',9)]))}const p=e(o,[["render",i]]);export{u as __pageData,p as default}; +import{_ as e,o as a,c as r,a3 as d}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"QueryFileInfo","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/fileInfo.md","filePath":"cn/src/ranuts/file/fileInfo.md","lastUpdated":1728921295000}'),o={name:"cn/src/ranuts/file/fileInfo.md"};function i(n,t,l,h,s,c){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[d('

          QueryFileInfo

          查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

          API

          Return

          • Promise
          参数说明类型描述
          success是否检查成功booleantrue 成功 false 失败
          data文件的信息,或者错误的原因Stats

          Options

          参数说明类型默认值
          path文件路径,需要检查的文件路径stringundefined

          Example

          ',9)]))}const p=e(o,[["render",i]]);export{u as __pageData,p as default}; diff --git a/assets/cn_src_ranuts_file_readDir.md.BSttmwRD.js b/assets/cn_src_ranuts_file_readDir.md.rKDcx1fc.js similarity index 96% rename from assets/cn_src_ranuts_file_readDir.md.BSttmwRD.js rename to assets/cn_src_ranuts_file_readDir.md.rKDcx1fc.js index 28e076bc67..87840d7ce8 100644 --- a/assets/cn_src_ranuts_file_readDir.md.BSttmwRD.js +++ b/assets/cn_src_ranuts_file_readDir.md.rKDcx1fc.js @@ -1 +1 @@ -import{_ as e,o as r,c as l,a3 as d,j as t,a as n}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"ReadDir","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/readDir.md","filePath":"cn/src/ranuts/file/readDir.md","lastUpdated":1728828157000}'),i={name:"cn/src/ranuts/file/readDir.md"};function o(s,a,h,u,c,p){return r(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[d('

          ReadDir

          读一个目录下的所有文件

          API

          Return

          • Promise
          参数说明类型描述
          result目录下所有文件的数组array传入函数的参数

          Options

          ',7),t("table",{tabindex:"0"},[t("thead",null,[t("tr",null,[t("th",null,"参数"),t("th",null,"说明"),t("th",null,"类型"),t("th",null,"默认值")])]),t("tbody",null,[t("tr",null,[t("td",null,"options"),t("td",{dirPath:""}),t("td",null,[t("code",null,"object")]),t("td",null,"传入函数的参数")]),t("tr",null,[t("td",null,"dirPath"),t("td",null,"文件的路径"),t("td",null,[t("code",null,"Stats")]),t("td")])])],-1),t("h2",{id:"example",tabindex:"-1"},[n("Example "),t("a",{class:"header-anchor",href:"#example","aria-label":'Permalink to "Example"'},"​")],-1)]))}const f=e(i,[["render",o]]);export{m as __pageData,f as default}; +import{_ as e,o as r,c as l,a3 as d,j as t,a as n}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"ReadDir","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/readDir.md","filePath":"cn/src/ranuts/file/readDir.md","lastUpdated":1728921295000}'),i={name:"cn/src/ranuts/file/readDir.md"};function o(s,a,h,u,c,p){return r(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[d('

          ReadDir

          读一个目录下的所有文件

          API

          Return

          • Promise
          参数说明类型描述
          result目录下所有文件的数组array传入函数的参数

          Options

          ',7),t("table",{tabindex:"0"},[t("thead",null,[t("tr",null,[t("th",null,"参数"),t("th",null,"说明"),t("th",null,"类型"),t("th",null,"默认值")])]),t("tbody",null,[t("tr",null,[t("td",null,"options"),t("td",{dirPath:""}),t("td",null,[t("code",null,"object")]),t("td",null,"传入函数的参数")]),t("tr",null,[t("td",null,"dirPath"),t("td",null,"文件的路径"),t("td",null,[t("code",null,"Stats")]),t("td")])])],-1),t("h2",{id:"example",tabindex:"-1"},[n("Example "),t("a",{class:"header-anchor",href:"#example","aria-label":'Permalink to "Example"'},"​")],-1)]))}const f=e(i,[["render",o]]);export{m as __pageData,f as default}; diff --git a/assets/cn_src_ranuts_file_readDir.md.BSttmwRD.lean.js b/assets/cn_src_ranuts_file_readDir.md.rKDcx1fc.lean.js similarity index 96% rename from assets/cn_src_ranuts_file_readDir.md.BSttmwRD.lean.js rename to assets/cn_src_ranuts_file_readDir.md.rKDcx1fc.lean.js index 28e076bc67..87840d7ce8 100644 --- a/assets/cn_src_ranuts_file_readDir.md.BSttmwRD.lean.js +++ b/assets/cn_src_ranuts_file_readDir.md.rKDcx1fc.lean.js @@ -1 +1 @@ -import{_ as e,o as r,c as l,a3 as d,j as t,a as n}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"ReadDir","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/readDir.md","filePath":"cn/src/ranuts/file/readDir.md","lastUpdated":1728828157000}'),i={name:"cn/src/ranuts/file/readDir.md"};function o(s,a,h,u,c,p){return r(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[d('

          ReadDir

          读一个目录下的所有文件

          API

          Return

          • Promise
          参数说明类型描述
          result目录下所有文件的数组array传入函数的参数

          Options

          ',7),t("table",{tabindex:"0"},[t("thead",null,[t("tr",null,[t("th",null,"参数"),t("th",null,"说明"),t("th",null,"类型"),t("th",null,"默认值")])]),t("tbody",null,[t("tr",null,[t("td",null,"options"),t("td",{dirPath:""}),t("td",null,[t("code",null,"object")]),t("td",null,"传入函数的参数")]),t("tr",null,[t("td",null,"dirPath"),t("td",null,"文件的路径"),t("td",null,[t("code",null,"Stats")]),t("td")])])],-1),t("h2",{id:"example",tabindex:"-1"},[n("Example "),t("a",{class:"header-anchor",href:"#example","aria-label":'Permalink to "Example"'},"​")],-1)]))}const f=e(i,[["render",o]]);export{m as __pageData,f as default}; +import{_ as e,o as r,c as l,a3 as d,j as t,a as n}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"ReadDir","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/readDir.md","filePath":"cn/src/ranuts/file/readDir.md","lastUpdated":1728921295000}'),i={name:"cn/src/ranuts/file/readDir.md"};function o(s,a,h,u,c,p){return r(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[d('

          ReadDir

          读一个目录下的所有文件

          API

          Return

          • Promise
          参数说明类型描述
          result目录下所有文件的数组array传入函数的参数

          Options

          ',7),t("table",{tabindex:"0"},[t("thead",null,[t("tr",null,[t("th",null,"参数"),t("th",null,"说明"),t("th",null,"类型"),t("th",null,"默认值")])]),t("tbody",null,[t("tr",null,[t("td",null,"options"),t("td",{dirPath:""}),t("td",null,[t("code",null,"object")]),t("td",null,"传入函数的参数")]),t("tr",null,[t("td",null,"dirPath"),t("td",null,"文件的路径"),t("td",null,[t("code",null,"Stats")]),t("td")])])],-1),t("h2",{id:"example",tabindex:"-1"},[n("Example "),t("a",{class:"header-anchor",href:"#example","aria-label":'Permalink to "Example"'},"​")],-1)]))}const f=e(i,[["render",o]]);export{m as __pageData,f as default}; diff --git a/assets/cn_src_ranuts_file_readFile.md.DqgoToSw.js b/assets/cn_src_ranuts_file_readFile.md.nK6bqV_e.js similarity index 96% rename from assets/cn_src_ranuts_file_readFile.md.DqgoToSw.js rename to assets/cn_src_ranuts_file_readFile.md.nK6bqV_e.js index b3a89f3fc9..8b6188bdc0 100644 --- a/assets/cn_src_ranuts_file_readFile.md.DqgoToSw.js +++ b/assets/cn_src_ranuts_file_readFile.md.nK6bqV_e.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ReadFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/readFile.md","filePath":"cn/src/ranuts/file/readFile.md","lastUpdated":1728828157000}'),o={name:"cn/src/ranuts/file/readFile.md"};function i(l,t,n,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          ReadFile

          观察一个文件是否改变

          API

          Return

          • Promise
          参数说明类型描述
          data文件是否被改变booleantrue 文件改变 false 文件没变

          Options

          参数说明类型默认值
          path文件路径,需要监听的文件stringundefined
          interval监听文件改变的时间,单位毫秒。number20

          Example

          ',9)]))}const b=e(o,[["render",i]]);export{p as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ReadFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/readFile.md","filePath":"cn/src/ranuts/file/readFile.md","lastUpdated":1728921295000}'),o={name:"cn/src/ranuts/file/readFile.md"};function i(l,t,n,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          ReadFile

          观察一个文件是否改变

          API

          Return

          • Promise
          参数说明类型描述
          data文件是否被改变booleantrue 文件改变 false 文件没变

          Options

          参数说明类型默认值
          path文件路径,需要监听的文件stringundefined
          interval监听文件改变的时间,单位毫秒。number20

          Example

          ',9)]))}const b=e(o,[["render",i]]);export{p as __pageData,b as default}; diff --git a/assets/cn_src_ranuts_file_readFile.md.DqgoToSw.lean.js b/assets/cn_src_ranuts_file_readFile.md.nK6bqV_e.lean.js similarity index 96% rename from assets/cn_src_ranuts_file_readFile.md.DqgoToSw.lean.js rename to assets/cn_src_ranuts_file_readFile.md.nK6bqV_e.lean.js index b3a89f3fc9..8b6188bdc0 100644 --- a/assets/cn_src_ranuts_file_readFile.md.DqgoToSw.lean.js +++ b/assets/cn_src_ranuts_file_readFile.md.nK6bqV_e.lean.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ReadFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/readFile.md","filePath":"cn/src/ranuts/file/readFile.md","lastUpdated":1728828157000}'),o={name:"cn/src/ranuts/file/readFile.md"};function i(l,t,n,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          ReadFile

          观察一个文件是否改变

          API

          Return

          • Promise
          参数说明类型描述
          data文件是否被改变booleantrue 文件改变 false 文件没变

          Options

          参数说明类型默认值
          path文件路径,需要监听的文件stringundefined
          interval监听文件改变的时间,单位毫秒。number20

          Example

          ',9)]))}const b=e(o,[["render",i]]);export{p as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ReadFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/readFile.md","filePath":"cn/src/ranuts/file/readFile.md","lastUpdated":1728921295000}'),o={name:"cn/src/ranuts/file/readFile.md"};function i(l,t,n,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          ReadFile

          观察一个文件是否改变

          API

          Return

          • Promise
          参数说明类型描述
          data文件是否被改变booleantrue 文件改变 false 文件没变

          Options

          参数说明类型默认值
          path文件路径,需要监听的文件stringundefined
          interval监听文件改变的时间,单位毫秒。number20

          Example

          ',9)]))}const b=e(o,[["render",i]]);export{p as __pageData,b as default}; diff --git a/assets/cn_src_ranuts_file_watchFile.md.DAZXSmjV.js b/assets/cn_src_ranuts_file_watchFile.md.CAsEL4vf.js similarity index 96% rename from assets/cn_src_ranuts_file_watchFile.md.DAZXSmjV.js rename to assets/cn_src_ranuts_file_watchFile.md.CAsEL4vf.js index 461bfe8a7f..2069c21857 100644 --- a/assets/cn_src_ranuts_file_watchFile.md.DAZXSmjV.js +++ b/assets/cn_src_ranuts_file_watchFile.md.CAsEL4vf.js @@ -1 +1 @@ -import{_ as a,o as e,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WatchFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/watchFile.md","filePath":"cn/src/ranuts/file/watchFile.md","lastUpdated":1728828157000}'),o={name:"cn/src/ranuts/file/watchFile.md"};function i(h,t,n,l,c,s){return e(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          WatchFile

          观察一个文件是否改变

          API

          Return

          • Promise
          参数说明类型描述
          status文件是否被改变booleantrue 文件改变 false 文件没变

          Options

          参数说明类型默认值
          path文件路径,需要监听的文件stringundefined
          interval监听文件改变的时间,单位毫秒。number20
          ',8)]))}const b=a(o,[["render",i]]);export{p as __pageData,b as default}; +import{_ as a,o as e,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WatchFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/watchFile.md","filePath":"cn/src/ranuts/file/watchFile.md","lastUpdated":1728921295000}'),o={name:"cn/src/ranuts/file/watchFile.md"};function i(h,t,n,l,c,s){return e(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          WatchFile

          观察一个文件是否改变

          API

          Return

          • Promise
          参数说明类型描述
          status文件是否被改变booleantrue 文件改变 false 文件没变

          Options

          参数说明类型默认值
          path文件路径,需要监听的文件stringundefined
          interval监听文件改变的时间,单位毫秒。number20
          ',8)]))}const b=a(o,[["render",i]]);export{p as __pageData,b as default}; diff --git a/assets/cn_src_ranuts_file_watchFile.md.DAZXSmjV.lean.js b/assets/cn_src_ranuts_file_watchFile.md.CAsEL4vf.lean.js similarity index 96% rename from assets/cn_src_ranuts_file_watchFile.md.DAZXSmjV.lean.js rename to assets/cn_src_ranuts_file_watchFile.md.CAsEL4vf.lean.js index 461bfe8a7f..2069c21857 100644 --- a/assets/cn_src_ranuts_file_watchFile.md.DAZXSmjV.lean.js +++ b/assets/cn_src_ranuts_file_watchFile.md.CAsEL4vf.lean.js @@ -1 +1 @@ -import{_ as a,o as e,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WatchFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/watchFile.md","filePath":"cn/src/ranuts/file/watchFile.md","lastUpdated":1728828157000}'),o={name:"cn/src/ranuts/file/watchFile.md"};function i(h,t,n,l,c,s){return e(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          WatchFile

          观察一个文件是否改变

          API

          Return

          • Promise
          参数说明类型描述
          status文件是否被改变booleantrue 文件改变 false 文件没变

          Options

          参数说明类型默认值
          path文件路径,需要监听的文件stringundefined
          interval监听文件改变的时间,单位毫秒。number20
          ',8)]))}const b=a(o,[["render",i]]);export{p as __pageData,b as default}; +import{_ as a,o as e,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WatchFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/watchFile.md","filePath":"cn/src/ranuts/file/watchFile.md","lastUpdated":1728921295000}'),o={name:"cn/src/ranuts/file/watchFile.md"};function i(h,t,n,l,c,s){return e(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          WatchFile

          观察一个文件是否改变

          API

          Return

          • Promise
          参数说明类型描述
          status文件是否被改变booleantrue 文件改变 false 文件没变

          Options

          参数说明类型默认值
          path文件路径,需要监听的文件stringundefined
          interval监听文件改变的时间,单位毫秒。number20
          ',8)]))}const b=a(o,[["render",i]]);export{p as __pageData,b as default}; diff --git a/assets/cn_src_ranuts_file_writeFile.md.mwv7EGlj.js b/assets/cn_src_ranuts_file_writeFile.md.BoU7gKL6.js similarity index 96% rename from assets/cn_src_ranuts_file_writeFile.md.mwv7EGlj.js rename to assets/cn_src_ranuts_file_writeFile.md.BoU7gKL6.js index 72e51105c1..d16ddbc8d0 100644 --- a/assets/cn_src_ranuts_file_writeFile.md.mwv7EGlj.js +++ b/assets/cn_src_ranuts_file_writeFile.md.BoU7gKL6.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WriteFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/writeFile.md","filePath":"cn/src/ranuts/file/writeFile.md","lastUpdated":1728828157000}'),i={name:"cn/src/ranuts/file/writeFile.md"};function o(n,t,l,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          WriteFile

          将内容写入文件

          API

          Return

          • Promise
          参数说明类型描述
          success是否写入成功booleantrue 成功 false 失败
          data写入失败的原因,添加成功后的文件内容和文件路径any

          Options

          参数说明类型默认值
          path文件路径,需要追加的文件stringundefined
          content需要追加的内容string
          ',8)]))}const b=e(i,[["render",o]]);export{p as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WriteFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/writeFile.md","filePath":"cn/src/ranuts/file/writeFile.md","lastUpdated":1728921295000}'),i={name:"cn/src/ranuts/file/writeFile.md"};function o(n,t,l,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          WriteFile

          将内容写入文件

          API

          Return

          • Promise
          参数说明类型描述
          success是否写入成功booleantrue 成功 false 失败
          data写入失败的原因,添加成功后的文件内容和文件路径any

          Options

          参数说明类型默认值
          path文件路径,需要追加的文件stringundefined
          content需要追加的内容string
          ',8)]))}const b=e(i,[["render",o]]);export{p as __pageData,b as default}; diff --git a/assets/cn_src_ranuts_file_writeFile.md.mwv7EGlj.lean.js b/assets/cn_src_ranuts_file_writeFile.md.BoU7gKL6.lean.js similarity index 96% rename from assets/cn_src_ranuts_file_writeFile.md.mwv7EGlj.lean.js rename to assets/cn_src_ranuts_file_writeFile.md.BoU7gKL6.lean.js index 72e51105c1..d16ddbc8d0 100644 --- a/assets/cn_src_ranuts_file_writeFile.md.mwv7EGlj.lean.js +++ b/assets/cn_src_ranuts_file_writeFile.md.BoU7gKL6.lean.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WriteFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/writeFile.md","filePath":"cn/src/ranuts/file/writeFile.md","lastUpdated":1728828157000}'),i={name:"cn/src/ranuts/file/writeFile.md"};function o(n,t,l,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          WriteFile

          将内容写入文件

          API

          Return

          • Promise
          参数说明类型描述
          success是否写入成功booleantrue 成功 false 失败
          data写入失败的原因,添加成功后的文件内容和文件路径any

          Options

          参数说明类型默认值
          path文件路径,需要追加的文件stringundefined
          content需要追加的内容string
          ',8)]))}const b=e(i,[["render",o]]);export{p as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WriteFile","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/file/writeFile.md","filePath":"cn/src/ranuts/file/writeFile.md","lastUpdated":1728921295000}'),i={name:"cn/src/ranuts/file/writeFile.md"};function o(n,t,l,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

          WriteFile

          将内容写入文件

          API

          Return

          • Promise
          参数说明类型描述
          success是否写入成功booleantrue 成功 false 失败
          data写入失败的原因,添加成功后的文件内容和文件路径any

          Options

          参数说明类型默认值
          path文件路径,需要追加的文件stringundefined
          content需要追加的内容string
          ',8)]))}const b=e(i,[["render",o]]);export{p as __pageData,b as default}; diff --git a/assets/cn_src_ranuts_index.md.ImKijNhD.js b/assets/cn_src_ranuts_index.md.CuyLwwdp.js similarity index 97% rename from assets/cn_src_ranuts_index.md.ImKijNhD.js rename to assets/cn_src_ranuts_index.md.CuyLwwdp.js index dc61420c57..c4a0447595 100644 --- a/assets/cn_src_ranuts_index.md.ImKijNhD.js +++ b/assets/cn_src_ranuts_index.md.CuyLwwdp.js @@ -1 +1 @@ -import{_ as r,o as d,c as a,a3 as i,G as o,B as l}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"ranuts overview","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/index.md","filePath":"cn/src/ranuts/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/index.md"};function s(h,t,m,f,c,u){const e=l("TOTP");return d(),a("div",{"data-pagefind-body":!0},[t[0]||(t[0]=i('

          ranuts overview

          方法列表

          方法说明详细内容
          writeFile写入文件writeFile
          readFile读取文件readFile
          readDir读取目录,获取目录下所有文件的名字readDir
          watchFile观察文件的内容是否发生变化watchFile
          queryFileInfo查询文件信息queryFileInfo
          filterObj过滤对象filterObj
          EventEmitter发布订阅类EventEmitter
          str2Xml字符串转成xmlstr2Xml
          getMime根据文件格式后缀获取 mime typegetMime
          getCookie获取指定 cookie 的值writeFile
          formatJson格式化 JSONformatJson

          TOTP

          ',4)),o(e)])}const v=r(n,[["render",s]]);export{b as __pageData,v as default}; +import{_ as r,o as d,c as a,a3 as i,G as o,B as l}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"ranuts overview","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/index.md","filePath":"cn/src/ranuts/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/index.md"};function s(h,t,m,f,c,u){const e=l("TOTP");return d(),a("div",{"data-pagefind-body":!0},[t[0]||(t[0]=i('

          ranuts overview

          方法列表

          方法说明详细内容
          writeFile写入文件writeFile
          readFile读取文件readFile
          readDir读取目录,获取目录下所有文件的名字readDir
          watchFile观察文件的内容是否发生变化watchFile
          queryFileInfo查询文件信息queryFileInfo
          filterObj过滤对象filterObj
          EventEmitter发布订阅类EventEmitter
          str2Xml字符串转成xmlstr2Xml
          getMime根据文件格式后缀获取 mime typegetMime
          getCookie获取指定 cookie 的值writeFile
          formatJson格式化 JSONformatJson

          TOTP

          ',4)),o(e)])}const v=r(n,[["render",s]]);export{b as __pageData,v as default}; diff --git a/assets/cn_src_ranuts_index.md.ImKijNhD.lean.js b/assets/cn_src_ranuts_index.md.CuyLwwdp.lean.js similarity index 97% rename from assets/cn_src_ranuts_index.md.ImKijNhD.lean.js rename to assets/cn_src_ranuts_index.md.CuyLwwdp.lean.js index dc61420c57..c4a0447595 100644 --- a/assets/cn_src_ranuts_index.md.ImKijNhD.lean.js +++ b/assets/cn_src_ranuts_index.md.CuyLwwdp.lean.js @@ -1 +1 @@ -import{_ as r,o as d,c as a,a3 as i,G as o,B as l}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"ranuts overview","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/index.md","filePath":"cn/src/ranuts/index.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/index.md"};function s(h,t,m,f,c,u){const e=l("TOTP");return d(),a("div",{"data-pagefind-body":!0},[t[0]||(t[0]=i('

          ranuts overview

          方法列表

          方法说明详细内容
          writeFile写入文件writeFile
          readFile读取文件readFile
          readDir读取目录,获取目录下所有文件的名字readDir
          watchFile观察文件的内容是否发生变化watchFile
          queryFileInfo查询文件信息queryFileInfo
          filterObj过滤对象filterObj
          EventEmitter发布订阅类EventEmitter
          str2Xml字符串转成xmlstr2Xml
          getMime根据文件格式后缀获取 mime typegetMime
          getCookie获取指定 cookie 的值writeFile
          formatJson格式化 JSONformatJson

          TOTP

          ',4)),o(e)])}const v=r(n,[["render",s]]);export{b as __pageData,v as default}; +import{_ as r,o as d,c as a,a3 as i,G as o,B as l}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"ranuts overview","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/index.md","filePath":"cn/src/ranuts/index.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/index.md"};function s(h,t,m,f,c,u){const e=l("TOTP");return d(),a("div",{"data-pagefind-body":!0},[t[0]||(t[0]=i('

          ranuts overview

          方法列表

          方法说明详细内容
          writeFile写入文件writeFile
          readFile读取文件readFile
          readDir读取目录,获取目录下所有文件的名字readDir
          watchFile观察文件的内容是否发生变化watchFile
          queryFileInfo查询文件信息queryFileInfo
          filterObj过滤对象filterObj
          EventEmitter发布订阅类EventEmitter
          str2Xml字符串转成xmlstr2Xml
          getMime根据文件格式后缀获取 mime typegetMime
          getCookie获取指定 cookie 的值writeFile
          formatJson格式化 JSONformatJson

          TOTP

          ',4)),o(e)])}const v=r(n,[["render",s]]);export{b as __pageData,v as default}; diff --git a/assets/cn_src_ranuts_mimeType_mimeType.md.DNyJyegy.js b/assets/cn_src_ranuts_mimeType_mimeType.md.C1HE55kh.js similarity index 98% rename from assets/cn_src_ranuts_mimeType_mimeType.md.DNyJyegy.js rename to assets/cn_src_ranuts_mimeType_mimeType.md.C1HE55kh.js index 5698029da0..0f7f7fa6cd 100644 --- a/assets/cn_src_ranuts_mimeType_mimeType.md.DNyJyegy.js +++ b/assets/cn_src_ranuts_mimeType_mimeType.md.C1HE55kh.js @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as t,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getMime","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/mimeType/mimeType.md","filePath":"cn/src/ranuts/mimeType/mimeType.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/mimeType/mimeType.md"};function h(l,s,p,r,d,k){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

          getMime

          传入文件格式后缀,返回mime type

          API

          Return

          参数说明类型
          string返回mime typestring

          Options

          参数说明类型默认值
          ext文件后缀格式string

          Example

          js
          import { getMime } from 'ranuts';
          +import{_ as i,o as a,c as t,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getMime","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/mimeType/mimeType.md","filePath":"cn/src/ranuts/mimeType/mimeType.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/mimeType/mimeType.md"};function h(l,s,p,r,d,k){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

          getMime

          传入文件格式后缀,返回mime type

          API

          Return

          参数说明类型
          string返回mime typestring

          Options

          参数说明类型默认值
          ext文件后缀格式string

          Example

          js
          import { getMime } from 'ranuts';
           
           const result = getMime('.pptx');
           console.log(result);
          diff --git a/assets/cn_src_ranuts_mimeType_mimeType.md.DNyJyegy.lean.js b/assets/cn_src_ranuts_mimeType_mimeType.md.C1HE55kh.lean.js
          similarity index 98%
          rename from assets/cn_src_ranuts_mimeType_mimeType.md.DNyJyegy.lean.js
          rename to assets/cn_src_ranuts_mimeType_mimeType.md.C1HE55kh.lean.js
          index 5698029da0..0f7f7fa6cd 100644
          --- a/assets/cn_src_ranuts_mimeType_mimeType.md.DNyJyegy.lean.js
          +++ b/assets/cn_src_ranuts_mimeType_mimeType.md.C1HE55kh.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as t,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getMime","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/mimeType/mimeType.md","filePath":"cn/src/ranuts/mimeType/mimeType.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/mimeType/mimeType.md"};function h(l,s,p,r,d,k){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

          getMime

          传入文件格式后缀,返回mime type

          API

          Return

          参数说明类型
          string返回mime typestring

          Options

          参数说明类型默认值
          ext文件后缀格式string

          Example

          js
          import { getMime } from 'ranuts';
          +import{_ as i,o as a,c as t,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getMime","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/mimeType/mimeType.md","filePath":"cn/src/ranuts/mimeType/mimeType.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/mimeType/mimeType.md"};function h(l,s,p,r,d,k){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

          getMime

          传入文件格式后缀,返回mime type

          API

          Return

          参数说明类型
          string返回mime typestring

          Options

          参数说明类型默认值
          ext文件后缀格式string

          Example

          js
          import { getMime } from 'ranuts';
           
           const result = getMime('.pptx');
           console.log(result);
          diff --git a/assets/cn_src_ranuts_mode_subscribe.md.BhBmLNNr.js b/assets/cn_src_ranuts_mode_subscribe.md.DVNH30m1.js
          similarity index 99%
          rename from assets/cn_src_ranuts_mode_subscribe.md.BhBmLNNr.js
          rename to assets/cn_src_ranuts_mode_subscribe.md.DVNH30m1.js
          index d51b185312..7838139bb1 100644
          --- a/assets/cn_src_ranuts_mode_subscribe.md.BhBmLNNr.js
          +++ b/assets/cn_src_ranuts_mode_subscribe.md.DVNH30m1.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"EventEmitter","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/mode/subscribe.md","filePath":"cn/src/ranuts/mode/subscribe.md","lastUpdated":1728828157000}'),h={name:"cn/src/ranuts/mode/subscribe.md"};function l(k,s,p,e,E,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

          EventEmitter

          发布订阅的类

          Class

          Methods

          方法参数说明默认值
          on订阅事件订阅事件,传入参数事件名,回调函数
          once订阅一次事件,传入参数事件名,回调函数订阅一次事件,触发一次后不再会触发
          off取消订阅事件,传入参数事件名,回调函数取消订阅事件
          emit触发事件,需要事件名触发事件

          Example

          js
          import { Subscribe } from 'ranuts';
          +import{_ as i,o as a,c as n,a3 as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"EventEmitter","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/mode/subscribe.md","filePath":"cn/src/ranuts/mode/subscribe.md","lastUpdated":1728921295000}'),h={name:"cn/src/ranuts/mode/subscribe.md"};function l(k,s,p,e,E,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

          EventEmitter

          发布订阅的类

          Class

          Methods

          方法参数说明默认值
          on订阅事件订阅事件,传入参数事件名,回调函数
          once订阅一次事件,传入参数事件名,回调函数订阅一次事件,触发一次后不再会触发
          off取消订阅事件,传入参数事件名,回调函数取消订阅事件
          emit触发事件,需要事件名触发事件

          Example

          js
          import { Subscribe } from 'ranuts';
           
           const subscribe = new Subscribe();
           
          diff --git a/assets/cn_src_ranuts_mode_subscribe.md.BhBmLNNr.lean.js b/assets/cn_src_ranuts_mode_subscribe.md.DVNH30m1.lean.js
          similarity index 99%
          rename from assets/cn_src_ranuts_mode_subscribe.md.BhBmLNNr.lean.js
          rename to assets/cn_src_ranuts_mode_subscribe.md.DVNH30m1.lean.js
          index d51b185312..7838139bb1 100644
          --- a/assets/cn_src_ranuts_mode_subscribe.md.BhBmLNNr.lean.js
          +++ b/assets/cn_src_ranuts_mode_subscribe.md.DVNH30m1.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"EventEmitter","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/mode/subscribe.md","filePath":"cn/src/ranuts/mode/subscribe.md","lastUpdated":1728828157000}'),h={name:"cn/src/ranuts/mode/subscribe.md"};function l(k,s,p,e,E,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

          EventEmitter

          发布订阅的类

          Class

          Methods

          方法参数说明默认值
          on订阅事件订阅事件,传入参数事件名,回调函数
          once订阅一次事件,传入参数事件名,回调函数订阅一次事件,触发一次后不再会触发
          off取消订阅事件,传入参数事件名,回调函数取消订阅事件
          emit触发事件,需要事件名触发事件

          Example

          js
          import { Subscribe } from 'ranuts';
          +import{_ as i,o as a,c as n,a3 as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"EventEmitter","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/mode/subscribe.md","filePath":"cn/src/ranuts/mode/subscribe.md","lastUpdated":1728921295000}'),h={name:"cn/src/ranuts/mode/subscribe.md"};function l(k,s,p,e,E,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

          EventEmitter

          发布订阅的类

          Class

          Methods

          方法参数说明默认值
          on订阅事件订阅事件,传入参数事件名,回调函数
          once订阅一次事件,传入参数事件名,回调函数订阅一次事件,触发一次后不再会触发
          off取消订阅事件,传入参数事件名,回调函数取消订阅事件
          emit触发事件,需要事件名触发事件

          Example

          js
          import { Subscribe } from 'ranuts';
           
           const subscribe = new Subscribe();
           
          diff --git a/assets/cn_src_ranuts_utils_convertImageToBase64.md.DXYg1zir.js b/assets/cn_src_ranuts_utils_convertImageToBase64.md.DeS8CqKI.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_convertImageToBase64.md.DXYg1zir.js
          rename to assets/cn_src_ranuts_utils_convertImageToBase64.md.DeS8CqKI.js
          index 217b5d0bcf..34f7358889 100644
          --- a/assets/cn_src_ranuts_utils_convertImageToBase64.md.DXYg1zir.js
          +++ b/assets/cn_src_ranuts_utils_convertImageToBase64.md.DeS8CqKI.js
          @@ -1,4 +1,4 @@
          -import{_ as t,o as s,c as e,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"convertImageToBase64","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/convertImageToBase64.md","filePath":"cn/src/ranuts/utils/convertImageToBase64.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/utils/convertImageToBase64.md"};function d(r,a,o,h,l,p){return s(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          convertImageToBase64

          图片转base64

          API

          Return

          参数说明类型
          success是否转换成功boolean
          data转换成功后的值string,ArrayBuffer , null
          message转换成功或失败的原因string

          Options

          参数说明类型默认值
          file传入的文件File

          Example

          js
          import { convertImageToBase64 } from 'ranuts';
          +import{_ as t,o as s,c as e,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"convertImageToBase64","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/convertImageToBase64.md","filePath":"cn/src/ranuts/utils/convertImageToBase64.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/utils/convertImageToBase64.md"};function d(r,a,o,h,l,p){return s(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          convertImageToBase64

          图片转base64

          API

          Return

          参数说明类型
          success是否转换成功boolean
          data转换成功后的值string,ArrayBuffer , null
          message转换成功或失败的原因string

          Options

          参数说明类型默认值
          file传入的文件File

          Example

          js
          import { convertImageToBase64 } from 'ranuts';
           
           convertImageToBase64(file).then((res) => {
             console.log(result);
          diff --git a/assets/cn_src_ranuts_utils_convertImageToBase64.md.DXYg1zir.lean.js b/assets/cn_src_ranuts_utils_convertImageToBase64.md.DeS8CqKI.lean.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_convertImageToBase64.md.DXYg1zir.lean.js
          rename to assets/cn_src_ranuts_utils_convertImageToBase64.md.DeS8CqKI.lean.js
          index 217b5d0bcf..34f7358889 100644
          --- a/assets/cn_src_ranuts_utils_convertImageToBase64.md.DXYg1zir.lean.js
          +++ b/assets/cn_src_ranuts_utils_convertImageToBase64.md.DeS8CqKI.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as t,o as s,c as e,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"convertImageToBase64","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/convertImageToBase64.md","filePath":"cn/src/ranuts/utils/convertImageToBase64.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/utils/convertImageToBase64.md"};function d(r,a,o,h,l,p){return s(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          convertImageToBase64

          图片转base64

          API

          Return

          参数说明类型
          success是否转换成功boolean
          data转换成功后的值string,ArrayBuffer , null
          message转换成功或失败的原因string

          Options

          参数说明类型默认值
          file传入的文件File

          Example

          js
          import { convertImageToBase64 } from 'ranuts';
          +import{_ as t,o as s,c as e,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"convertImageToBase64","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/convertImageToBase64.md","filePath":"cn/src/ranuts/utils/convertImageToBase64.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/utils/convertImageToBase64.md"};function d(r,a,o,h,l,p){return s(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

          convertImageToBase64

          图片转base64

          API

          Return

          参数说明类型
          success是否转换成功boolean
          data转换成功后的值string,ArrayBuffer , null
          message转换成功或失败的原因string

          Options

          参数说明类型默认值
          file传入的文件File

          Example

          js
          import { convertImageToBase64 } from 'ranuts';
           
           convertImageToBase64(file).then((res) => {
             console.log(result);
          diff --git a/assets/cn_src_ranuts_utils_filterObj.md.DE1C38Kh.js b/assets/cn_src_ranuts_utils_filterObj.md.Dr_ls9ui.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_filterObj.md.DE1C38Kh.js
          rename to assets/cn_src_ranuts_utils_filterObj.md.Dr_ls9ui.js
          index adc918b8a0..9cbff198d3 100644
          --- a/assets/cn_src_ranuts_utils_filterObj.md.DE1C38Kh.js
          +++ b/assets/cn_src_ranuts_utils_filterObj.md.Dr_ls9ui.js
          @@ -1,4 +1,4 @@
          -import{_ as a,o as i,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"filterObj","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/filterObj.md","filePath":"cn/src/ranuts/utils/filterObj.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranuts/utils/filterObj.md"};function l(h,s,p,r,d,k){return i(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          filterObj

          过滤对象的属性,去除对象中在 list 数组里面有的属性,返回一个新对象,一般是用于去除空字符和 null

          API

          Return

          参数说明类型
          Object返回的一个对象Object

          Options

          参数说明类型默认值
          obj需要过滤的对象object
          list需要过滤的熟悉数组array

          Example

          js
          import { filterObj } from 'ranuts';
          +import{_ as a,o as i,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"filterObj","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/filterObj.md","filePath":"cn/src/ranuts/utils/filterObj.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranuts/utils/filterObj.md"};function l(h,s,p,r,d,k){return i(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          filterObj

          过滤对象的属性,去除对象中在 list 数组里面有的属性,返回一个新对象,一般是用于去除空字符和 null

          API

          Return

          参数说明类型
          Object返回的一个对象Object

          Options

          参数说明类型默认值
          obj需要过滤的对象object
          list需要过滤的熟悉数组array

          Example

          js
          import { filterObj } from 'ranuts';
           
           const obj = {
             name: 'chaxus',
          diff --git a/assets/cn_src_ranuts_utils_filterObj.md.DE1C38Kh.lean.js b/assets/cn_src_ranuts_utils_filterObj.md.Dr_ls9ui.lean.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_filterObj.md.DE1C38Kh.lean.js
          rename to assets/cn_src_ranuts_utils_filterObj.md.Dr_ls9ui.lean.js
          index adc918b8a0..9cbff198d3 100644
          --- a/assets/cn_src_ranuts_utils_filterObj.md.DE1C38Kh.lean.js
          +++ b/assets/cn_src_ranuts_utils_filterObj.md.Dr_ls9ui.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as a,o as i,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"filterObj","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/filterObj.md","filePath":"cn/src/ranuts/utils/filterObj.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranuts/utils/filterObj.md"};function l(h,s,p,r,d,k){return i(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          filterObj

          过滤对象的属性,去除对象中在 list 数组里面有的属性,返回一个新对象,一般是用于去除空字符和 null

          API

          Return

          参数说明类型
          Object返回的一个对象Object

          Options

          参数说明类型默认值
          obj需要过滤的对象object
          list需要过滤的熟悉数组array

          Example

          js
          import { filterObj } from 'ranuts';
          +import{_ as a,o as i,c as t,a3 as n}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"filterObj","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/filterObj.md","filePath":"cn/src/ranuts/utils/filterObj.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranuts/utils/filterObj.md"};function l(h,s,p,r,d,k){return i(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          filterObj

          过滤对象的属性,去除对象中在 list 数组里面有的属性,返回一个新对象,一般是用于去除空字符和 null

          API

          Return

          参数说明类型
          Object返回的一个对象Object

          Options

          参数说明类型默认值
          obj需要过滤的对象object
          list需要过滤的熟悉数组array

          Example

          js
          import { filterObj } from 'ranuts';
           
           const obj = {
             name: 'chaxus',
          diff --git a/assets/cn_src_ranuts_utils_formatJson.md.C6zYMUay.js b/assets/cn_src_ranuts_utils_formatJson.md.DAOEUsMy.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_formatJson.md.C6zYMUay.js
          rename to assets/cn_src_ranuts_utils_formatJson.md.DAOEUsMy.js
          index 3cecfe3717..635819b048 100644
          --- a/assets/cn_src_ranuts_utils_formatJson.md.C6zYMUay.js
          +++ b/assets/cn_src_ranuts_utils_formatJson.md.DAOEUsMy.js
          @@ -1,4 +1,4 @@
          -import{_ as a,o as t,c as i,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"formatJson","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/formatJson.md","filePath":"cn/src/ranuts/utils/formatJson.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranuts/utils/formatJson.md"};function h(l,s,r,d,p,o){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          formatJson

          传入一个 JSON 或者 JSON 的字符串,添加空格和换行进行返回一个格式化的 JSON 字符串

          API

          Return

          参数说明类型
          string返回的一个对象Object

          Options

          参数说明类型默认值
          json需要格式化的 JSON 对象object,string
          callback错误回调,可选function

          Example

          js
          import { formatJson } from 'ranuts';
          +import{_ as a,o as t,c as i,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"formatJson","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/formatJson.md","filePath":"cn/src/ranuts/utils/formatJson.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranuts/utils/formatJson.md"};function h(l,s,r,d,p,o){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          formatJson

          传入一个 JSON 或者 JSON 的字符串,添加空格和换行进行返回一个格式化的 JSON 字符串

          API

          Return

          参数说明类型
          string返回的一个对象Object

          Options

          参数说明类型默认值
          json需要格式化的 JSON 对象object,string
          callback错误回调,可选function

          Example

          js
          import { formatJson } from 'ranuts';
           
           const json = {
             name: 'chaxus',
          diff --git a/assets/cn_src_ranuts_utils_formatJson.md.C6zYMUay.lean.js b/assets/cn_src_ranuts_utils_formatJson.md.DAOEUsMy.lean.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_formatJson.md.C6zYMUay.lean.js
          rename to assets/cn_src_ranuts_utils_formatJson.md.DAOEUsMy.lean.js
          index 3cecfe3717..635819b048 100644
          --- a/assets/cn_src_ranuts_utils_formatJson.md.C6zYMUay.lean.js
          +++ b/assets/cn_src_ranuts_utils_formatJson.md.DAOEUsMy.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as a,o as t,c as i,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"formatJson","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/formatJson.md","filePath":"cn/src/ranuts/utils/formatJson.md","lastUpdated":1728828157000}'),e={name:"cn/src/ranuts/utils/formatJson.md"};function h(l,s,r,d,p,o){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          formatJson

          传入一个 JSON 或者 JSON 的字符串,添加空格和换行进行返回一个格式化的 JSON 字符串

          API

          Return

          参数说明类型
          string返回的一个对象Object

          Options

          参数说明类型默认值
          json需要格式化的 JSON 对象object,string
          callback错误回调,可选function

          Example

          js
          import { formatJson } from 'ranuts';
          +import{_ as a,o as t,c as i,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"formatJson","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/formatJson.md","filePath":"cn/src/ranuts/utils/formatJson.md","lastUpdated":1728921295000}'),e={name:"cn/src/ranuts/utils/formatJson.md"};function h(l,s,r,d,p,o){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

          formatJson

          传入一个 JSON 或者 JSON 的字符串,添加空格和换行进行返回一个格式化的 JSON 字符串

          API

          Return

          参数说明类型
          string返回的一个对象Object

          Options

          参数说明类型默认值
          json需要格式化的 JSON 对象object,string
          callback错误回调,可选function

          Example

          js
          import { formatJson } from 'ranuts';
           
           const json = {
             name: 'chaxus',
          diff --git a/assets/cn_src_ranuts_utils_getCookie.md.BomC6eQg.js b/assets/cn_src_ranuts_utils_getCookie.md.DbhTAbDg.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_getCookie.md.BomC6eQg.js
          rename to assets/cn_src_ranuts_utils_getCookie.md.DbhTAbDg.js
          index 10f62db624..aa0be15d21 100644
          --- a/assets/cn_src_ranuts_utils_getCookie.md.BomC6eQg.js
          +++ b/assets/cn_src_ranuts_utils_getCookie.md.DbhTAbDg.js
          @@ -1,4 +1,4 @@
          -import{_ as t,o as s,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getCookie","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/getCookie.md","filePath":"cn/src/ranuts/utils/getCookie.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/utils/getCookie.md"};function h(o,a,l,r,d,p){return s(),i("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

          getCookie

          传入字符串,获取指定名字的 cookie 的值

          API

          Return

          参数说明类型
          sting返回的一个指定名称的 cookie 的值string

          Options

          参数说明类型默认值
          name指定获取 cookie 的名称的值object

          Example

          js
          import { getCookie } from 'ranuts';
          +import{_ as t,o as s,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getCookie","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/getCookie.md","filePath":"cn/src/ranuts/utils/getCookie.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/utils/getCookie.md"};function h(o,a,l,r,d,p){return s(),i("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

          getCookie

          传入字符串,获取指定名字的 cookie 的值

          API

          Return

          参数说明类型
          sting返回的一个指定名称的 cookie 的值string

          Options

          参数说明类型默认值
          name指定获取 cookie 的名称的值object

          Example

          js
          import { getCookie } from 'ranuts';
           
           const result = getCookie('name');
           
          diff --git a/assets/cn_src_ranuts_utils_getCookie.md.BomC6eQg.lean.js b/assets/cn_src_ranuts_utils_getCookie.md.DbhTAbDg.lean.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_getCookie.md.BomC6eQg.lean.js
          rename to assets/cn_src_ranuts_utils_getCookie.md.DbhTAbDg.lean.js
          index 10f62db624..aa0be15d21 100644
          --- a/assets/cn_src_ranuts_utils_getCookie.md.BomC6eQg.lean.js
          +++ b/assets/cn_src_ranuts_utils_getCookie.md.DbhTAbDg.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as t,o as s,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getCookie","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/getCookie.md","filePath":"cn/src/ranuts/utils/getCookie.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/utils/getCookie.md"};function h(o,a,l,r,d,p){return s(),i("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

          getCookie

          传入字符串,获取指定名字的 cookie 的值

          API

          Return

          参数说明类型
          sting返回的一个指定名称的 cookie 的值string

          Options

          参数说明类型默认值
          name指定获取 cookie 的名称的值object

          Example

          js
          import { getCookie } from 'ranuts';
          +import{_ as t,o as s,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getCookie","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/getCookie.md","filePath":"cn/src/ranuts/utils/getCookie.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/utils/getCookie.md"};function h(o,a,l,r,d,p){return s(),i("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

          getCookie

          传入字符串,获取指定名字的 cookie 的值

          API

          Return

          参数说明类型
          sting返回的一个指定名称的 cookie 的值string

          Options

          参数说明类型默认值
          name指定获取 cookie 的名称的值object

          Example

          js
          import { getCookie } from 'ranuts';
           
           const result = getCookie('name');
           
          diff --git a/assets/cn_src_ranuts_utils_ocr.md.Bsfwykuh.js b/assets/cn_src_ranuts_utils_ocr.md.uNdytYyR.js
          similarity index 99%
          rename from assets/cn_src_ranuts_utils_ocr.md.Bsfwykuh.js
          rename to assets/cn_src_ranuts_utils_ocr.md.uNdytYyR.js
          index 1ccf661ee7..6a5f8416db 100644
          --- a/assets/cn_src_ranuts_utils_ocr.md.Bsfwykuh.js
          +++ b/assets/cn_src_ranuts_utils_ocr.md.uNdytYyR.js
          @@ -1,4 +1,4 @@
          -import{_ as d,o as a,c as r,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"OCR","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/ocr.md","filePath":"cn/src/ranuts/utils/ocr.md","lastUpdated":1728828157000}'),s={name:"cn/src/ranuts/utils/ocr.md"};function n(e,t,l,h,o,p){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

          OCR

          传入图片和对应的语言类型,返回图片中的文本。

          API

          Return

          参数说明类型
          success是否解析成功boolean
          data解析成功后的对象obj
          message解析成功或失败的原因string

          Options

          参数说明类型默认值
          images图片的数组,支持urlbase64Array<string>
          language指定生成文本的语言,具体参数见lang-codestring
          langPath使用的时候需要能访问cdn.jsdelivr.net,会下载对应的语言包,如果无法访问,也可以将语言包放在本地,传入对应的 目录 路径string可选参数,默认走网络下载

          Example

          js
          import { ocr } from 'ranuts';
          +import{_ as d,o as a,c as r,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"OCR","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/ocr.md","filePath":"cn/src/ranuts/utils/ocr.md","lastUpdated":1728921295000}'),s={name:"cn/src/ranuts/utils/ocr.md"};function n(e,t,l,h,o,p){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

          OCR

          传入图片和对应的语言类型,返回图片中的文本。

          API

          Return

          参数说明类型
          success是否解析成功boolean
          data解析成功后的对象obj
          message解析成功或失败的原因string

          Options

          参数说明类型默认值
          images图片的数组,支持urlbase64Array<string>
          language指定生成文本的语言,具体参数见lang-codestring
          langPath使用的时候需要能访问cdn.jsdelivr.net,会下载对应的语言包,如果无法访问,也可以将语言包放在本地,传入对应的 目录 路径string可选参数,默认走网络下载

          Example

          js
          import { ocr } from 'ranuts';
           
           const images = ['https://chaxus.github.io/ran/ocr/eng.png'];
           const languages = 'eng';
          diff --git a/assets/cn_src_ranuts_utils_ocr.md.Bsfwykuh.lean.js b/assets/cn_src_ranuts_utils_ocr.md.uNdytYyR.lean.js
          similarity index 99%
          rename from assets/cn_src_ranuts_utils_ocr.md.Bsfwykuh.lean.js
          rename to assets/cn_src_ranuts_utils_ocr.md.uNdytYyR.lean.js
          index 1ccf661ee7..6a5f8416db 100644
          --- a/assets/cn_src_ranuts_utils_ocr.md.Bsfwykuh.lean.js
          +++ b/assets/cn_src_ranuts_utils_ocr.md.uNdytYyR.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as d,o as a,c as r,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"OCR","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/ocr.md","filePath":"cn/src/ranuts/utils/ocr.md","lastUpdated":1728828157000}'),s={name:"cn/src/ranuts/utils/ocr.md"};function n(e,t,l,h,o,p){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

          OCR

          传入图片和对应的语言类型,返回图片中的文本。

          API

          Return

          参数说明类型
          success是否解析成功boolean
          data解析成功后的对象obj
          message解析成功或失败的原因string

          Options

          参数说明类型默认值
          images图片的数组,支持urlbase64Array<string>
          language指定生成文本的语言,具体参数见lang-codestring
          langPath使用的时候需要能访问cdn.jsdelivr.net,会下载对应的语言包,如果无法访问,也可以将语言包放在本地,传入对应的 目录 路径string可选参数,默认走网络下载

          Example

          js
          import { ocr } from 'ranuts';
          +import{_ as d,o as a,c as r,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"OCR","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/ocr.md","filePath":"cn/src/ranuts/utils/ocr.md","lastUpdated":1728921295000}'),s={name:"cn/src/ranuts/utils/ocr.md"};function n(e,t,l,h,o,p){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

          OCR

          传入图片和对应的语言类型,返回图片中的文本。

          API

          Return

          参数说明类型
          success是否解析成功boolean
          data解析成功后的对象obj
          message解析成功或失败的原因string

          Options

          参数说明类型默认值
          images图片的数组,支持urlbase64Array<string>
          language指定生成文本的语言,具体参数见lang-codestring
          langPath使用的时候需要能访问cdn.jsdelivr.net,会下载对应的语言包,如果无法访问,也可以将语言包放在本地,传入对应的 目录 路径string可选参数,默认走网络下载

          Example

          js
          import { ocr } from 'ranuts';
           
           const images = ['https://chaxus.github.io/ran/ocr/eng.png'];
           const languages = 'eng';
          diff --git a/assets/cn_src_ranuts_utils_str2xml.md.Bf-gtS9N.js b/assets/cn_src_ranuts_utils_str2xml.md.s2QXhzVM.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_str2xml.md.Bf-gtS9N.js
          rename to assets/cn_src_ranuts_utils_str2xml.md.s2QXhzVM.js
          index 729b6d5b08..e179d594f0 100644
          --- a/assets/cn_src_ranuts_utils_str2xml.md.Bf-gtS9N.js
          +++ b/assets/cn_src_ranuts_utils_str2xml.md.s2QXhzVM.js
          @@ -1,4 +1,4 @@
          -import{_ as s,o as a,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"str2Xml","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/str2xml.md","filePath":"cn/src/ranuts/utils/str2xml.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/utils/str2xml.md"};function l(d,t,h,o,r,p){return a(),i("div",{"data-pagefind-body":!0},t[0]||(t[0]=[e(`

          str2Xml

          传入字符串,转成xml

          API

          Return

          参数说明类型
          HTMLElement返回一个HTMLElementHTMLElement

          Options

          参数说明类型默认值
          xmlStr传入的参数string
          format设置需要转换的格式,默认text/xmlDOMParserSupportedType

          Example

          比如在做图标库的时候,我们需要动态导入目录下的所有icon。这时候导入的是字符串,但字符串无法添加到xml中。 因此我们需要将字符串转换成xml,然后就可以将它加入到xml中。

          js
          import { str2Xml } from 'ranuts';
          +import{_ as s,o as a,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"str2Xml","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/str2xml.md","filePath":"cn/src/ranuts/utils/str2xml.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/utils/str2xml.md"};function l(d,t,h,o,r,p){return a(),i("div",{"data-pagefind-body":!0},t[0]||(t[0]=[e(`

          str2Xml

          传入字符串,转成xml

          API

          Return

          参数说明类型
          HTMLElement返回一个HTMLElementHTMLElement

          Options

          参数说明类型默认值
          xmlStr传入的参数string
          format设置需要转换的格式,默认text/xmlDOMParserSupportedType

          Example

          比如在做图标库的时候,我们需要动态导入目录下的所有icon。这时候导入的是字符串,但字符串无法添加到xml中。 因此我们需要将字符串转换成xml,然后就可以将它加入到xml中。

          js
          import { str2Xml } from 'ranuts';
           
           // import 'assets/*.svg'
           const svg = \`<svg t="1667483498347" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8544" width="200" height="200"><path d="M858.5 763.6c-18.9-44.8-46.1-85-80.6-119.5-34.5-34.5-74.7-61.6-119.5-80.6-0.4-0.2-0.8-0.3-1.2-0.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-0.4 0.2-0.8 0.3-1.2 0.5-44.8 18.9-85 46-119.5 80.6-34.5 34.5-61.6 74.7-80.6 119.5C146.9 807.5 137 854 136 901.8c-0.1 4.5 3.5 8.2 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c0.1 4.4 3.6 7.8 8 7.8h60c4.5 0 8.1-3.7 8-8.2-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z" p-id="8545"></path></svg>\`;
          diff --git a/assets/cn_src_ranuts_utils_str2xml.md.Bf-gtS9N.lean.js b/assets/cn_src_ranuts_utils_str2xml.md.s2QXhzVM.lean.js
          similarity index 98%
          rename from assets/cn_src_ranuts_utils_str2xml.md.Bf-gtS9N.lean.js
          rename to assets/cn_src_ranuts_utils_str2xml.md.s2QXhzVM.lean.js
          index 729b6d5b08..e179d594f0 100644
          --- a/assets/cn_src_ranuts_utils_str2xml.md.Bf-gtS9N.lean.js
          +++ b/assets/cn_src_ranuts_utils_str2xml.md.s2QXhzVM.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as s,o as a,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"str2Xml","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/str2xml.md","filePath":"cn/src/ranuts/utils/str2xml.md","lastUpdated":1728828157000}'),n={name:"cn/src/ranuts/utils/str2xml.md"};function l(d,t,h,o,r,p){return a(),i("div",{"data-pagefind-body":!0},t[0]||(t[0]=[e(`

          str2Xml

          传入字符串,转成xml

          API

          Return

          参数说明类型
          HTMLElement返回一个HTMLElementHTMLElement

          Options

          参数说明类型默认值
          xmlStr传入的参数string
          format设置需要转换的格式,默认text/xmlDOMParserSupportedType

          Example

          比如在做图标库的时候,我们需要动态导入目录下的所有icon。这时候导入的是字符串,但字符串无法添加到xml中。 因此我们需要将字符串转换成xml,然后就可以将它加入到xml中。

          js
          import { str2Xml } from 'ranuts';
          +import{_ as s,o as a,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"str2Xml","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/str2xml.md","filePath":"cn/src/ranuts/utils/str2xml.md","lastUpdated":1728921295000}'),n={name:"cn/src/ranuts/utils/str2xml.md"};function l(d,t,h,o,r,p){return a(),i("div",{"data-pagefind-body":!0},t[0]||(t[0]=[e(`

          str2Xml

          传入字符串,转成xml

          API

          Return

          参数说明类型
          HTMLElement返回一个HTMLElementHTMLElement

          Options

          参数说明类型默认值
          xmlStr传入的参数string
          format设置需要转换的格式,默认text/xmlDOMParserSupportedType

          Example

          比如在做图标库的时候,我们需要动态导入目录下的所有icon。这时候导入的是字符串,但字符串无法添加到xml中。 因此我们需要将字符串转换成xml,然后就可以将它加入到xml中。

          js
          import { str2Xml } from 'ranuts';
           
           // import 'assets/*.svg'
           const svg = \`<svg t="1667483498347" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8544" width="200" height="200"><path d="M858.5 763.6c-18.9-44.8-46.1-85-80.6-119.5-34.5-34.5-74.7-61.6-119.5-80.6-0.4-0.2-0.8-0.3-1.2-0.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-0.4 0.2-0.8 0.3-1.2 0.5-44.8 18.9-85 46-119.5 80.6-34.5 34.5-61.6 74.7-80.6 119.5C146.9 807.5 137 854 136 901.8c-0.1 4.5 3.5 8.2 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c0.1 4.4 3.6 7.8 8 7.8h60c4.5 0 8.1-3.7 8-8.2-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z" p-id="8545"></path></svg>\`;
          diff --git a/assets/cn_src_ranuts_utils_task.md.DwcnyfHt.js b/assets/cn_src_ranuts_utils_task.md.DbClSCsQ.js
          similarity index 99%
          rename from assets/cn_src_ranuts_utils_task.md.DwcnyfHt.js
          rename to assets/cn_src_ranuts_utils_task.md.DbClSCsQ.js
          index 833362a227..a2aa7cf307 100644
          --- a/assets/cn_src_ranuts_utils_task.md.DwcnyfHt.js
          +++ b/assets/cn_src_ranuts_utils_task.md.DbClSCsQ.js
          @@ -1 +1 @@
          -import{_ as a,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"统计执行时间","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/task.md","filePath":"cn/src/ranuts/utils/task.md","lastUpdated":1728828157000}'),o={name:"cn/src/ranuts/utils/task.md"};function n(d,e,r,c,l,h){return t(),s("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

          统计执行时间

          有的时候,我们需要统计一个函数的执行时间,用于分析性能。因此封装了startTasktaskEnd函数。同时介绍其他三种统计方法

          1. new Date().getTime(),
          2. console.time()console.timeEnd(),
          3. performance.now()

          一.startTask,taskEnd

          1.startTask

          任务开始之前执行

          Return

          参数说明类型
          taskId任务标识unique symbol

          2.taskEnd

          任务结束的时候执行,需要传入startTask返回的任务标识

          Options

          参数说明类型默认值
          taskId任务标识unique symbol 无默认值,参数必传,否则无法识别是哪个任务

          Return

          参数说明类型
          timetask执行的时间number

          3.使用例子

          js
          const taskId = startTask();\n\n// do something\n\nconst time = taskEnd(taskId);\n\nconsole.log('task 执行花费的时间', time);

          二.new Date().getTime()

          new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

          1. 某些情况下,毫秒级精度可能不够。
          2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

            由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

          三.console.time(), console.timeEnd()

          启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

          四.performance.now()

          performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

          注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

          ',24)]))}const m=a(o,[["render",n]]);export{k as __pageData,m as default}; +import{_ as a,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"统计执行时间","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/task.md","filePath":"cn/src/ranuts/utils/task.md","lastUpdated":1728921295000}'),o={name:"cn/src/ranuts/utils/task.md"};function n(d,e,r,c,l,h){return t(),s("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

          统计执行时间

          有的时候,我们需要统计一个函数的执行时间,用于分析性能。因此封装了startTasktaskEnd函数。同时介绍其他三种统计方法

          1. new Date().getTime(),
          2. console.time()console.timeEnd(),
          3. performance.now()

          一.startTask,taskEnd

          1.startTask

          任务开始之前执行

          Return

          参数说明类型
          taskId任务标识unique symbol

          2.taskEnd

          任务结束的时候执行,需要传入startTask返回的任务标识

          Options

          参数说明类型默认值
          taskId任务标识unique symbol 无默认值,参数必传,否则无法识别是哪个任务

          Return

          参数说明类型
          timetask执行的时间number

          3.使用例子

          js
          const taskId = startTask();\n\n// do something\n\nconst time = taskEnd(taskId);\n\nconsole.log('task 执行花费的时间', time);

          二.new Date().getTime()

          new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

          1. 某些情况下,毫秒级精度可能不够。
          2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

            由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

          三.console.time(), console.timeEnd()

          启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

          四.performance.now()

          performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

          注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

          ',24)]))}const m=a(o,[["render",n]]);export{k as __pageData,m as default}; diff --git a/assets/cn_src_ranuts_utils_task.md.DwcnyfHt.lean.js b/assets/cn_src_ranuts_utils_task.md.DbClSCsQ.lean.js similarity index 99% rename from assets/cn_src_ranuts_utils_task.md.DwcnyfHt.lean.js rename to assets/cn_src_ranuts_utils_task.md.DbClSCsQ.lean.js index 833362a227..a2aa7cf307 100644 --- a/assets/cn_src_ranuts_utils_task.md.DwcnyfHt.lean.js +++ b/assets/cn_src_ranuts_utils_task.md.DbClSCsQ.lean.js @@ -1 +1 @@ -import{_ as a,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"统计执行时间","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/task.md","filePath":"cn/src/ranuts/utils/task.md","lastUpdated":1728828157000}'),o={name:"cn/src/ranuts/utils/task.md"};function n(d,e,r,c,l,h){return t(),s("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

          统计执行时间

          有的时候,我们需要统计一个函数的执行时间,用于分析性能。因此封装了startTasktaskEnd函数。同时介绍其他三种统计方法

          1. new Date().getTime(),
          2. console.time()console.timeEnd(),
          3. performance.now()

          一.startTask,taskEnd

          1.startTask

          任务开始之前执行

          Return

          参数说明类型
          taskId任务标识unique symbol

          2.taskEnd

          任务结束的时候执行,需要传入startTask返回的任务标识

          Options

          参数说明类型默认值
          taskId任务标识unique symbol 无默认值,参数必传,否则无法识别是哪个任务

          Return

          参数说明类型
          timetask执行的时间number

          3.使用例子

          js
          const taskId = startTask();\n\n// do something\n\nconst time = taskEnd(taskId);\n\nconsole.log('task 执行花费的时间', time);

          二.new Date().getTime()

          new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

          1. 某些情况下,毫秒级精度可能不够。
          2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

            由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

          三.console.time(), console.timeEnd()

          启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

          四.performance.now()

          performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

          注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

          ',24)]))}const m=a(o,[["render",n]]);export{k as __pageData,m as default}; +import{_ as a,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"统计执行时间","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/ranuts/utils/task.md","filePath":"cn/src/ranuts/utils/task.md","lastUpdated":1728921295000}'),o={name:"cn/src/ranuts/utils/task.md"};function n(d,e,r,c,l,h){return t(),s("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

          统计执行时间

          有的时候,我们需要统计一个函数的执行时间,用于分析性能。因此封装了startTasktaskEnd函数。同时介绍其他三种统计方法

          1. new Date().getTime(),
          2. console.time()console.timeEnd(),
          3. performance.now()

          一.startTask,taskEnd

          1.startTask

          任务开始之前执行

          Return

          参数说明类型
          taskId任务标识unique symbol

          2.taskEnd

          任务结束的时候执行,需要传入startTask返回的任务标识

          Options

          参数说明类型默认值
          taskId任务标识unique symbol 无默认值,参数必传,否则无法识别是哪个任务

          Return

          参数说明类型
          timetask执行的时间number

          3.使用例子

          js
          const taskId = startTask();\n\n// do something\n\nconst time = taskEnd(taskId);\n\nconsole.log('task 执行花费的时间', time);

          二.new Date().getTime()

          new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

          1. 某些情况下,毫秒级精度可能不够。
          2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

            由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

          三.console.time(), console.timeEnd()

          启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

          四.performance.now()

          performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

          注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

          ',24)]))}const m=a(o,[["render",n]]);export{k as __pageData,m as default}; diff --git "a/assets/cn_src_types_TS\347\261\273\345\236\213.md.BdnhcvJe.js" "b/assets/cn_src_types_TS\347\261\273\345\236\213.md.iJyVKiUM.js" similarity index 99% rename from "assets/cn_src_types_TS\347\261\273\345\236\213.md.BdnhcvJe.js" rename to "assets/cn_src_types_TS\347\261\273\345\236\213.md.iJyVKiUM.js" index 9d3be6bbf2..18b8665298 100644 --- "a/assets/cn_src_types_TS\347\261\273\345\236\213.md.BdnhcvJe.js" +++ "b/assets/cn_src_types_TS\347\261\273\345\236\213.md.iJyVKiUM.js" @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/TS类型.md","filePath":"cn/src/types/TS类型.md","lastUpdated":1728828157000}'),l={name:"cn/src/types/TS类型.md"};function t(p,s,k,e,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          TypeScript 类型系统中的类型

          1. 基本类型: number、boolean、string、object、bigint、symbol、undefined、null
          2. 复合类型: class、Array、元组(Tuple)、接口(Interface)、枚举(Enum)
          3. 特殊的类型:void、never、any、unknown

          Tuple

          元组(Tuple)就是元素个数和类型固定的数组类型:

          ts
          type Tuple = [number, string];

          Interface

          接口(Interface)可以描述函数、对象、构造器的结构:

          • 对象
          ts
          interface IPerson {
          +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/TS类型.md","filePath":"cn/src/types/TS类型.md","lastUpdated":1728921295000}'),l={name:"cn/src/types/TS类型.md"};function t(p,s,k,e,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          TypeScript 类型系统中的类型

          1. 基本类型: number、boolean、string、object、bigint、symbol、undefined、null
          2. 复合类型: class、Array、元组(Tuple)、接口(Interface)、枚举(Enum)
          3. 特殊的类型:void、never、any、unknown

          Tuple

          元组(Tuple)就是元素个数和类型固定的数组类型:

          ts
          type Tuple = [number, string];

          Interface

          接口(Interface)可以描述函数、对象、构造器的结构:

          • 对象
          ts
          interface IPerson {
             name: string;
             age: number;
           }
          diff --git "a/assets/cn_src_types_TS\347\261\273\345\236\213.md.BdnhcvJe.lean.js" "b/assets/cn_src_types_TS\347\261\273\345\236\213.md.iJyVKiUM.lean.js"
          similarity index 99%
          rename from "assets/cn_src_types_TS\347\261\273\345\236\213.md.BdnhcvJe.lean.js"
          rename to "assets/cn_src_types_TS\347\261\273\345\236\213.md.iJyVKiUM.lean.js"
          index 9d3be6bbf2..18b8665298 100644
          --- "a/assets/cn_src_types_TS\347\261\273\345\236\213.md.BdnhcvJe.lean.js"
          +++ "b/assets/cn_src_types_TS\347\261\273\345\236\213.md.iJyVKiUM.lean.js"
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/TS类型.md","filePath":"cn/src/types/TS类型.md","lastUpdated":1728828157000}'),l={name:"cn/src/types/TS类型.md"};function t(p,s,k,e,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          TypeScript 类型系统中的类型

          1. 基本类型: number、boolean、string、object、bigint、symbol、undefined、null
          2. 复合类型: class、Array、元组(Tuple)、接口(Interface)、枚举(Enum)
          3. 特殊的类型:void、never、any、unknown

          Tuple

          元组(Tuple)就是元素个数和类型固定的数组类型:

          ts
          type Tuple = [number, string];

          Interface

          接口(Interface)可以描述函数、对象、构造器的结构:

          • 对象
          ts
          interface IPerson {
          +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/TS类型.md","filePath":"cn/src/types/TS类型.md","lastUpdated":1728921295000}'),l={name:"cn/src/types/TS类型.md"};function t(p,s,k,e,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

          TypeScript 类型系统中的类型

          1. 基本类型: number、boolean、string、object、bigint、symbol、undefined、null
          2. 复合类型: class、Array、元组(Tuple)、接口(Interface)、枚举(Enum)
          3. 特殊的类型:void、never、any、unknown

          Tuple

          元组(Tuple)就是元素个数和类型固定的数组类型:

          ts
          type Tuple = [number, string];

          Interface

          接口(Interface)可以描述函数、对象、构造器的结构:

          • 对象
          ts
          interface IPerson {
             name: string;
             age: number;
           }
          diff --git "a/assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.LMxiYHqa.js" "b/assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CpwnVZOP.js"
          similarity index 99%
          rename from "assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.LMxiYHqa.js"
          rename to "assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CpwnVZOP.js"
          index 3a9656b76c..aff6f336fc 100644
          --- "a/assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.LMxiYHqa.js"
          +++ "b/assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CpwnVZOP.js"
          @@ -1 +1 @@
          -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"模式匹配","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/模式匹配.md","filePath":"cn/src/types/模式匹配.md","lastUpdated":1728828157000}'),k={name:"cn/src/types/模式匹配.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

          模式匹配

          Typescript 的类型也同样可以做模式匹配。

          比如这样一个 Promise 类型:

          ts
          type p = Promise<'value'>;

          我们想提取 value 的类型,可以这样做:

          ts
          type GetPromiseValue<T> = T extends Promise<infer value> ? value : never;

          通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

          ts
          type result = GetPromiseValue<Promise<'name'>>; // name

          数组类型

          数组类型想提取第一个元素的类型怎么做呢?

          ts
          type arr = [1, 2, 3];

          用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

          ts
          type GetArrayFirstItem<T extends unknown[]> = T extends [infer value, ...unknown[]] ? value : never;

          类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unknown 也就是可以是任何值。

          any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

          对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type result = GetArrayFirstItem<[1, 2, 3]>; // 1

          当类型参数 Arr 为 [] 时:

          ts
          type result = GetArrayFirstItem<[]>; // never

          可以提取第一个元素,当然也可以提取最后一个元素,修改下模式类型就行:

          ts
          type GetArrayLastItem<T extends unknown[]> = T extends [...unknown[],inter L] ? L : never

          我们分别取了首尾元素,当然也可以取剩余的数组,比如取去掉了最后一个元素的数组:

          ts
          type Pop<T extends unknown[]> = T extends [] ? [] : T extends [...infer Rest, unknown] ? Rest : never;

          如果是空数组,就直接返回,否则匹配剩余的元素,放到 infer 声明的局部变量 Rest 里,返回 Rest。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type Result = Pop<[1, 2, 3]>; // [1,2]

          当类型参数 Arr 为 [] 时:

          ts
          type Result = Pop<[]>; // []

          同理可得 ShiftArr 的实现:

          ts
          type Shift<T extends unknown[]> = T extends [] ? [] : T extends [unknown, ...infer Rest] ? Rest : never;

          字符串类型也同样可以做模式匹配,匹配一个模式字符串,把需要提取的部分放到 infer 声明的局部变量里。

          判断字符串是否以某个前缀开头,也是通过模式匹配:

          ts
          type StartWidth<S extends string, P extends string> = S extends `${P}${string}` ? true : false;

          需要声明字符串 Str、匹配的前缀 Prefix 两个类型参数,它们都是 string。

          用 Str 去匹配一个模式类型,模式类型的前缀是 Prefix,后面是任意的 string,如果匹配返回 true,否则返回 false。

          字符串可以匹配一个模式类型,提取想要的部分,自然也可以用这些再构成一个新的类型。

          比如实现字符串替换:

          ts
          type Replace<S extends string, F extends string, T extends string> = S extends `${infer P}${F}${infer L}`\n  ? `${P}${T}${L}`\n  : S;

          声明要替换的字符串 Str、待替换的字符串 From、替换成的字符串 3 个类型参数,通过 extends 约束为都是 string 类型。

          用 Str 去匹配模式串,模式串由 From 和之前之后的字符串构成,把之前之后的字符串放到通过 infer 声明的局部变量 Prefix、Suffix 里。

          用 Prefix、Suffix 加上替换到的字符串 To 构造成新的字符串类型返回。

          Trim

          能够匹配和替换字符串,那也就能实现去掉空白字符的 Trim:

          不过因为我们不知道有多少个空白字符,所以只能一个个匹配和去掉,需要递归。

          先实现 TrimRight:

          ts
          type TrimRight<S extends string> = S extends `${infer Rest}${' ' | '\\n' | '\\t'}` ? TrimRight<Rest> : S;

          类型参数 Str 是要 Trim 的字符串。

          如果 Str 匹配字符串 + 空白字符 (空格、换行、制表符),那就把字符串放到 infer 声明的局部变量 Rest 里。

          把 Rest 作为类型参数递归 TrimRight,直到不匹配,这时的类型参数 Str 就是处理结果。

          同理可得 TrimLeft:

          ts
          type TrimLeft<S extends string> = S extends `${' ' | '\\n' | '\\t'}${infer Rest}` ? TrimLeft<Rest> : S;

          TrimRight 和 TrimLeft 结合就是 Trim:

          ts
          type Trim<S extends string> = TrimLeft<TrimRight<S>>;

          函数

          函数同样也可以做类型匹配,比如提取参数、返回值的类型。

          GetParameters

          函数类型可以通过模式匹配来提取参数的类型:

          ts
          type GetParameters<T extends Function> = T extends (...args: infer A) => unknown ? A : never;

          类型参数 Func 是要匹配的函数类型,通过 extends 约束为 Function。

          Func 和模式类型做匹配,参数类型放到用 infer 声明的局部变量 Args 里,返回值可以是任何类型,用 unknown。

          返回提取到的参数类型 Args。

          GetReturnType

          ts
          type GetReturnType<T extends Function> = T extends (...args: unknown[]) => infer R ? R : never;

          Func 和模式类型做匹配,提取返回值到通过 infer 声明的局部变量 ReturnType 里返回。

          参数类型可以是任意类型,也就是 any[](注意,这里不能用 unknown,这里的解释涉及到参数的逆变性质,具体原因逆变那一节会解释)。

          GetThisParameterType

          方法里可以调用 this,用对象.方法名的方式调用的时候,this 就指向那个对象。

          但是方法也可以用 call 或者 apply 调用,call 调用的时候,this 就变了,但这里却没有被检查出来 this 指向的错误。

          这里的 this 类型同样也可以通过模式匹配提取出来:

          ts
          type GetThisParameterType<T extends Function> = T extends (this: infer H, ...args: unknown[]) => unknown ? H : unknown;

          构造器

          构造器和函数的区别是,构造器是用于创建对象的,所以可以被 new。

          同样,我们也可以通过模式匹配提取构造器的参数和返回值的类型:

          GetInstanceType

          构造器类型可以用 interface 声明,使用 new(): xx 的语法。

          ts
          interface Person {\n  name: string;\n}\n\ninterface PersonConstructor {\n  new (name: string): Person;\n}

          这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

          ts
          type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T\n  ? T\n  : unknown;
          ',79)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"模式匹配","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/模式匹配.md","filePath":"cn/src/types/模式匹配.md","lastUpdated":1728921295000}'),k={name:"cn/src/types/模式匹配.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

          模式匹配

          Typescript 的类型也同样可以做模式匹配。

          比如这样一个 Promise 类型:

          ts
          type p = Promise<'value'>;

          我们想提取 value 的类型,可以这样做:

          ts
          type GetPromiseValue<T> = T extends Promise<infer value> ? value : never;

          通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

          ts
          type result = GetPromiseValue<Promise<'name'>>; // name

          数组类型

          数组类型想提取第一个元素的类型怎么做呢?

          ts
          type arr = [1, 2, 3];

          用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

          ts
          type GetArrayFirstItem<T extends unknown[]> = T extends [infer value, ...unknown[]] ? value : never;

          类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unknown 也就是可以是任何值。

          any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

          对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type result = GetArrayFirstItem<[1, 2, 3]>; // 1

          当类型参数 Arr 为 [] 时:

          ts
          type result = GetArrayFirstItem<[]>; // never

          可以提取第一个元素,当然也可以提取最后一个元素,修改下模式类型就行:

          ts
          type GetArrayLastItem<T extends unknown[]> = T extends [...unknown[],inter L] ? L : never

          我们分别取了首尾元素,当然也可以取剩余的数组,比如取去掉了最后一个元素的数组:

          ts
          type Pop<T extends unknown[]> = T extends [] ? [] : T extends [...infer Rest, unknown] ? Rest : never;

          如果是空数组,就直接返回,否则匹配剩余的元素,放到 infer 声明的局部变量 Rest 里,返回 Rest。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type Result = Pop<[1, 2, 3]>; // [1,2]

          当类型参数 Arr 为 [] 时:

          ts
          type Result = Pop<[]>; // []

          同理可得 ShiftArr 的实现:

          ts
          type Shift<T extends unknown[]> = T extends [] ? [] : T extends [unknown, ...infer Rest] ? Rest : never;

          字符串类型也同样可以做模式匹配,匹配一个模式字符串,把需要提取的部分放到 infer 声明的局部变量里。

          判断字符串是否以某个前缀开头,也是通过模式匹配:

          ts
          type StartWidth<S extends string, P extends string> = S extends `${P}${string}` ? true : false;

          需要声明字符串 Str、匹配的前缀 Prefix 两个类型参数,它们都是 string。

          用 Str 去匹配一个模式类型,模式类型的前缀是 Prefix,后面是任意的 string,如果匹配返回 true,否则返回 false。

          字符串可以匹配一个模式类型,提取想要的部分,自然也可以用这些再构成一个新的类型。

          比如实现字符串替换:

          ts
          type Replace<S extends string, F extends string, T extends string> = S extends `${infer P}${F}${infer L}`\n  ? `${P}${T}${L}`\n  : S;

          声明要替换的字符串 Str、待替换的字符串 From、替换成的字符串 3 个类型参数,通过 extends 约束为都是 string 类型。

          用 Str 去匹配模式串,模式串由 From 和之前之后的字符串构成,把之前之后的字符串放到通过 infer 声明的局部变量 Prefix、Suffix 里。

          用 Prefix、Suffix 加上替换到的字符串 To 构造成新的字符串类型返回。

          Trim

          能够匹配和替换字符串,那也就能实现去掉空白字符的 Trim:

          不过因为我们不知道有多少个空白字符,所以只能一个个匹配和去掉,需要递归。

          先实现 TrimRight:

          ts
          type TrimRight<S extends string> = S extends `${infer Rest}${' ' | '\\n' | '\\t'}` ? TrimRight<Rest> : S;

          类型参数 Str 是要 Trim 的字符串。

          如果 Str 匹配字符串 + 空白字符 (空格、换行、制表符),那就把字符串放到 infer 声明的局部变量 Rest 里。

          把 Rest 作为类型参数递归 TrimRight,直到不匹配,这时的类型参数 Str 就是处理结果。

          同理可得 TrimLeft:

          ts
          type TrimLeft<S extends string> = S extends `${' ' | '\\n' | '\\t'}${infer Rest}` ? TrimLeft<Rest> : S;

          TrimRight 和 TrimLeft 结合就是 Trim:

          ts
          type Trim<S extends string> = TrimLeft<TrimRight<S>>;

          函数

          函数同样也可以做类型匹配,比如提取参数、返回值的类型。

          GetParameters

          函数类型可以通过模式匹配来提取参数的类型:

          ts
          type GetParameters<T extends Function> = T extends (...args: infer A) => unknown ? A : never;

          类型参数 Func 是要匹配的函数类型,通过 extends 约束为 Function。

          Func 和模式类型做匹配,参数类型放到用 infer 声明的局部变量 Args 里,返回值可以是任何类型,用 unknown。

          返回提取到的参数类型 Args。

          GetReturnType

          ts
          type GetReturnType<T extends Function> = T extends (...args: unknown[]) => infer R ? R : never;

          Func 和模式类型做匹配,提取返回值到通过 infer 声明的局部变量 ReturnType 里返回。

          参数类型可以是任意类型,也就是 any[](注意,这里不能用 unknown,这里的解释涉及到参数的逆变性质,具体原因逆变那一节会解释)。

          GetThisParameterType

          方法里可以调用 this,用对象.方法名的方式调用的时候,this 就指向那个对象。

          但是方法也可以用 call 或者 apply 调用,call 调用的时候,this 就变了,但这里却没有被检查出来 this 指向的错误。

          这里的 this 类型同样也可以通过模式匹配提取出来:

          ts
          type GetThisParameterType<T extends Function> = T extends (this: infer H, ...args: unknown[]) => unknown ? H : unknown;

          构造器

          构造器和函数的区别是,构造器是用于创建对象的,所以可以被 new。

          同样,我们也可以通过模式匹配提取构造器的参数和返回值的类型:

          GetInstanceType

          构造器类型可以用 interface 声明,使用 new(): xx 的语法。

          ts
          interface Person {\n  name: string;\n}\n\ninterface PersonConstructor {\n  new (name: string): Person;\n}

          这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

          ts
          type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T\n  ? T\n  : unknown;
          ',79)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; diff --git "a/assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.LMxiYHqa.lean.js" "b/assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CpwnVZOP.lean.js" similarity index 99% rename from "assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.LMxiYHqa.lean.js" rename to "assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CpwnVZOP.lean.js" index 3a9656b76c..aff6f336fc 100644 --- "a/assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.LMxiYHqa.lean.js" +++ "b/assets/cn_src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CpwnVZOP.lean.js" @@ -1 +1 @@ -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"模式匹配","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/模式匹配.md","filePath":"cn/src/types/模式匹配.md","lastUpdated":1728828157000}'),k={name:"cn/src/types/模式匹配.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

          模式匹配

          Typescript 的类型也同样可以做模式匹配。

          比如这样一个 Promise 类型:

          ts
          type p = Promise<'value'>;

          我们想提取 value 的类型,可以这样做:

          ts
          type GetPromiseValue<T> = T extends Promise<infer value> ? value : never;

          通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

          ts
          type result = GetPromiseValue<Promise<'name'>>; // name

          数组类型

          数组类型想提取第一个元素的类型怎么做呢?

          ts
          type arr = [1, 2, 3];

          用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

          ts
          type GetArrayFirstItem<T extends unknown[]> = T extends [infer value, ...unknown[]] ? value : never;

          类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unknown 也就是可以是任何值。

          any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

          对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type result = GetArrayFirstItem<[1, 2, 3]>; // 1

          当类型参数 Arr 为 [] 时:

          ts
          type result = GetArrayFirstItem<[]>; // never

          可以提取第一个元素,当然也可以提取最后一个元素,修改下模式类型就行:

          ts
          type GetArrayLastItem<T extends unknown[]> = T extends [...unknown[],inter L] ? L : never

          我们分别取了首尾元素,当然也可以取剩余的数组,比如取去掉了最后一个元素的数组:

          ts
          type Pop<T extends unknown[]> = T extends [] ? [] : T extends [...infer Rest, unknown] ? Rest : never;

          如果是空数组,就直接返回,否则匹配剩余的元素,放到 infer 声明的局部变量 Rest 里,返回 Rest。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type Result = Pop<[1, 2, 3]>; // [1,2]

          当类型参数 Arr 为 [] 时:

          ts
          type Result = Pop<[]>; // []

          同理可得 ShiftArr 的实现:

          ts
          type Shift<T extends unknown[]> = T extends [] ? [] : T extends [unknown, ...infer Rest] ? Rest : never;

          字符串类型也同样可以做模式匹配,匹配一个模式字符串,把需要提取的部分放到 infer 声明的局部变量里。

          判断字符串是否以某个前缀开头,也是通过模式匹配:

          ts
          type StartWidth<S extends string, P extends string> = S extends `${P}${string}` ? true : false;

          需要声明字符串 Str、匹配的前缀 Prefix 两个类型参数,它们都是 string。

          用 Str 去匹配一个模式类型,模式类型的前缀是 Prefix,后面是任意的 string,如果匹配返回 true,否则返回 false。

          字符串可以匹配一个模式类型,提取想要的部分,自然也可以用这些再构成一个新的类型。

          比如实现字符串替换:

          ts
          type Replace<S extends string, F extends string, T extends string> = S extends `${infer P}${F}${infer L}`\n  ? `${P}${T}${L}`\n  : S;

          声明要替换的字符串 Str、待替换的字符串 From、替换成的字符串 3 个类型参数,通过 extends 约束为都是 string 类型。

          用 Str 去匹配模式串,模式串由 From 和之前之后的字符串构成,把之前之后的字符串放到通过 infer 声明的局部变量 Prefix、Suffix 里。

          用 Prefix、Suffix 加上替换到的字符串 To 构造成新的字符串类型返回。

          Trim

          能够匹配和替换字符串,那也就能实现去掉空白字符的 Trim:

          不过因为我们不知道有多少个空白字符,所以只能一个个匹配和去掉,需要递归。

          先实现 TrimRight:

          ts
          type TrimRight<S extends string> = S extends `${infer Rest}${' ' | '\\n' | '\\t'}` ? TrimRight<Rest> : S;

          类型参数 Str 是要 Trim 的字符串。

          如果 Str 匹配字符串 + 空白字符 (空格、换行、制表符),那就把字符串放到 infer 声明的局部变量 Rest 里。

          把 Rest 作为类型参数递归 TrimRight,直到不匹配,这时的类型参数 Str 就是处理结果。

          同理可得 TrimLeft:

          ts
          type TrimLeft<S extends string> = S extends `${' ' | '\\n' | '\\t'}${infer Rest}` ? TrimLeft<Rest> : S;

          TrimRight 和 TrimLeft 结合就是 Trim:

          ts
          type Trim<S extends string> = TrimLeft<TrimRight<S>>;

          函数

          函数同样也可以做类型匹配,比如提取参数、返回值的类型。

          GetParameters

          函数类型可以通过模式匹配来提取参数的类型:

          ts
          type GetParameters<T extends Function> = T extends (...args: infer A) => unknown ? A : never;

          类型参数 Func 是要匹配的函数类型,通过 extends 约束为 Function。

          Func 和模式类型做匹配,参数类型放到用 infer 声明的局部变量 Args 里,返回值可以是任何类型,用 unknown。

          返回提取到的参数类型 Args。

          GetReturnType

          ts
          type GetReturnType<T extends Function> = T extends (...args: unknown[]) => infer R ? R : never;

          Func 和模式类型做匹配,提取返回值到通过 infer 声明的局部变量 ReturnType 里返回。

          参数类型可以是任意类型,也就是 any[](注意,这里不能用 unknown,这里的解释涉及到参数的逆变性质,具体原因逆变那一节会解释)。

          GetThisParameterType

          方法里可以调用 this,用对象.方法名的方式调用的时候,this 就指向那个对象。

          但是方法也可以用 call 或者 apply 调用,call 调用的时候,this 就变了,但这里却没有被检查出来 this 指向的错误。

          这里的 this 类型同样也可以通过模式匹配提取出来:

          ts
          type GetThisParameterType<T extends Function> = T extends (this: infer H, ...args: unknown[]) => unknown ? H : unknown;

          构造器

          构造器和函数的区别是,构造器是用于创建对象的,所以可以被 new。

          同样,我们也可以通过模式匹配提取构造器的参数和返回值的类型:

          GetInstanceType

          构造器类型可以用 interface 声明,使用 new(): xx 的语法。

          ts
          interface Person {\n  name: string;\n}\n\ninterface PersonConstructor {\n  new (name: string): Person;\n}

          这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

          ts
          type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T\n  ? T\n  : unknown;
          ',79)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"模式匹配","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/模式匹配.md","filePath":"cn/src/types/模式匹配.md","lastUpdated":1728921295000}'),k={name:"cn/src/types/模式匹配.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

          模式匹配

          Typescript 的类型也同样可以做模式匹配。

          比如这样一个 Promise 类型:

          ts
          type p = Promise<'value'>;

          我们想提取 value 的类型,可以这样做:

          ts
          type GetPromiseValue<T> = T extends Promise<infer value> ? value : never;

          通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

          ts
          type result = GetPromiseValue<Promise<'name'>>; // name

          数组类型

          数组类型想提取第一个元素的类型怎么做呢?

          ts
          type arr = [1, 2, 3];

          用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

          ts
          type GetArrayFirstItem<T extends unknown[]> = T extends [infer value, ...unknown[]] ? value : never;

          类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unknown 也就是可以是任何值。

          any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

          对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type result = GetArrayFirstItem<[1, 2, 3]>; // 1

          当类型参数 Arr 为 [] 时:

          ts
          type result = GetArrayFirstItem<[]>; // never

          可以提取第一个元素,当然也可以提取最后一个元素,修改下模式类型就行:

          ts
          type GetArrayLastItem<T extends unknown[]> = T extends [...unknown[],inter L] ? L : never

          我们分别取了首尾元素,当然也可以取剩余的数组,比如取去掉了最后一个元素的数组:

          ts
          type Pop<T extends unknown[]> = T extends [] ? [] : T extends [...infer Rest, unknown] ? Rest : never;

          如果是空数组,就直接返回,否则匹配剩余的元素,放到 infer 声明的局部变量 Rest 里,返回 Rest。

          当类型参数 Arr 为 [1,2,3] 时:

          ts
          type Result = Pop<[1, 2, 3]>; // [1,2]

          当类型参数 Arr 为 [] 时:

          ts
          type Result = Pop<[]>; // []

          同理可得 ShiftArr 的实现:

          ts
          type Shift<T extends unknown[]> = T extends [] ? [] : T extends [unknown, ...infer Rest] ? Rest : never;

          字符串类型也同样可以做模式匹配,匹配一个模式字符串,把需要提取的部分放到 infer 声明的局部变量里。

          判断字符串是否以某个前缀开头,也是通过模式匹配:

          ts
          type StartWidth<S extends string, P extends string> = S extends `${P}${string}` ? true : false;

          需要声明字符串 Str、匹配的前缀 Prefix 两个类型参数,它们都是 string。

          用 Str 去匹配一个模式类型,模式类型的前缀是 Prefix,后面是任意的 string,如果匹配返回 true,否则返回 false。

          字符串可以匹配一个模式类型,提取想要的部分,自然也可以用这些再构成一个新的类型。

          比如实现字符串替换:

          ts
          type Replace<S extends string, F extends string, T extends string> = S extends `${infer P}${F}${infer L}`\n  ? `${P}${T}${L}`\n  : S;

          声明要替换的字符串 Str、待替换的字符串 From、替换成的字符串 3 个类型参数,通过 extends 约束为都是 string 类型。

          用 Str 去匹配模式串,模式串由 From 和之前之后的字符串构成,把之前之后的字符串放到通过 infer 声明的局部变量 Prefix、Suffix 里。

          用 Prefix、Suffix 加上替换到的字符串 To 构造成新的字符串类型返回。

          Trim

          能够匹配和替换字符串,那也就能实现去掉空白字符的 Trim:

          不过因为我们不知道有多少个空白字符,所以只能一个个匹配和去掉,需要递归。

          先实现 TrimRight:

          ts
          type TrimRight<S extends string> = S extends `${infer Rest}${' ' | '\\n' | '\\t'}` ? TrimRight<Rest> : S;

          类型参数 Str 是要 Trim 的字符串。

          如果 Str 匹配字符串 + 空白字符 (空格、换行、制表符),那就把字符串放到 infer 声明的局部变量 Rest 里。

          把 Rest 作为类型参数递归 TrimRight,直到不匹配,这时的类型参数 Str 就是处理结果。

          同理可得 TrimLeft:

          ts
          type TrimLeft<S extends string> = S extends `${' ' | '\\n' | '\\t'}${infer Rest}` ? TrimLeft<Rest> : S;

          TrimRight 和 TrimLeft 结合就是 Trim:

          ts
          type Trim<S extends string> = TrimLeft<TrimRight<S>>;

          函数

          函数同样也可以做类型匹配,比如提取参数、返回值的类型。

          GetParameters

          函数类型可以通过模式匹配来提取参数的类型:

          ts
          type GetParameters<T extends Function> = T extends (...args: infer A) => unknown ? A : never;

          类型参数 Func 是要匹配的函数类型,通过 extends 约束为 Function。

          Func 和模式类型做匹配,参数类型放到用 infer 声明的局部变量 Args 里,返回值可以是任何类型,用 unknown。

          返回提取到的参数类型 Args。

          GetReturnType

          ts
          type GetReturnType<T extends Function> = T extends (...args: unknown[]) => infer R ? R : never;

          Func 和模式类型做匹配,提取返回值到通过 infer 声明的局部变量 ReturnType 里返回。

          参数类型可以是任意类型,也就是 any[](注意,这里不能用 unknown,这里的解释涉及到参数的逆变性质,具体原因逆变那一节会解释)。

          GetThisParameterType

          方法里可以调用 this,用对象.方法名的方式调用的时候,this 就指向那个对象。

          但是方法也可以用 call 或者 apply 调用,call 调用的时候,this 就变了,但这里却没有被检查出来 this 指向的错误。

          这里的 this 类型同样也可以通过模式匹配提取出来:

          ts
          type GetThisParameterType<T extends Function> = T extends (this: infer H, ...args: unknown[]) => unknown ? H : unknown;

          构造器

          构造器和函数的区别是,构造器是用于创建对象的,所以可以被 new。

          同样,我们也可以通过模式匹配提取构造器的参数和返回值的类型:

          GetInstanceType

          构造器类型可以用 interface 声明,使用 new(): xx 的语法。

          ts
          interface Person {\n  name: string;\n}\n\ninterface PersonConstructor {\n  new (name: string): Person;\n}

          这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

          ts
          type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T\n  ? T\n  : unknown;
          ',79)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; diff --git "a/assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Q4zNTo0P.js" "b/assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.HXO7_zmg.js" similarity index 99% rename from "assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Q4zNTo0P.js" rename to "assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.HXO7_zmg.js" index 06dde7545b..c61c9b897e 100644 --- "a/assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Q4zNTo0P.js" +++ "b/assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.HXO7_zmg.js" @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型运算","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/类型运算.md","filePath":"cn/src/types/类型运算.md","lastUpdated":1728828157000}'),n={name:"cn/src/types/类型运算.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          TypeScript 类型系统中的类型运算

          条件:extends ? :

          TypeScript 里的条件判断是 extends ? :,叫做条件类型(Conditional Type)比如:

          ts
          type isTwo<T> = T extends 2 ? true : false;
          +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型运算","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/类型运算.md","filePath":"cn/src/types/类型运算.md","lastUpdated":1728921295000}'),n={name:"cn/src/types/类型运算.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          TypeScript 类型系统中的类型运算

          条件:extends ? :

          TypeScript 里的条件判断是 extends ? :,叫做条件类型(Conditional Type)比如:

          ts
          type isTwo<T> = T extends 2 ? true : false;
           
           type res = isTwo<1>; // true
           type res2 = isTwo<2>; // false

          这种类型也叫做高级类型。

          高级类型的特点是传入类型参数,经过一系列类型运算逻辑后,返回新的类型。

          推导:infer

          如何提取类型的一部分呢?答案是 infer。

          比如提取元组类型的第一个元素:

          ts
          type FirstTupleItem<Tuple extends unknown[]> = Tuple extends [infer T, ...inter R] ? T : never;
          diff --git "a/assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Q4zNTo0P.lean.js" "b/assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.HXO7_zmg.lean.js"
          similarity index 99%
          rename from "assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Q4zNTo0P.lean.js"
          rename to "assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.HXO7_zmg.lean.js"
          index 06dde7545b..c61c9b897e 100644
          --- "a/assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Q4zNTo0P.lean.js"
          +++ "b/assets/cn_src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.HXO7_zmg.lean.js"
          @@ -1,4 +1,4 @@
          -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型运算","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/类型运算.md","filePath":"cn/src/types/类型运算.md","lastUpdated":1728828157000}'),n={name:"cn/src/types/类型运算.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          TypeScript 类型系统中的类型运算

          条件:extends ? :

          TypeScript 里的条件判断是 extends ? :,叫做条件类型(Conditional Type)比如:

          ts
          type isTwo<T> = T extends 2 ? true : false;
          +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型运算","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/类型运算.md","filePath":"cn/src/types/类型运算.md","lastUpdated":1728921295000}'),n={name:"cn/src/types/类型运算.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

          TypeScript 类型系统中的类型运算

          条件:extends ? :

          TypeScript 里的条件判断是 extends ? :,叫做条件类型(Conditional Type)比如:

          ts
          type isTwo<T> = T extends 2 ? true : false;
           
           type res = isTwo<1>; // true
           type res2 = isTwo<2>; // false

          这种类型也叫做高级类型。

          高级类型的特点是传入类型参数,经过一系列类型运算逻辑后,返回新的类型。

          推导:infer

          如何提取类型的一部分呢?答案是 infer。

          比如提取元组类型的第一个元素:

          ts
          type FirstTupleItem<Tuple extends unknown[]> = Tuple extends [infer T, ...inter R] ? T : never;
          diff --git "a/assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CX5Or8t7.js" "b/assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DshdJwmZ.js"
          similarity index 98%
          rename from "assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CX5Or8t7.js"
          rename to "assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DshdJwmZ.js"
          index 4a1f007012..78a22e5b4a 100644
          --- "a/assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CX5Or8t7.js"
          +++ "b/assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DshdJwmZ.js"
          @@ -1 +1 @@
          -import{_ as e,o as r,c as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"TypeScript 内置的高级类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/高级类型.md","filePath":"cn/src/types/高级类型.md","lastUpdated":1728828157000}'),o={name:"cn/src/types/高级类型.md"};function l(n,a,h,c,s,d){return r(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          TypeScript 内置的高级类型

          Parameters

          Parameters 用于提取函数类型的参数类型。

          ReturnType

          ReturnType 用于提取函数类型的返回值类型。

          ConstructorParameters

          构造器类型和函数类型的区别就是可以被 new。

          Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

          InstanceType

          提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

          ThisParameterType

          OmitThisParameter

          Partial

          Required

          Readonly

          Pick

          Record

          Exclude

          Extract

          Omit

          Awaited

          NonNullable

          Uppercase

          Lowercase

          Capitalize

          Uncapitalize

          总结

          比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

          用模式匹配 + 重新构造可以实现:OmitThisParameter

          用重新构造可以实现:Partial、Required、Readonly、Pick、Record

          用模式匹配 + 递归可以实现: Awaited

          用联合类型在分布式条件类型的特性可以实现: Exclude

          此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

          ',33)]))}const m=e(o,[["render",l]]);export{u as __pageData,m as default}; +import{_ as e,o as r,c as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"TypeScript 内置的高级类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/高级类型.md","filePath":"cn/src/types/高级类型.md","lastUpdated":1728921295000}'),o={name:"cn/src/types/高级类型.md"};function l(n,a,h,c,s,d){return r(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          TypeScript 内置的高级类型

          Parameters

          Parameters 用于提取函数类型的参数类型。

          ReturnType

          ReturnType 用于提取函数类型的返回值类型。

          ConstructorParameters

          构造器类型和函数类型的区别就是可以被 new。

          Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

          InstanceType

          提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

          ThisParameterType

          OmitThisParameter

          Partial

          Required

          Readonly

          Pick

          Record

          Exclude

          Extract

          Omit

          Awaited

          NonNullable

          Uppercase

          Lowercase

          Capitalize

          Uncapitalize

          总结

          比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

          用模式匹配 + 重新构造可以实现:OmitThisParameter

          用重新构造可以实现:Partial、Required、Readonly、Pick、Record

          用模式匹配 + 递归可以实现: Awaited

          用联合类型在分布式条件类型的特性可以实现: Exclude

          此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

          ',33)]))}const m=e(o,[["render",l]]);export{u as __pageData,m as default}; diff --git "a/assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CX5Or8t7.lean.js" "b/assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DshdJwmZ.lean.js" similarity index 98% rename from "assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CX5Or8t7.lean.js" rename to "assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DshdJwmZ.lean.js" index 4a1f007012..78a22e5b4a 100644 --- "a/assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CX5Or8t7.lean.js" +++ "b/assets/cn_src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DshdJwmZ.lean.js" @@ -1 +1 @@ -import{_ as e,o as r,c as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"TypeScript 内置的高级类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/高级类型.md","filePath":"cn/src/types/高级类型.md","lastUpdated":1728828157000}'),o={name:"cn/src/types/高级类型.md"};function l(n,a,h,c,s,d){return r(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          TypeScript 内置的高级类型

          Parameters

          Parameters 用于提取函数类型的参数类型。

          ReturnType

          ReturnType 用于提取函数类型的返回值类型。

          ConstructorParameters

          构造器类型和函数类型的区别就是可以被 new。

          Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

          InstanceType

          提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

          ThisParameterType

          OmitThisParameter

          Partial

          Required

          Readonly

          Pick

          Record

          Exclude

          Extract

          Omit

          Awaited

          NonNullable

          Uppercase

          Lowercase

          Capitalize

          Uncapitalize

          总结

          比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

          用模式匹配 + 重新构造可以实现:OmitThisParameter

          用重新构造可以实现:Partial、Required、Readonly、Pick、Record

          用模式匹配 + 递归可以实现: Awaited

          用联合类型在分布式条件类型的特性可以实现: Exclude

          此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

          ',33)]))}const m=e(o,[["render",l]]);export{u as __pageData,m as default}; +import{_ as e,o as r,c as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"TypeScript 内置的高级类型","description":"","frontmatter":{},"headers":[],"relativePath":"cn/src/types/高级类型.md","filePath":"cn/src/types/高级类型.md","lastUpdated":1728921295000}'),o={name:"cn/src/types/高级类型.md"};function l(n,a,h,c,s,d){return r(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

          TypeScript 内置的高级类型

          Parameters

          Parameters 用于提取函数类型的参数类型。

          ReturnType

          ReturnType 用于提取函数类型的返回值类型。

          ConstructorParameters

          构造器类型和函数类型的区别就是可以被 new。

          Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

          InstanceType

          提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

          ThisParameterType

          OmitThisParameter

          Partial

          Required

          Readonly

          Pick

          Record

          Exclude

          Extract

          Omit

          Awaited

          NonNullable

          Uppercase

          Lowercase

          Capitalize

          Uncapitalize

          总结

          比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

          用模式匹配 + 重新构造可以实现:OmitThisParameter

          用重新构造可以实现:Partial、Required、Readonly、Pick、Record

          用模式匹配 + 递归可以实现: Awaited

          用联合类型在分布式条件类型的特性可以实现: Exclude

          此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

          ',33)]))}const m=e(o,[["render",l]]);export{u as __pageData,m as default}; diff --git a/assets/index.md.C05wkIRp.js b/assets/index.md.B_9rwraW.js similarity index 93% rename from assets/index.md.C05wkIRp.js rename to assets/index.md.B_9rwraW.js index 2281a93084..adc110f88e 100644 --- a/assets/index.md.C05wkIRp.js +++ b/assets/index.md.B_9rwraW.js @@ -1 +1 @@ -import{_ as t,o as e,c as a}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse(`{"title":"Home","description":"","frontmatter":{"layout":"home","title":"Home","hero":{"name":"ran","tagline":"A Troupe of little vagrants of the world , leave your footprints in my words .","image":{"src":"/home.svg","alt":"logo"},"actions":[{"theme":"brand","text":"Thanks to star","link":"https://github.com/chaxus/ran"},{"theme":"alt","text":"Visit my GitHub","link":"https://github.com/chaxus/ran"}]},"features":[{"icon":"⚡️","title":"record","details":"Every journey has its final day."},{"icon":"🛠️","title":"solve","details":"If you can't measure it, you can't improve it."},{"icon":"🖖","title":"share","details":"If you want to go fast, go alone. If you want to go far, go together."}]},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1728828157000}`),o={name:"index.md"};function i(n,r,s,l,c,d){return e(),a("div")}const u=t(o,[["render",i]]);export{h as __pageData,u as default}; +import{_ as t,o as e,c as a}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse(`{"title":"Home","description":"","frontmatter":{"layout":"home","title":"Home","hero":{"name":"ran","tagline":"A Troupe of little vagrants of the world , leave your footprints in my words .","image":{"src":"/home.svg","alt":"logo"},"actions":[{"theme":"brand","text":"Thanks to star","link":"https://github.com/chaxus/ran"},{"theme":"alt","text":"Visit my GitHub","link":"https://github.com/chaxus/ran"}]},"features":[{"icon":"⚡️","title":"record","details":"Every journey has its final day."},{"icon":"🛠️","title":"solve","details":"If you can't measure it, you can't improve it."},{"icon":"🖖","title":"share","details":"If you want to go fast, go alone. If you want to go far, go together."}]},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1728921295000}`),o={name:"index.md"};function i(n,r,s,l,c,d){return e(),a("div")}const u=t(o,[["render",i]]);export{h as __pageData,u as default}; diff --git a/assets/index.md.C05wkIRp.lean.js b/assets/index.md.B_9rwraW.lean.js similarity index 93% rename from assets/index.md.C05wkIRp.lean.js rename to assets/index.md.B_9rwraW.lean.js index 2281a93084..adc110f88e 100644 --- a/assets/index.md.C05wkIRp.lean.js +++ b/assets/index.md.B_9rwraW.lean.js @@ -1 +1 @@ -import{_ as t,o as e,c as a}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse(`{"title":"Home","description":"","frontmatter":{"layout":"home","title":"Home","hero":{"name":"ran","tagline":"A Troupe of little vagrants of the world , leave your footprints in my words .","image":{"src":"/home.svg","alt":"logo"},"actions":[{"theme":"brand","text":"Thanks to star","link":"https://github.com/chaxus/ran"},{"theme":"alt","text":"Visit my GitHub","link":"https://github.com/chaxus/ran"}]},"features":[{"icon":"⚡️","title":"record","details":"Every journey has its final day."},{"icon":"🛠️","title":"solve","details":"If you can't measure it, you can't improve it."},{"icon":"🖖","title":"share","details":"If you want to go fast, go alone. If you want to go far, go together."}]},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1728828157000}`),o={name:"index.md"};function i(n,r,s,l,c,d){return e(),a("div")}const u=t(o,[["render",i]]);export{h as __pageData,u as default}; +import{_ as t,o as e,c as a}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse(`{"title":"Home","description":"","frontmatter":{"layout":"home","title":"Home","hero":{"name":"ran","tagline":"A Troupe of little vagrants of the world , leave your footprints in my words .","image":{"src":"/home.svg","alt":"logo"},"actions":[{"theme":"brand","text":"Thanks to star","link":"https://github.com/chaxus/ran"},{"theme":"alt","text":"Visit my GitHub","link":"https://github.com/chaxus/ran"}]},"features":[{"icon":"⚡️","title":"record","details":"Every journey has its final day."},{"icon":"🛠️","title":"solve","details":"If you can't measure it, you can't improve it."},{"icon":"🖖","title":"share","details":"If you want to go fast, go alone. If you want to go far, go together."}]},"headers":[],"relativePath":"index.md","filePath":"index.md","lastUpdated":1728921295000}`),o={name:"index.md"};function i(n,r,s,l,c,d){return e(),a("div")}const u=t(o,[["render",i]]);export{h as __pageData,u as default}; diff --git a/assets/src_article_astParse_tokenizer.md.B5PslVvl.js b/assets/src_article_astParse_tokenizer.md.BvreBUpi.js similarity index 99% rename from assets/src_article_astParse_tokenizer.md.B5PslVvl.js rename to assets/src_article_astParse_tokenizer.md.BvreBUpi.js index a9c02de967..1c2fadbdb9 100644 --- a/assets/src_article_astParse_tokenizer.md.B5PslVvl.js +++ b/assets/src_article_astParse_tokenizer.md.BvreBUpi.js @@ -1,4 +1,4 @@ -import{_ as a,a as n,b as h,c as p,d as k,e as t,f as l,g as e,h as d,i as E,j as r,k as g,l as c,m as i,n as y}from"./chunks/extra.Cu56q3CZ.js";import{_ as o,o as F,c as C,a3 as A}from"./chunks/framework.BYE6xntm.js";const S=JSON.parse('{"title":"Abstract Syntax Tree","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/astParse/tokenizer.md","filePath":"src/article/astParse/tokenizer.md","lastUpdated":1728828157000}'),u={name:"src/article/astParse/tokenizer.md"};function D(B,s,m,b,v,T){return F(),C("div",{"data-pagefind-body":!0},s[0]||(s[0]=[A('

          Abstract Syntax Tree

          一.(abstract syntax tree)抽象语法树的作用

          源码是一串按照语法格式来组织的字符串,人能够认识,但是计算机并不认识,想让计算机认识就要转成一种数据结构,通过不同的对象来保存不同的数据,并且按照依赖关系组织起来,这种数据结构就是抽象语法树(abstract syntax tree)。

          之所以叫“抽象”语法树是因为数据结构中省略掉了一些无具体意义的分隔符比如 ; { } 等。

          有了 AST,计算机就能理解源码字符串的意思,而理解是能够转换的前提,所以编译的第一步需要把源码 parseAST

          转成 AST 之后就可以通过修改 AST ,分析 AST 的方式来修改和分析代码,比如 babel 就通过这种方式进行代码的转换,比如 rollupTree Shaking ,就是通过分析 AST的 导入导出语法,从而分析出没有使用的代码,进行去除。

          二。常见的 AST 节点

          常见的 AST 节点 AST 是对源码的抽象,字面量、标识符、表达式、语句、模块语法、class 语法都有各自的 AST。

          我们分别来了解一下:

          Literal

          Literal 是字面量的意思,比如 let name = 'value'中,'value'就是一个字符串字面量 StringLiteral,相应的还有数字字面量 NumericLiteral,布尔字面量 BooleanLiteral,字符串字面量 StringLiteral,正则表达式字面量 RegExpLiteral 等。

          下面这些字面量都有对应的 Literal 节点:

          代码中的字面量很多,babel 就是通过 xxLiteral 来抽象这部分内容的。

          Identifier

          Identifer 是标识符的意思,变量名、属性名、参数名等各种声明和引用的名字,都是Identifer

          我们知道, JS 中的标识符只能包含字母或数字或下划线 (“_”) 或美元符号 (“$”) ,且不能以数字开头。这是 Identifier 的词法特点。

          尝试分析一下,下面这一段代码里面有多少 Identifier 呢?

          js
          const name = 'value';
          +import{_ as a,a as n,b as h,c as p,d as k,e as t,f as l,g as e,h as d,i as E,j as r,k as g,l as c,m as i,n as y}from"./chunks/extra.Cu56q3CZ.js";import{_ as o,o as F,c as C,a3 as A}from"./chunks/framework.BYE6xntm.js";const S=JSON.parse('{"title":"Abstract Syntax Tree","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/astParse/tokenizer.md","filePath":"src/article/astParse/tokenizer.md","lastUpdated":1728921295000}'),u={name:"src/article/astParse/tokenizer.md"};function D(B,s,m,b,v,T){return F(),C("div",{"data-pagefind-body":!0},s[0]||(s[0]=[A('

          Abstract Syntax Tree

          一.(abstract syntax tree)抽象语法树的作用

          源码是一串按照语法格式来组织的字符串,人能够认识,但是计算机并不认识,想让计算机认识就要转成一种数据结构,通过不同的对象来保存不同的数据,并且按照依赖关系组织起来,这种数据结构就是抽象语法树(abstract syntax tree)。

          之所以叫“抽象”语法树是因为数据结构中省略掉了一些无具体意义的分隔符比如 ; { } 等。

          有了 AST,计算机就能理解源码字符串的意思,而理解是能够转换的前提,所以编译的第一步需要把源码 parseAST

          转成 AST 之后就可以通过修改 AST ,分析 AST 的方式来修改和分析代码,比如 babel 就通过这种方式进行代码的转换,比如 rollupTree Shaking ,就是通过分析 AST的 导入导出语法,从而分析出没有使用的代码,进行去除。

          二。常见的 AST 节点

          常见的 AST 节点 AST 是对源码的抽象,字面量、标识符、表达式、语句、模块语法、class 语法都有各自的 AST。

          我们分别来了解一下:

          Literal

          Literal 是字面量的意思,比如 let name = 'value'中,'value'就是一个字符串字面量 StringLiteral,相应的还有数字字面量 NumericLiteral,布尔字面量 BooleanLiteral,字符串字面量 StringLiteral,正则表达式字面量 RegExpLiteral 等。

          下面这些字面量都有对应的 Literal 节点:

          代码中的字面量很多,babel 就是通过 xxLiteral 来抽象这部分内容的。

          Identifier

          Identifer 是标识符的意思,变量名、属性名、参数名等各种声明和引用的名字,都是Identifer

          我们知道, JS 中的标识符只能包含字母或数字或下划线 (“_”) 或美元符号 (“$”) ,且不能以数字开头。这是 Identifier 的词法特点。

          尝试分析一下,下面这一段代码里面有多少 Identifier 呢?

          js
          const name = 'value';
           
           function say(name) {
             console.log(name);
          diff --git a/assets/src_article_astParse_tokenizer.md.B5PslVvl.lean.js b/assets/src_article_astParse_tokenizer.md.BvreBUpi.lean.js
          similarity index 99%
          rename from assets/src_article_astParse_tokenizer.md.B5PslVvl.lean.js
          rename to assets/src_article_astParse_tokenizer.md.BvreBUpi.lean.js
          index a9c02de967..1c2fadbdb9 100644
          --- a/assets/src_article_astParse_tokenizer.md.B5PslVvl.lean.js
          +++ b/assets/src_article_astParse_tokenizer.md.BvreBUpi.lean.js
          @@ -1,4 +1,4 @@
          -import{_ as a,a as n,b as h,c as p,d as k,e as t,f as l,g as e,h as d,i as E,j as r,k as g,l as c,m as i,n as y}from"./chunks/extra.Cu56q3CZ.js";import{_ as o,o as F,c as C,a3 as A}from"./chunks/framework.BYE6xntm.js";const S=JSON.parse('{"title":"Abstract Syntax Tree","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/astParse/tokenizer.md","filePath":"src/article/astParse/tokenizer.md","lastUpdated":1728828157000}'),u={name:"src/article/astParse/tokenizer.md"};function D(B,s,m,b,v,T){return F(),C("div",{"data-pagefind-body":!0},s[0]||(s[0]=[A('

          Abstract Syntax Tree

          一.(abstract syntax tree)抽象语法树的作用

          源码是一串按照语法格式来组织的字符串,人能够认识,但是计算机并不认识,想让计算机认识就要转成一种数据结构,通过不同的对象来保存不同的数据,并且按照依赖关系组织起来,这种数据结构就是抽象语法树(abstract syntax tree)。

          之所以叫“抽象”语法树是因为数据结构中省略掉了一些无具体意义的分隔符比如 ; { } 等。

          有了 AST,计算机就能理解源码字符串的意思,而理解是能够转换的前提,所以编译的第一步需要把源码 parseAST

          转成 AST 之后就可以通过修改 AST ,分析 AST 的方式来修改和分析代码,比如 babel 就通过这种方式进行代码的转换,比如 rollupTree Shaking ,就是通过分析 AST的 导入导出语法,从而分析出没有使用的代码,进行去除。

          二。常见的 AST 节点

          常见的 AST 节点 AST 是对源码的抽象,字面量、标识符、表达式、语句、模块语法、class 语法都有各自的 AST。

          我们分别来了解一下:

          Literal

          Literal 是字面量的意思,比如 let name = 'value'中,'value'就是一个字符串字面量 StringLiteral,相应的还有数字字面量 NumericLiteral,布尔字面量 BooleanLiteral,字符串字面量 StringLiteral,正则表达式字面量 RegExpLiteral 等。

          下面这些字面量都有对应的 Literal 节点:

          代码中的字面量很多,babel 就是通过 xxLiteral 来抽象这部分内容的。

          Identifier

          Identifer 是标识符的意思,变量名、属性名、参数名等各种声明和引用的名字,都是Identifer

          我们知道, JS 中的标识符只能包含字母或数字或下划线 (“_”) 或美元符号 (“$”) ,且不能以数字开头。这是 Identifier 的词法特点。

          尝试分析一下,下面这一段代码里面有多少 Identifier 呢?

          js
          const name = 'value';
          +import{_ as a,a as n,b as h,c as p,d as k,e as t,f as l,g as e,h as d,i as E,j as r,k as g,l as c,m as i,n as y}from"./chunks/extra.Cu56q3CZ.js";import{_ as o,o as F,c as C,a3 as A}from"./chunks/framework.BYE6xntm.js";const S=JSON.parse('{"title":"Abstract Syntax Tree","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/astParse/tokenizer.md","filePath":"src/article/astParse/tokenizer.md","lastUpdated":1728921295000}'),u={name:"src/article/astParse/tokenizer.md"};function D(B,s,m,b,v,T){return F(),C("div",{"data-pagefind-body":!0},s[0]||(s[0]=[A('

          Abstract Syntax Tree

          一.(abstract syntax tree)抽象语法树的作用

          源码是一串按照语法格式来组织的字符串,人能够认识,但是计算机并不认识,想让计算机认识就要转成一种数据结构,通过不同的对象来保存不同的数据,并且按照依赖关系组织起来,这种数据结构就是抽象语法树(abstract syntax tree)。

          之所以叫“抽象”语法树是因为数据结构中省略掉了一些无具体意义的分隔符比如 ; { } 等。

          有了 AST,计算机就能理解源码字符串的意思,而理解是能够转换的前提,所以编译的第一步需要把源码 parseAST

          转成 AST 之后就可以通过修改 AST ,分析 AST 的方式来修改和分析代码,比如 babel 就通过这种方式进行代码的转换,比如 rollupTree Shaking ,就是通过分析 AST的 导入导出语法,从而分析出没有使用的代码,进行去除。

          二。常见的 AST 节点

          常见的 AST 节点 AST 是对源码的抽象,字面量、标识符、表达式、语句、模块语法、class 语法都有各自的 AST。

          我们分别来了解一下:

          Literal

          Literal 是字面量的意思,比如 let name = 'value'中,'value'就是一个字符串字面量 StringLiteral,相应的还有数字字面量 NumericLiteral,布尔字面量 BooleanLiteral,字符串字面量 StringLiteral,正则表达式字面量 RegExpLiteral 等。

          下面这些字面量都有对应的 Literal 节点:

          代码中的字面量很多,babel 就是通过 xxLiteral 来抽象这部分内容的。

          Identifier

          Identifer 是标识符的意思,变量名、属性名、参数名等各种声明和引用的名字,都是Identifer

          我们知道, JS 中的标识符只能包含字母或数字或下划线 (“_”) 或美元符号 (“$”) ,且不能以数字开头。这是 Identifier 的词法特点。

          尝试分析一下,下面这一段代码里面有多少 Identifier 呢?

          js
          const name = 'value';
           
           function say(name) {
             console.log(name);
          diff --git a/assets/src_article_babel.md.Czc7FSEu.js b/assets/src_article_babel.md.D6U-I50A.js
          similarity index 95%
          rename from assets/src_article_babel.md.Czc7FSEu.js
          rename to assets/src_article_babel.md.D6U-I50A.js
          index 1c06dc406a..a9a8817bd1 100644
          --- a/assets/src_article_babel.md.Czc7FSEu.js
          +++ b/assets/src_article_babel.md.D6U-I50A.js
          @@ -1 +1 @@
          -import{_ as a,o as t,c as l,a3 as r}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Babel","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/babel.md","filePath":"src/article/babel.md","lastUpdated":1728828157000}'),i={name:"src/article/babel.md"};function s(b,e,o,p,c,n){return t(),l("div",{"data-pagefind-body":!0},e[0]||(e[0]=[r('

          Babel

          babel 核心库主要是:

          • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
          • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
          • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
          • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
          • @babel/code-frame 可以创建友好的报错信息
          • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
          • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。
          ',3)]))}const u=a(i,[["render",s]]);export{m as __pageData,u as default}; +import{_ as a,o as t,c as l,a3 as r}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Babel","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/babel.md","filePath":"src/article/babel.md","lastUpdated":1728921295000}'),i={name:"src/article/babel.md"};function s(b,e,o,p,c,n){return t(),l("div",{"data-pagefind-body":!0},e[0]||(e[0]=[r('

          Babel

          babel 核心库主要是:

          • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
          • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
          • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
          • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
          • @babel/code-frame 可以创建友好的报错信息
          • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
          • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。
          ',3)]))}const u=a(i,[["render",s]]);export{m as __pageData,u as default}; diff --git a/assets/src_article_babel.md.Czc7FSEu.lean.js b/assets/src_article_babel.md.D6U-I50A.lean.js similarity index 95% rename from assets/src_article_babel.md.Czc7FSEu.lean.js rename to assets/src_article_babel.md.D6U-I50A.lean.js index 1c06dc406a..a9a8817bd1 100644 --- a/assets/src_article_babel.md.Czc7FSEu.lean.js +++ b/assets/src_article_babel.md.D6U-I50A.lean.js @@ -1 +1 @@ -import{_ as a,o as t,c as l,a3 as r}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Babel","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/babel.md","filePath":"src/article/babel.md","lastUpdated":1728828157000}'),i={name:"src/article/babel.md"};function s(b,e,o,p,c,n){return t(),l("div",{"data-pagefind-body":!0},e[0]||(e[0]=[r('

          Babel

          babel 核心库主要是:

          • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
          • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
          • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
          • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
          • @babel/code-frame 可以创建友好的报错信息
          • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
          • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。
          ',3)]))}const u=a(i,[["render",s]]);export{m as __pageData,u as default}; +import{_ as a,o as t,c as l,a3 as r}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"Babel","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/babel.md","filePath":"src/article/babel.md","lastUpdated":1728921295000}'),i={name:"src/article/babel.md"};function s(b,e,o,p,c,n){return t(),l("div",{"data-pagefind-body":!0},e[0]||(e[0]=[r('

          Babel

          babel 核心库主要是:

          • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
          • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
          • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
          • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
          • @babel/code-frame 可以创建友好的报错信息
          • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
          • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。
          ',3)]))}const u=a(i,[["render",s]]);export{m as __pageData,u as default}; diff --git a/assets/src_article_bundle.md.DqBSsozI.js b/assets/src_article_bundle.md.ChxeIam8.js similarity index 93% rename from assets/src_article_bundle.md.DqBSsozI.js rename to assets/src_article_bundle.md.ChxeIam8.js index ae4f69d30b..23ea632f17 100644 --- a/assets/src_article_bundle.md.DqBSsozI.js +++ b/assets/src_article_bundle.md.ChxeIam8.js @@ -1 +1 @@ -import{_ as a,o as t,c as n,j as e,a as r}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"Bundle","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/bundle.md","filePath":"src/article/bundle.md","lastUpdated":1728828157000}'),d={name:"src/article/bundle.md"};function s(i,l,c,o,u,p){return t(),n("div",{"data-pagefind-body":!0},l[0]||(l[0]=[e("h1",{id:"bundle",tabindex:"-1"},[r("Bundle "),e("a",{class:"header-anchor",href:"#bundle","aria-label":'Permalink to "Bundle"'},"​")],-1),e("p",null,"Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:",-1),e("ul",null,[e("li",null,"编译能力"),e("li",null,"插件机制"),e("li",null,"HMR"),e("li",null,"cli 和命令行能力")],-1)]))}const m=a(d,[["render",s]]);export{f as __pageData,m as default}; +import{_ as a,o as t,c as n,j as e,a as r}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"Bundle","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/bundle.md","filePath":"src/article/bundle.md","lastUpdated":1728921295000}'),d={name:"src/article/bundle.md"};function s(i,l,c,o,u,p){return t(),n("div",{"data-pagefind-body":!0},l[0]||(l[0]=[e("h1",{id:"bundle",tabindex:"-1"},[r("Bundle "),e("a",{class:"header-anchor",href:"#bundle","aria-label":'Permalink to "Bundle"'},"​")],-1),e("p",null,"Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:",-1),e("ul",null,[e("li",null,"编译能力"),e("li",null,"插件机制"),e("li",null,"HMR"),e("li",null,"cli 和命令行能力")],-1)]))}const m=a(d,[["render",s]]);export{f as __pageData,m as default}; diff --git a/assets/src_article_bundle.md.DqBSsozI.lean.js b/assets/src_article_bundle.md.ChxeIam8.lean.js similarity index 93% rename from assets/src_article_bundle.md.DqBSsozI.lean.js rename to assets/src_article_bundle.md.ChxeIam8.lean.js index ae4f69d30b..23ea632f17 100644 --- a/assets/src_article_bundle.md.DqBSsozI.lean.js +++ b/assets/src_article_bundle.md.ChxeIam8.lean.js @@ -1 +1 @@ -import{_ as a,o as t,c as n,j as e,a as r}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"Bundle","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/bundle.md","filePath":"src/article/bundle.md","lastUpdated":1728828157000}'),d={name:"src/article/bundle.md"};function s(i,l,c,o,u,p){return t(),n("div",{"data-pagefind-body":!0},l[0]||(l[0]=[e("h1",{id:"bundle",tabindex:"-1"},[r("Bundle "),e("a",{class:"header-anchor",href:"#bundle","aria-label":'Permalink to "Bundle"'},"​")],-1),e("p",null,"Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:",-1),e("ul",null,[e("li",null,"编译能力"),e("li",null,"插件机制"),e("li",null,"HMR"),e("li",null,"cli 和命令行能力")],-1)]))}const m=a(d,[["render",s]]);export{f as __pageData,m as default}; +import{_ as a,o as t,c as n,j as e,a as r}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"Bundle","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/bundle.md","filePath":"src/article/bundle.md","lastUpdated":1728921295000}'),d={name:"src/article/bundle.md"};function s(i,l,c,o,u,p){return t(),n("div",{"data-pagefind-body":!0},l[0]||(l[0]=[e("h1",{id:"bundle",tabindex:"-1"},[r("Bundle "),e("a",{class:"header-anchor",href:"#bundle","aria-label":'Permalink to "Bundle"'},"​")],-1),e("p",null,"Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:",-1),e("ul",null,[e("li",null,"编译能力"),e("li",null,"插件机制"),e("li",null,"HMR"),e("li",null,"cli 和命令行能力")],-1)]))}const m=a(d,[["render",s]]);export{f as __pageData,m as default}; diff --git a/assets/src_article_designMode.md.GNIygirc.js b/assets/src_article_designMode.md.DUzkKke4.js similarity index 99% rename from assets/src_article_designMode.md.GNIygirc.js rename to assets/src_article_designMode.md.DUzkKke4.js index 929b045a3f..7fccaa448a 100644 --- a/assets/src_article_designMode.md.GNIygirc.js +++ b/assets/src_article_designMode.md.DUzkKke4.js @@ -1,4 +1,4 @@ -import{_ as i,a,b as n,c as e,d as t,e as h,f as l,g as p,h as k,i as r,j as o,k as d,l as E,m as c,n as g,o as y,p as F,q as u,r as m,s as b,t as f,u as C,v as A,w as B,x as v,y as D,z as w,A as x,B as j}from"./chunks/访问者._0swtoJg.js";import{_ as q,o as P,c as T,a3 as _}from"./chunks/framework.BYE6xntm.js";const U=JSON.parse('{"title":"23 classic design patterns","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/designMode.md","filePath":"src/article/designMode.md","lastUpdated":1728828157000}'),I={name:"src/article/designMode.md"};function S(M,s,z,L,V,W){return P(),T("div",{"data-pagefind-body":!0},s[0]||(s[0]=[_(`

          23 classic design patterns

          The Design Pattern is a set of frequently used, widely known, cataloged code design experiences that are used in order to reuse code, make it easier for others to understand, and ensure code reliability.

          In the book "Design Patterns: The Foundation of Reusable Object-Oriented Software" introduced 23 classic design patterns, but the design pattern is not only these 23, with the development of software development industry, more and more new patterns continue to be born and applied. Experienced developers learn design patterns that can be corroborated with past experience, making it easier to understand them.

          A design pattern generally contains elements such as the pattern name, problem, purpose, solution, and effect. The problem describes when patterns should be used, and it contains problems with the design and why they exist. A solution describes the components of a design pattern and how these components relate to each other, their respective responsibilities, and how they work together. Typically, the solution is described through UML class diagrams and core code. Effects describe the advantages and disadvantages of the pattern and the trade-offs that should be made when using the pattern.

          Why learn design patterns:

          • Design patterns are derived from the experience and wisdom of many experts. They are successful and reusable design solutions from many excellent software systems. Using these solutions will allow us to avoid doing some repetitive work

          • Design patterns provide a common set of design vocabulary and a common form to facilitate communication and exchange between developers, making design solutions more understandable

          • Most of the design patterns take into account the reusability and extensibility of the system, which enables us to better reuse some existing design schemes, functional modules and even a complete software system, so as to avoid us often doing some repetitive design and writing some repetitive code

          • Proper use of design patterns and documentation of their use will help others understand the system more quickly

          • Learning design patterns will help beginners understand object-oriented ideas more deeply

          Reserve knowledge

          • Abstract class: The general abstract class is as a base class, for example, "computer" can be used as an abstract class, according to the abstract class derived "desktop computer" and "laptop computer" 2 concrete classes. Abstract classes are generally not instantiated.

          • Combination is better than inheritance: inheritance cannot be abused to expand functionality, and combination is more flexible. Also take the "computer" abstract class for example, if we use inheritance to distinguish different types of "computer" we can derive "desktop computer" and "laptop computer", if we add another dimension, according to the brand can continue to subdivide "Lenovo desktop computer", "Lenovo laptop", "Apple desktop computer" and "Apple laptop" and so on. If you add another dimension and continue to subdivide, it is clear that inheritance is not adequate. At this time, you can use inheritance and composition, and the combined object can also be abstract design:

            ts
            interface Brand {
            +import{_ as i,a,b as n,c as e,d as t,e as h,f as l,g as p,h as k,i as r,j as o,k as d,l as E,m as c,n as g,o as y,p as F,q as u,r as m,s as b,t as f,u as C,v as A,w as B,x as v,y as D,z as w,A as x,B as j}from"./chunks/访问者._0swtoJg.js";import{_ as q,o as P,c as T,a3 as _}from"./chunks/framework.BYE6xntm.js";const U=JSON.parse('{"title":"23 classic design patterns","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/designMode.md","filePath":"src/article/designMode.md","lastUpdated":1728921295000}'),I={name:"src/article/designMode.md"};function S(M,s,z,L,V,W){return P(),T("div",{"data-pagefind-body":!0},s[0]||(s[0]=[_(`

            23 classic design patterns

            The Design Pattern is a set of frequently used, widely known, cataloged code design experiences that are used in order to reuse code, make it easier for others to understand, and ensure code reliability.

            In the book "Design Patterns: The Foundation of Reusable Object-Oriented Software" introduced 23 classic design patterns, but the design pattern is not only these 23, with the development of software development industry, more and more new patterns continue to be born and applied. Experienced developers learn design patterns that can be corroborated with past experience, making it easier to understand them.

            A design pattern generally contains elements such as the pattern name, problem, purpose, solution, and effect. The problem describes when patterns should be used, and it contains problems with the design and why they exist. A solution describes the components of a design pattern and how these components relate to each other, their respective responsibilities, and how they work together. Typically, the solution is described through UML class diagrams and core code. Effects describe the advantages and disadvantages of the pattern and the trade-offs that should be made when using the pattern.

            Why learn design patterns:

            • Design patterns are derived from the experience and wisdom of many experts. They are successful and reusable design solutions from many excellent software systems. Using these solutions will allow us to avoid doing some repetitive work

            • Design patterns provide a common set of design vocabulary and a common form to facilitate communication and exchange between developers, making design solutions more understandable

            • Most of the design patterns take into account the reusability and extensibility of the system, which enables us to better reuse some existing design schemes, functional modules and even a complete software system, so as to avoid us often doing some repetitive design and writing some repetitive code

            • Proper use of design patterns and documentation of their use will help others understand the system more quickly

            • Learning design patterns will help beginners understand object-oriented ideas more deeply

            Reserve knowledge

            • Abstract class: The general abstract class is as a base class, for example, "computer" can be used as an abstract class, according to the abstract class derived "desktop computer" and "laptop computer" 2 concrete classes. Abstract classes are generally not instantiated.

            • Combination is better than inheritance: inheritance cannot be abused to expand functionality, and combination is more flexible. Also take the "computer" abstract class for example, if we use inheritance to distinguish different types of "computer" we can derive "desktop computer" and "laptop computer", if we add another dimension, according to the brand can continue to subdivide "Lenovo desktop computer", "Lenovo laptop", "Apple desktop computer" and "Apple laptop" and so on. If you add another dimension and continue to subdivide, it is clear that inheritance is not adequate. At this time, you can use inheritance and composition, and the combined object can also be abstract design:

              ts
              interface Brand {
                 // ...
               }
               interface Lenovo extends Brand {
              diff --git a/assets/src_article_designMode.md.GNIygirc.lean.js b/assets/src_article_designMode.md.DUzkKke4.lean.js
              similarity index 99%
              rename from assets/src_article_designMode.md.GNIygirc.lean.js
              rename to assets/src_article_designMode.md.DUzkKke4.lean.js
              index 929b045a3f..7fccaa448a 100644
              --- a/assets/src_article_designMode.md.GNIygirc.lean.js
              +++ b/assets/src_article_designMode.md.DUzkKke4.lean.js
              @@ -1,4 +1,4 @@
              -import{_ as i,a,b as n,c as e,d as t,e as h,f as l,g as p,h as k,i as r,j as o,k as d,l as E,m as c,n as g,o as y,p as F,q as u,r as m,s as b,t as f,u as C,v as A,w as B,x as v,y as D,z as w,A as x,B as j}from"./chunks/访问者._0swtoJg.js";import{_ as q,o as P,c as T,a3 as _}from"./chunks/framework.BYE6xntm.js";const U=JSON.parse('{"title":"23 classic design patterns","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/designMode.md","filePath":"src/article/designMode.md","lastUpdated":1728828157000}'),I={name:"src/article/designMode.md"};function S(M,s,z,L,V,W){return P(),T("div",{"data-pagefind-body":!0},s[0]||(s[0]=[_(`

              23 classic design patterns

              The Design Pattern is a set of frequently used, widely known, cataloged code design experiences that are used in order to reuse code, make it easier for others to understand, and ensure code reliability.

              In the book "Design Patterns: The Foundation of Reusable Object-Oriented Software" introduced 23 classic design patterns, but the design pattern is not only these 23, with the development of software development industry, more and more new patterns continue to be born and applied. Experienced developers learn design patterns that can be corroborated with past experience, making it easier to understand them.

              A design pattern generally contains elements such as the pattern name, problem, purpose, solution, and effect. The problem describes when patterns should be used, and it contains problems with the design and why they exist. A solution describes the components of a design pattern and how these components relate to each other, their respective responsibilities, and how they work together. Typically, the solution is described through UML class diagrams and core code. Effects describe the advantages and disadvantages of the pattern and the trade-offs that should be made when using the pattern.

              Why learn design patterns:

              • Design patterns are derived from the experience and wisdom of many experts. They are successful and reusable design solutions from many excellent software systems. Using these solutions will allow us to avoid doing some repetitive work

              • Design patterns provide a common set of design vocabulary and a common form to facilitate communication and exchange between developers, making design solutions more understandable

              • Most of the design patterns take into account the reusability and extensibility of the system, which enables us to better reuse some existing design schemes, functional modules and even a complete software system, so as to avoid us often doing some repetitive design and writing some repetitive code

              • Proper use of design patterns and documentation of their use will help others understand the system more quickly

              • Learning design patterns will help beginners understand object-oriented ideas more deeply

              Reserve knowledge

              • Abstract class: The general abstract class is as a base class, for example, "computer" can be used as an abstract class, according to the abstract class derived "desktop computer" and "laptop computer" 2 concrete classes. Abstract classes are generally not instantiated.

              • Combination is better than inheritance: inheritance cannot be abused to expand functionality, and combination is more flexible. Also take the "computer" abstract class for example, if we use inheritance to distinguish different types of "computer" we can derive "desktop computer" and "laptop computer", if we add another dimension, according to the brand can continue to subdivide "Lenovo desktop computer", "Lenovo laptop", "Apple desktop computer" and "Apple laptop" and so on. If you add another dimension and continue to subdivide, it is clear that inheritance is not adequate. At this time, you can use inheritance and composition, and the combined object can also be abstract design:

                ts
                interface Brand {
                +import{_ as i,a,b as n,c as e,d as t,e as h,f as l,g as p,h as k,i as r,j as o,k as d,l as E,m as c,n as g,o as y,p as F,q as u,r as m,s as b,t as f,u as C,v as A,w as B,x as v,y as D,z as w,A as x,B as j}from"./chunks/访问者._0swtoJg.js";import{_ as q,o as P,c as T,a3 as _}from"./chunks/framework.BYE6xntm.js";const U=JSON.parse('{"title":"23 classic design patterns","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/designMode.md","filePath":"src/article/designMode.md","lastUpdated":1728921295000}'),I={name:"src/article/designMode.md"};function S(M,s,z,L,V,W){return P(),T("div",{"data-pagefind-body":!0},s[0]||(s[0]=[_(`

                23 classic design patterns

                The Design Pattern is a set of frequently used, widely known, cataloged code design experiences that are used in order to reuse code, make it easier for others to understand, and ensure code reliability.

                In the book "Design Patterns: The Foundation of Reusable Object-Oriented Software" introduced 23 classic design patterns, but the design pattern is not only these 23, with the development of software development industry, more and more new patterns continue to be born and applied. Experienced developers learn design patterns that can be corroborated with past experience, making it easier to understand them.

                A design pattern generally contains elements such as the pattern name, problem, purpose, solution, and effect. The problem describes when patterns should be used, and it contains problems with the design and why they exist. A solution describes the components of a design pattern and how these components relate to each other, their respective responsibilities, and how they work together. Typically, the solution is described through UML class diagrams and core code. Effects describe the advantages and disadvantages of the pattern and the trade-offs that should be made when using the pattern.

                Why learn design patterns:

                • Design patterns are derived from the experience and wisdom of many experts. They are successful and reusable design solutions from many excellent software systems. Using these solutions will allow us to avoid doing some repetitive work

                • Design patterns provide a common set of design vocabulary and a common form to facilitate communication and exchange between developers, making design solutions more understandable

                • Most of the design patterns take into account the reusability and extensibility of the system, which enables us to better reuse some existing design schemes, functional modules and even a complete software system, so as to avoid us often doing some repetitive design and writing some repetitive code

                • Proper use of design patterns and documentation of their use will help others understand the system more quickly

                • Learning design patterns will help beginners understand object-oriented ideas more deeply

                Reserve knowledge

                • Abstract class: The general abstract class is as a base class, for example, "computer" can be used as an abstract class, according to the abstract class derived "desktop computer" and "laptop computer" 2 concrete classes. Abstract classes are generally not instantiated.

                • Combination is better than inheritance: inheritance cannot be abused to expand functionality, and combination is more flexible. Also take the "computer" abstract class for example, if we use inheritance to distinguish different types of "computer" we can derive "desktop computer" and "laptop computer", if we add another dimension, according to the brand can continue to subdivide "Lenovo desktop computer", "Lenovo laptop", "Apple desktop computer" and "Apple laptop" and so on. If you add another dimension and continue to subdivide, it is clear that inheritance is not adequate. At this time, you can use inheritance and composition, and the combined object can also be abstract design:

                  ts
                  interface Brand {
                     // ...
                   }
                   interface Lenovo extends Brand {
                  diff --git a/assets/src_article_functionalProgramming.md.zs1zfDDr.js b/assets/src_article_functionalProgramming.md.dIGyJ6sB.js
                  similarity index 99%
                  rename from assets/src_article_functionalProgramming.md.zs1zfDDr.js
                  rename to assets/src_article_functionalProgramming.md.dIGyJ6sB.js
                  index 27325e422e..f71a85b1e4 100644
                  --- a/assets/src_article_functionalProgramming.md.zs1zfDDr.js
                  +++ b/assets/src_article_functionalProgramming.md.dIGyJ6sB.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"函数式编程","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/functionalProgramming.md","filePath":"src/article/functionalProgramming.md","lastUpdated":1728828157000}'),k={name:"src/article/functionalProgramming.md"};function l(p,s,t,E,e,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  函数式编程

                  • 概述:函数式编程 (Functional Programming)FP就是编程规范之一,我们常听说的编程规范还有面向对象编程,面向过程编程。
                  • 面向对象的编程思维方式:把现实世界中的事物抽象成程序世界的类和对象,通过封装,继承和多态演示事物事件的联系
                  • 函数编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界 (对运算过程进行抽象)
                    • 程序的本质:根据输入,通过某种运算,获得相应的输出
                    • 函数式编程中的函数不是指程序中的 (函数) 方法,而是数学中的函数,即映射关系
                    • 相同的输入始终要得到相同的输出 (纯函数)
                    • 函数式编程用来描述数据 (函数) 之间的映射关系
                  js
                  //非函数式编程,面向过程的编程方式
                  +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"函数式编程","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/functionalProgramming.md","filePath":"src/article/functionalProgramming.md","lastUpdated":1728921295000}'),k={name:"src/article/functionalProgramming.md"};function l(p,s,t,E,e,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  函数式编程

                  • 概述:函数式编程 (Functional Programming)FP就是编程规范之一,我们常听说的编程规范还有面向对象编程,面向过程编程。
                  • 面向对象的编程思维方式:把现实世界中的事物抽象成程序世界的类和对象,通过封装,继承和多态演示事物事件的联系
                  • 函数编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界 (对运算过程进行抽象)
                    • 程序的本质:根据输入,通过某种运算,获得相应的输出
                    • 函数式编程中的函数不是指程序中的 (函数) 方法,而是数学中的函数,即映射关系
                    • 相同的输入始终要得到相同的输出 (纯函数)
                    • 函数式编程用来描述数据 (函数) 之间的映射关系
                  js
                  //非函数式编程,面向过程的编程方式
                   let num1 = 1;
                   let num2 = 2;
                   let sum = num1 + num2;
                  diff --git a/assets/src_article_functionalProgramming.md.zs1zfDDr.lean.js b/assets/src_article_functionalProgramming.md.dIGyJ6sB.lean.js
                  similarity index 99%
                  rename from assets/src_article_functionalProgramming.md.zs1zfDDr.lean.js
                  rename to assets/src_article_functionalProgramming.md.dIGyJ6sB.lean.js
                  index 27325e422e..f71a85b1e4 100644
                  --- a/assets/src_article_functionalProgramming.md.zs1zfDDr.lean.js
                  +++ b/assets/src_article_functionalProgramming.md.dIGyJ6sB.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"函数式编程","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/functionalProgramming.md","filePath":"src/article/functionalProgramming.md","lastUpdated":1728828157000}'),k={name:"src/article/functionalProgramming.md"};function l(p,s,t,E,e,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  函数式编程

                  • 概述:函数式编程 (Functional Programming)FP就是编程规范之一,我们常听说的编程规范还有面向对象编程,面向过程编程。
                  • 面向对象的编程思维方式:把现实世界中的事物抽象成程序世界的类和对象,通过封装,继承和多态演示事物事件的联系
                  • 函数编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界 (对运算过程进行抽象)
                    • 程序的本质:根据输入,通过某种运算,获得相应的输出
                    • 函数式编程中的函数不是指程序中的 (函数) 方法,而是数学中的函数,即映射关系
                    • 相同的输入始终要得到相同的输出 (纯函数)
                    • 函数式编程用来描述数据 (函数) 之间的映射关系
                  js
                  //非函数式编程,面向过程的编程方式
                  +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"函数式编程","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/functionalProgramming.md","filePath":"src/article/functionalProgramming.md","lastUpdated":1728921295000}'),k={name:"src/article/functionalProgramming.md"};function l(p,s,t,E,e,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  函数式编程

                  • 概述:函数式编程 (Functional Programming)FP就是编程规范之一,我们常听说的编程规范还有面向对象编程,面向过程编程。
                  • 面向对象的编程思维方式:把现实世界中的事物抽象成程序世界的类和对象,通过封装,继承和多态演示事物事件的联系
                  • 函数编程的思维方式:把现实世界的事物和事物之间的联系抽象到程序世界 (对运算过程进行抽象)
                    • 程序的本质:根据输入,通过某种运算,获得相应的输出
                    • 函数式编程中的函数不是指程序中的 (函数) 方法,而是数学中的函数,即映射关系
                    • 相同的输入始终要得到相同的输出 (纯函数)
                    • 函数式编程用来描述数据 (函数) 之间的映射关系
                  js
                  //非函数式编程,面向过程的编程方式
                   let num1 = 1;
                   let num2 = 2;
                   let sum = num1 + num2;
                  diff --git a/assets/src_article_imagemin.md.BAQ0hCS3.js b/assets/src_article_imagemin.md.CBY6W2re.js
                  similarity index 91%
                  rename from assets/src_article_imagemin.md.BAQ0hCS3.js
                  rename to assets/src_article_imagemin.md.CBY6W2re.js
                  index 43e02a0c5f..674b93dbad 100644
                  --- a/assets/src_article_imagemin.md.BAQ0hCS3.js
                  +++ b/assets/src_article_imagemin.md.CBY6W2re.js
                  @@ -1 +1 @@
                  -import{_ as t,o as i,c as r,j as a,a as m}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"imagemin 图片压缩源码分析","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/imagemin.md","filePath":"src/article/imagemin.md","lastUpdated":1728828157000}'),n={name:"src/article/imagemin.md"};function s(o,e,c,d,l,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[a("h1",{id:"imagemin-图片压缩源码分析",tabindex:"-1"},[m("imagemin 图片压缩源码分析 "),a("a",{class:"header-anchor",href:"#imagemin-图片压缩源码分析","aria-label":'Permalink to "imagemin 图片压缩源码分析"'},"​")],-1)]))}const _=t(n,[["render",s]]);export{f as __pageData,_ as default};
                  +import{_ as t,o as i,c as r,j as a,a as m}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"imagemin 图片压缩源码分析","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/imagemin.md","filePath":"src/article/imagemin.md","lastUpdated":1728921295000}'),n={name:"src/article/imagemin.md"};function s(o,e,c,d,l,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[a("h1",{id:"imagemin-图片压缩源码分析",tabindex:"-1"},[m("imagemin 图片压缩源码分析 "),a("a",{class:"header-anchor",href:"#imagemin-图片压缩源码分析","aria-label":'Permalink to "imagemin 图片压缩源码分析"'},"​")],-1)]))}const _=t(n,[["render",s]]);export{f as __pageData,_ as default};
                  diff --git a/assets/src_article_imagemin.md.BAQ0hCS3.lean.js b/assets/src_article_imagemin.md.CBY6W2re.lean.js
                  similarity index 91%
                  rename from assets/src_article_imagemin.md.BAQ0hCS3.lean.js
                  rename to assets/src_article_imagemin.md.CBY6W2re.lean.js
                  index 43e02a0c5f..674b93dbad 100644
                  --- a/assets/src_article_imagemin.md.BAQ0hCS3.lean.js
                  +++ b/assets/src_article_imagemin.md.CBY6W2re.lean.js
                  @@ -1 +1 @@
                  -import{_ as t,o as i,c as r,j as a,a as m}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"imagemin 图片压缩源码分析","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/imagemin.md","filePath":"src/article/imagemin.md","lastUpdated":1728828157000}'),n={name:"src/article/imagemin.md"};function s(o,e,c,d,l,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[a("h1",{id:"imagemin-图片压缩源码分析",tabindex:"-1"},[m("imagemin 图片压缩源码分析 "),a("a",{class:"header-anchor",href:"#imagemin-图片压缩源码分析","aria-label":'Permalink to "imagemin 图片压缩源码分析"'},"​")],-1)]))}const _=t(n,[["render",s]]);export{f as __pageData,_ as default};
                  +import{_ as t,o as i,c as r,j as a,a as m}from"./chunks/framework.BYE6xntm.js";const f=JSON.parse('{"title":"imagemin 图片压缩源码分析","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/imagemin.md","filePath":"src/article/imagemin.md","lastUpdated":1728921295000}'),n={name:"src/article/imagemin.md"};function s(o,e,c,d,l,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[a("h1",{id:"imagemin-图片压缩源码分析",tabindex:"-1"},[m("imagemin 图片压缩源码分析 "),a("a",{class:"header-anchor",href:"#imagemin-图片压缩源码分析","aria-label":'Permalink to "imagemin 图片压缩源码分析"'},"​")],-1)]))}const _=t(n,[["render",s]]);export{f as __pageData,_ as default};
                  diff --git a/assets/src_article_javascript_domLoad.md.BMbEujHQ.js b/assets/src_article_javascript_domLoad.md.Dd7Dzr5Y.js
                  similarity index 97%
                  rename from assets/src_article_javascript_domLoad.md.BMbEujHQ.js
                  rename to assets/src_article_javascript_domLoad.md.Dd7Dzr5Y.js
                  index cb1a31e711..50b52060a7 100644
                  --- a/assets/src_article_javascript_domLoad.md.BMbEujHQ.js
                  +++ b/assets/src_article_javascript_domLoad.md.Dd7Dzr5Y.js
                  @@ -1 +1 @@
                  -import{_ as e,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"页面加载完成后事件","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/javascript/domLoad.md","filePath":"src/article/javascript/domLoad.md","lastUpdated":1728828157000}'),o={name:"src/article/javascript/domLoad.md"};function n(d,a,l,r,c,h){return t(),s("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

                  页面加载完成后事件

                  window.onload

                  DOMContentLoaded

                  js
                  document.addEventListener('DOMContentLoaded', fun);

                  <body onload="fun()">

                  readyState

                  js
                  document.readyState;\n\ndocument.onreadystatechange;

                  一个文档的 readyState 可以是以下之一:

                  • loading / 加载。document 仍在加载。
                  • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
                  • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
                  ',9)]))}const k=e(o,[["render",n]]);export{u as __pageData,k as default}; +import{_ as e,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"页面加载完成后事件","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/javascript/domLoad.md","filePath":"src/article/javascript/domLoad.md","lastUpdated":1728921295000}'),o={name:"src/article/javascript/domLoad.md"};function n(d,a,l,r,c,h){return t(),s("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

                  页面加载完成后事件

                  window.onload

                  DOMContentLoaded

                  js
                  document.addEventListener('DOMContentLoaded', fun);

                  <body onload="fun()">

                  readyState

                  js
                  document.readyState;\n\ndocument.onreadystatechange;

                  一个文档的 readyState 可以是以下之一:

                  • loading / 加载。document 仍在加载。
                  • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
                  • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
                  ',9)]))}const k=e(o,[["render",n]]);export{u as __pageData,k as default}; diff --git a/assets/src_article_javascript_domLoad.md.BMbEujHQ.lean.js b/assets/src_article_javascript_domLoad.md.Dd7Dzr5Y.lean.js similarity index 97% rename from assets/src_article_javascript_domLoad.md.BMbEujHQ.lean.js rename to assets/src_article_javascript_domLoad.md.Dd7Dzr5Y.lean.js index cb1a31e711..50b52060a7 100644 --- a/assets/src_article_javascript_domLoad.md.BMbEujHQ.lean.js +++ b/assets/src_article_javascript_domLoad.md.Dd7Dzr5Y.lean.js @@ -1 +1 @@ -import{_ as e,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"页面加载完成后事件","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/javascript/domLoad.md","filePath":"src/article/javascript/domLoad.md","lastUpdated":1728828157000}'),o={name:"src/article/javascript/domLoad.md"};function n(d,a,l,r,c,h){return t(),s("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

                  页面加载完成后事件

                  window.onload

                  DOMContentLoaded

                  js
                  document.addEventListener('DOMContentLoaded', fun);

                  <body onload="fun()">

                  readyState

                  js
                  document.readyState;\n\ndocument.onreadystatechange;

                  一个文档的 readyState 可以是以下之一:

                  • loading / 加载。document 仍在加载。
                  • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
                  • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
                  ',9)]))}const k=e(o,[["render",n]]);export{u as __pageData,k as default}; +import{_ as e,o as t,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"页面加载完成后事件","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/javascript/domLoad.md","filePath":"src/article/javascript/domLoad.md","lastUpdated":1728921295000}'),o={name:"src/article/javascript/domLoad.md"};function n(d,a,l,r,c,h){return t(),s("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

                  页面加载完成后事件

                  window.onload

                  DOMContentLoaded

                  js
                  document.addEventListener('DOMContentLoaded', fun);

                  <body onload="fun()">

                  readyState

                  js
                  document.readyState;\n\ndocument.onreadystatechange;

                  一个文档的 readyState 可以是以下之一:

                  • loading / 加载。document 仍在加载。
                  • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
                  • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。
                  ',9)]))}const k=e(o,[["render",n]]);export{u as __pageData,k as default}; diff --git a/assets/src_article_sort_bubble_index.md.LfnS1mFU.js b/assets/src_article_sort_bubble_index.md.BmVWI7FN.js similarity index 99% rename from assets/src_article_sort_bubble_index.md.LfnS1mFU.js rename to assets/src_article_sort_bubble_index.md.BmVWI7FN.js index 8db7b584fb..08bdeafbb9 100644 --- a/assets/src_article_sort_bubble_index.md.LfnS1mFU.js +++ b/assets/src_article_sort_bubble_index.md.BmVWI7FN.js @@ -1,4 +1,4 @@ -import{_ as i}from"./chunks/bubble.Dg5jgvyl.js";import{_ as a,o as t,c as e,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Bubble Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/bubble/index.md","filePath":"src/article/sort/bubble/index.md","lastUpdated":1728828157000}'),h={name:"src/article/sort/bubble/index.md"};function l(p,s,k,r,d,E){return t(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

                  Bubble Sort

                  Bubble sort is a simple sort algorithm. It repeatedly visits the sequence to be sorted, comparing two elements at a time and swapping them if they are in the wrong order. The work of visiting the sequence is repeated until no more exchanges are needed, that is, the sequence has been sorted. The algorithm gets its name from the fact that smaller elements slowly "float" to the top of the sequence through exchange.

                  Algorithm description

                  • Compare adjacent elements. If the first one is bigger than the second, swap them both;
                  • Do the same for each pair of adjacent elements, from the first pair at the beginning to the last pair at the end, so that the last element should be the largest;
                  • Repeat the above steps for all elements except the last one;
                  • Repeat steps 1 to 3 until the sorting is complete.

                  GIF presentation

                  Bubble Sort

                  Code demo

                  ts
                  const bubble = (list: number[]) => {
                  +import{_ as i}from"./chunks/bubble.Dg5jgvyl.js";import{_ as a,o as t,c as e,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Bubble Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/bubble/index.md","filePath":"src/article/sort/bubble/index.md","lastUpdated":1728921295000}'),h={name:"src/article/sort/bubble/index.md"};function l(p,s,k,r,d,E){return t(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

                  Bubble Sort

                  Bubble sort is a simple sort algorithm. It repeatedly visits the sequence to be sorted, comparing two elements at a time and swapping them if they are in the wrong order. The work of visiting the sequence is repeated until no more exchanges are needed, that is, the sequence has been sorted. The algorithm gets its name from the fact that smaller elements slowly "float" to the top of the sequence through exchange.

                  Algorithm description

                  • Compare adjacent elements. If the first one is bigger than the second, swap them both;
                  • Do the same for each pair of adjacent elements, from the first pair at the beginning to the last pair at the end, so that the last element should be the largest;
                  • Repeat the above steps for all elements except the last one;
                  • Repeat steps 1 to 3 until the sorting is complete.

                  GIF presentation

                  Bubble Sort

                  Code demo

                  ts
                  const bubble = (list: number[]) => {
                     const size = list.length;
                     for (let i = 0; i < size; i++) {
                       for (let j = 0; j < size; j++) {
                  diff --git a/assets/src_article_sort_bubble_index.md.LfnS1mFU.lean.js b/assets/src_article_sort_bubble_index.md.BmVWI7FN.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_bubble_index.md.LfnS1mFU.lean.js
                  rename to assets/src_article_sort_bubble_index.md.BmVWI7FN.lean.js
                  index 8db7b584fb..08bdeafbb9 100644
                  --- a/assets/src_article_sort_bubble_index.md.LfnS1mFU.lean.js
                  +++ b/assets/src_article_sort_bubble_index.md.BmVWI7FN.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/bubble.Dg5jgvyl.js";import{_ as a,o as t,c as e,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Bubble Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/bubble/index.md","filePath":"src/article/sort/bubble/index.md","lastUpdated":1728828157000}'),h={name:"src/article/sort/bubble/index.md"};function l(p,s,k,r,d,E){return t(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

                  Bubble Sort

                  Bubble sort is a simple sort algorithm. It repeatedly visits the sequence to be sorted, comparing two elements at a time and swapping them if they are in the wrong order. The work of visiting the sequence is repeated until no more exchanges are needed, that is, the sequence has been sorted. The algorithm gets its name from the fact that smaller elements slowly "float" to the top of the sequence through exchange.

                  Algorithm description

                  • Compare adjacent elements. If the first one is bigger than the second, swap them both;
                  • Do the same for each pair of adjacent elements, from the first pair at the beginning to the last pair at the end, so that the last element should be the largest;
                  • Repeat the above steps for all elements except the last one;
                  • Repeat steps 1 to 3 until the sorting is complete.

                  GIF presentation

                  Bubble Sort

                  Code demo

                  ts
                  const bubble = (list: number[]) => {
                  +import{_ as i}from"./chunks/bubble.Dg5jgvyl.js";import{_ as a,o as t,c as e,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Bubble Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/bubble/index.md","filePath":"src/article/sort/bubble/index.md","lastUpdated":1728921295000}'),h={name:"src/article/sort/bubble/index.md"};function l(p,s,k,r,d,E){return t(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

                  Bubble Sort

                  Bubble sort is a simple sort algorithm. It repeatedly visits the sequence to be sorted, comparing two elements at a time and swapping them if they are in the wrong order. The work of visiting the sequence is repeated until no more exchanges are needed, that is, the sequence has been sorted. The algorithm gets its name from the fact that smaller elements slowly "float" to the top of the sequence through exchange.

                  Algorithm description

                  • Compare adjacent elements. If the first one is bigger than the second, swap them both;
                  • Do the same for each pair of adjacent elements, from the first pair at the beginning to the last pair at the end, so that the last element should be the largest;
                  • Repeat the above steps for all elements except the last one;
                  • Repeat steps 1 to 3 until the sorting is complete.

                  GIF presentation

                  Bubble Sort

                  Code demo

                  ts
                  const bubble = (list: number[]) => {
                     const size = list.length;
                     for (let i = 0; i < size; i++) {
                       for (let j = 0; j < size; j++) {
                  diff --git a/assets/src_article_sort_bucket_index.md.B2XZzvVq.js b/assets/src_article_sort_bucket_index.md.C8sI_tGv.js
                  similarity index 99%
                  rename from assets/src_article_sort_bucket_index.md.B2XZzvVq.js
                  rename to assets/src_article_sort_bucket_index.md.C8sI_tGv.js
                  index 548d2800e1..d89171136b 100644
                  --- a/assets/src_article_sort_bucket_index.md.B2XZzvVq.js
                  +++ b/assets/src_article_sort_bucket_index.md.C8sI_tGv.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Bucket Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/bucket/index.md","filePath":"src/article/sort/bucket/index.md","lastUpdated":1728828157000}'),k={name:"src/article/sort/bucket/index.md"};function t(l,s,p,e,E,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  Bucket Sort

                  The key to efficiency is this bucket function. The data is divided into a limited number of buckets, and each bucket is sorted separately (it is possible to use another sorting algorithm or recursively continue to use bucket sorting).

                  Algorithm description

                  • Set a quantitative array as an empty bucket;
                  • Iterate over the input data and place the data one by one into the corresponding bucket;
                  • Sort each bucket that is not empty;
                  • Piecing together sorted data from a bucket that is never empty.

                  Code demo

                  ts
                  const count = (list: Array<number>, max: number = 100): Array<number> => {
                  +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Bucket Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/bucket/index.md","filePath":"src/article/sort/bucket/index.md","lastUpdated":1728921295000}'),k={name:"src/article/sort/bucket/index.md"};function t(l,s,p,e,E,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  Bucket Sort

                  The key to efficiency is this bucket function. The data is divided into a limited number of buckets, and each bucket is sorted separately (it is possible to use another sorting algorithm or recursively continue to use bucket sorting).

                  Algorithm description

                  • Set a quantitative array as an empty bucket;
                  • Iterate over the input data and place the data one by one into the corresponding bucket;
                  • Sort each bucket that is not empty;
                  • Piecing together sorted data from a bucket that is never empty.

                  Code demo

                  ts
                  const count = (list: Array<number>, max: number = 100): Array<number> => {
                     const countList = new Array(max + 1);
                     for (let i = 0; i < list.length; i++) {
                       if (!countList[list[i]]) {
                  diff --git a/assets/src_article_sort_bucket_index.md.B2XZzvVq.lean.js b/assets/src_article_sort_bucket_index.md.C8sI_tGv.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_bucket_index.md.B2XZzvVq.lean.js
                  rename to assets/src_article_sort_bucket_index.md.C8sI_tGv.lean.js
                  index 548d2800e1..d89171136b 100644
                  --- a/assets/src_article_sort_bucket_index.md.B2XZzvVq.lean.js
                  +++ b/assets/src_article_sort_bucket_index.md.C8sI_tGv.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Bucket Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/bucket/index.md","filePath":"src/article/sort/bucket/index.md","lastUpdated":1728828157000}'),k={name:"src/article/sort/bucket/index.md"};function t(l,s,p,e,E,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  Bucket Sort

                  The key to efficiency is this bucket function. The data is divided into a limited number of buckets, and each bucket is sorted separately (it is possible to use another sorting algorithm or recursively continue to use bucket sorting).

                  Algorithm description

                  • Set a quantitative array as an empty bucket;
                  • Iterate over the input data and place the data one by one into the corresponding bucket;
                  • Sort each bucket that is not empty;
                  • Piecing together sorted data from a bucket that is never empty.

                  Code demo

                  ts
                  const count = (list: Array<number>, max: number = 100): Array<number> => {
                  +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Bucket Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/bucket/index.md","filePath":"src/article/sort/bucket/index.md","lastUpdated":1728921295000}'),k={name:"src/article/sort/bucket/index.md"};function t(l,s,p,e,E,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  Bucket Sort

                  The key to efficiency is this bucket function. The data is divided into a limited number of buckets, and each bucket is sorted separately (it is possible to use another sorting algorithm or recursively continue to use bucket sorting).

                  Algorithm description

                  • Set a quantitative array as an empty bucket;
                  • Iterate over the input data and place the data one by one into the corresponding bucket;
                  • Sort each bucket that is not empty;
                  • Piecing together sorted data from a bucket that is never empty.

                  Code demo

                  ts
                  const count = (list: Array<number>, max: number = 100): Array<number> => {
                     const countList = new Array(max + 1);
                     for (let i = 0; i < list.length; i++) {
                       if (!countList[list[i]]) {
                  diff --git a/assets/src_article_sort_count_index.md.DPdRRb52.js b/assets/src_article_sort_count_index.md.BXZiVRgc.js
                  similarity index 99%
                  rename from assets/src_article_sort_count_index.md.DPdRRb52.js
                  rename to assets/src_article_sort_count_index.md.BXZiVRgc.js
                  index ed682e75eb..996d370d89 100644
                  --- a/assets/src_article_sort_count_index.md.DPdRRb52.js
                  +++ b/assets/src_article_sort_count_index.md.BXZiVRgc.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/count.CcfK-WL7.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Count Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/count/index.md","filePath":"src/article/sort/count/index.md","lastUpdated":1728828157000}'),l={name:"src/article/sort/count/index.md"};function k(e,s,p,r,E,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

                  Count Sort

                  counting sort is a kind of sorting algorithm that sacrifices memory space for low time complexity, and it is also a kind of algorithm that is not based on comparison. The non-comparison-based sorting algorithm here means that there is no comparison size between array elements. We know that the divide-and-conquer method to solve the sorting problem can only make the time complexity of the algorithm approach Θ(nlogn) at the fastest, that is, the time complexity based on comparison has a lower bound Ω(nlog⁡n), and the sorting algorithm based on no comparison can break through this lower bound.

                  Algorithm description

                  • Find the largest and smallest elements of the array to be sorted;
                  • Count the number of occurrences of each element with value i in the array, stored in the i - th item of the array C;
                  • Add up all counts (starting with the first element in C and adding each term to the previous one);
                  • Backfill the target array: Place each element i in the C(i) item of the new array, and subtract 1 from C(i) for each element.

                  GIF presentation

                  Count Sort

                  Code demo

                  ts
                  const getMax = (list: number[]) => {
                  +import{_ as i}from"./chunks/count.CcfK-WL7.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Count Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/count/index.md","filePath":"src/article/sort/count/index.md","lastUpdated":1728921295000}'),l={name:"src/article/sort/count/index.md"};function k(e,s,p,r,E,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

                  Count Sort

                  counting sort is a kind of sorting algorithm that sacrifices memory space for low time complexity, and it is also a kind of algorithm that is not based on comparison. The non-comparison-based sorting algorithm here means that there is no comparison size between array elements. We know that the divide-and-conquer method to solve the sorting problem can only make the time complexity of the algorithm approach Θ(nlogn) at the fastest, that is, the time complexity based on comparison has a lower bound Ω(nlog⁡n), and the sorting algorithm based on no comparison can break through this lower bound.

                  Algorithm description

                  • Find the largest and smallest elements of the array to be sorted;
                  • Count the number of occurrences of each element with value i in the array, stored in the i - th item of the array C;
                  • Add up all counts (starting with the first element in C and adding each term to the previous one);
                  • Backfill the target array: Place each element i in the C(i) item of the new array, and subtract 1 from C(i) for each element.

                  GIF presentation

                  Count Sort

                  Code demo

                  ts
                  const getMax = (list: number[]) => {
                     let max = list[0];
                     for (let i = 1; i < list.length; i++) {
                       if (max < list[i]) {
                  diff --git a/assets/src_article_sort_count_index.md.DPdRRb52.lean.js b/assets/src_article_sort_count_index.md.BXZiVRgc.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_count_index.md.DPdRRb52.lean.js
                  rename to assets/src_article_sort_count_index.md.BXZiVRgc.lean.js
                  index ed682e75eb..996d370d89 100644
                  --- a/assets/src_article_sort_count_index.md.DPdRRb52.lean.js
                  +++ b/assets/src_article_sort_count_index.md.BXZiVRgc.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/count.CcfK-WL7.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Count Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/count/index.md","filePath":"src/article/sort/count/index.md","lastUpdated":1728828157000}'),l={name:"src/article/sort/count/index.md"};function k(e,s,p,r,E,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

                  Count Sort

                  counting sort is a kind of sorting algorithm that sacrifices memory space for low time complexity, and it is also a kind of algorithm that is not based on comparison. The non-comparison-based sorting algorithm here means that there is no comparison size between array elements. We know that the divide-and-conquer method to solve the sorting problem can only make the time complexity of the algorithm approach Θ(nlogn) at the fastest, that is, the time complexity based on comparison has a lower bound Ω(nlog⁡n), and the sorting algorithm based on no comparison can break through this lower bound.

                  Algorithm description

                  • Find the largest and smallest elements of the array to be sorted;
                  • Count the number of occurrences of each element with value i in the array, stored in the i - th item of the array C;
                  • Add up all counts (starting with the first element in C and adding each term to the previous one);
                  • Backfill the target array: Place each element i in the C(i) item of the new array, and subtract 1 from C(i) for each element.

                  GIF presentation

                  Count Sort

                  Code demo

                  ts
                  const getMax = (list: number[]) => {
                  +import{_ as i}from"./chunks/count.CcfK-WL7.js";import{_ as a,o as n,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Count Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/count/index.md","filePath":"src/article/sort/count/index.md","lastUpdated":1728921295000}'),l={name:"src/article/sort/count/index.md"};function k(e,s,p,r,E,d){return n(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

                  Count Sort

                  counting sort is a kind of sorting algorithm that sacrifices memory space for low time complexity, and it is also a kind of algorithm that is not based on comparison. The non-comparison-based sorting algorithm here means that there is no comparison size between array elements. We know that the divide-and-conquer method to solve the sorting problem can only make the time complexity of the algorithm approach Θ(nlogn) at the fastest, that is, the time complexity based on comparison has a lower bound Ω(nlog⁡n), and the sorting algorithm based on no comparison can break through this lower bound.

                  Algorithm description

                  • Find the largest and smallest elements of the array to be sorted;
                  • Count the number of occurrences of each element with value i in the array, stored in the i - th item of the array C;
                  • Add up all counts (starting with the first element in C and adding each term to the previous one);
                  • Backfill the target array: Place each element i in the C(i) item of the new array, and subtract 1 from C(i) for each element.

                  GIF presentation

                  Count Sort

                  Code demo

                  ts
                  const getMax = (list: number[]) => {
                     let max = list[0];
                     for (let i = 1; i < list.length; i++) {
                       if (max < list[i]) {
                  diff --git a/assets/src_article_sort_heap_index.md.DrKoQkIR.js b/assets/src_article_sort_heap_index.md.D8fxvFJ4.js
                  similarity index 99%
                  rename from assets/src_article_sort_heap_index.md.DrKoQkIR.js
                  rename to assets/src_article_sort_heap_index.md.D8fxvFJ4.js
                  index 40e594cfe5..f02a2a91f6 100644
                  --- a/assets/src_article_sort_heap_index.md.DrKoQkIR.js
                  +++ b/assets/src_article_sort_heap_index.md.D8fxvFJ4.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/heap.xduQWyUN.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"Heap Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/heap/index.md","filePath":"src/article/sort/heap/index.md","lastUpdated":1728828157000}'),t={name:"src/article/sort/heap/index.md"};function l(p,s,e,r,E,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

                  Heap Sort

                  Heapsort (Heapsort) is a kind of sorting algorithm designed by using the heap data structure. A heap is an almost complete binary tree structure, but also satisfies the property of a heap: the key value or index of a child node is always less than (or greater than) its parent node.

                  Algorithm description

                  • The initial sequence of keywords to be sorted (R1,R2... .Rn) builds a large top heap, which is the initial disordered region;
                  • Swap the top element R[1] with the last element R[n] to get a new unordered region (R1,R2,... Rn-1) and a new ordered region (Rn), satisfying R[1,2... n-1]< =R[n];
                  • Since the new top R[1] may violate the nature of the heap after exchange, it is necessary to adjust the current disorder region (R1,R2,... Rn-1) adjusts to the new heap, then swaps R[1] again with the last element of the unordered area, giving a new unordered area (R1,R2... .Rn-2) and the new ordered region (RN-1,Rn). Repeat this process until the number of elements in the ordered area is n-1, then the sorting process is complete.
                  • Use large root piles in ascending order and small root piles in descending order

                  GIF presentation

                  Heap Sort

                  Code demo

                  ts
                  class Heap {
                  +import{_ as i}from"./chunks/heap.xduQWyUN.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"Heap Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/heap/index.md","filePath":"src/article/sort/heap/index.md","lastUpdated":1728921295000}'),t={name:"src/article/sort/heap/index.md"};function l(p,s,e,r,E,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

                  Heap Sort

                  Heapsort (Heapsort) is a kind of sorting algorithm designed by using the heap data structure. A heap is an almost complete binary tree structure, but also satisfies the property of a heap: the key value or index of a child node is always less than (or greater than) its parent node.

                  Algorithm description

                  • The initial sequence of keywords to be sorted (R1,R2... .Rn) builds a large top heap, which is the initial disordered region;
                  • Swap the top element R[1] with the last element R[n] to get a new unordered region (R1,R2,... Rn-1) and a new ordered region (Rn), satisfying R[1,2... n-1]< =R[n];
                  • Since the new top R[1] may violate the nature of the heap after exchange, it is necessary to adjust the current disorder region (R1,R2,... Rn-1) adjusts to the new heap, then swaps R[1] again with the last element of the unordered area, giving a new unordered area (R1,R2... .Rn-2) and the new ordered region (RN-1,Rn). Repeat this process until the number of elements in the ordered area is n-1, then the sorting process is complete.
                  • Use large root piles in ascending order and small root piles in descending order

                  GIF presentation

                  Heap Sort

                  Code demo

                  ts
                  class Heap {
                     value: Array<number>;
                     size: number;
                     constructor(arr: Array<number> = []) {
                  diff --git a/assets/src_article_sort_heap_index.md.DrKoQkIR.lean.js b/assets/src_article_sort_heap_index.md.D8fxvFJ4.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_heap_index.md.DrKoQkIR.lean.js
                  rename to assets/src_article_sort_heap_index.md.D8fxvFJ4.lean.js
                  index 40e594cfe5..f02a2a91f6 100644
                  --- a/assets/src_article_sort_heap_index.md.DrKoQkIR.lean.js
                  +++ b/assets/src_article_sort_heap_index.md.D8fxvFJ4.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/heap.xduQWyUN.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"Heap Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/heap/index.md","filePath":"src/article/sort/heap/index.md","lastUpdated":1728828157000}'),t={name:"src/article/sort/heap/index.md"};function l(p,s,e,r,E,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

                  Heap Sort

                  Heapsort (Heapsort) is a kind of sorting algorithm designed by using the heap data structure. A heap is an almost complete binary tree structure, but also satisfies the property of a heap: the key value or index of a child node is always less than (or greater than) its parent node.

                  Algorithm description

                  • The initial sequence of keywords to be sorted (R1,R2... .Rn) builds a large top heap, which is the initial disordered region;
                  • Swap the top element R[1] with the last element R[n] to get a new unordered region (R1,R2,... Rn-1) and a new ordered region (Rn), satisfying R[1,2... n-1]< =R[n];
                  • Since the new top R[1] may violate the nature of the heap after exchange, it is necessary to adjust the current disorder region (R1,R2,... Rn-1) adjusts to the new heap, then swaps R[1] again with the last element of the unordered area, giving a new unordered area (R1,R2... .Rn-2) and the new ordered region (RN-1,Rn). Repeat this process until the number of elements in the ordered area is n-1, then the sorting process is complete.
                  • Use large root piles in ascending order and small root piles in descending order

                  GIF presentation

                  Heap Sort

                  Code demo

                  ts
                  class Heap {
                  +import{_ as i}from"./chunks/heap.xduQWyUN.js";import{_ as a,o as h,c as n,a3 as k}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"Heap Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/heap/index.md","filePath":"src/article/sort/heap/index.md","lastUpdated":1728921295000}'),t={name:"src/article/sort/heap/index.md"};function l(p,s,e,r,E,d){return h(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k('

                  Heap Sort

                  Heapsort (Heapsort) is a kind of sorting algorithm designed by using the heap data structure. A heap is an almost complete binary tree structure, but also satisfies the property of a heap: the key value or index of a child node is always less than (or greater than) its parent node.

                  Algorithm description

                  • The initial sequence of keywords to be sorted (R1,R2... .Rn) builds a large top heap, which is the initial disordered region;
                  • Swap the top element R[1] with the last element R[n] to get a new unordered region (R1,R2,... Rn-1) and a new ordered region (Rn), satisfying R[1,2... n-1]< =R[n];
                  • Since the new top R[1] may violate the nature of the heap after exchange, it is necessary to adjust the current disorder region (R1,R2,... Rn-1) adjusts to the new heap, then swaps R[1] again with the last element of the unordered area, giving a new unordered area (R1,R2... .Rn-2) and the new ordered region (RN-1,Rn). Repeat this process until the number of elements in the ordered area is n-1, then the sorting process is complete.
                  • Use large root piles in ascending order and small root piles in descending order

                  GIF presentation

                  Heap Sort

                  Code demo

                  ts
                  class Heap {
                     value: Array<number>;
                     size: number;
                     constructor(arr: Array<number> = []) {
                  diff --git a/assets/src_article_sort_index.md.ILCQfWPM.js b/assets/src_article_sort_index.md.Du9jHICi.js
                  similarity index 97%
                  rename from assets/src_article_sort_index.md.ILCQfWPM.js
                  rename to assets/src_article_sort_index.md.Du9jHICi.js
                  index d049d35e4e..d41e4b4318 100644
                  --- a/assets/src_article_sort_index.md.ILCQfWPM.js
                  +++ b/assets/src_article_sort_index.md.Du9jHICi.js
                  @@ -1 +1 @@
                  -import{_ as t,a}from"./chunks/complexity.CSkvDr7k.js";import{_ as o,o as i,c as r,a3 as n}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Ten classic sorting algorithms","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/index.md","filePath":"src/article/sort/index.md","lastUpdated":1728828157000}'),s={name:"src/article/sort/index.md"};function l(c,e,m,d,h,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[n('

                  Ten classic sorting algorithms

                  The ten common sorting algorithms can be divided into two broad categories:

                  • Comparator sort:By comparison to determine the relative order between elements, because its time complexity can not break through O(nlogn), so it is also called nonlinear time comparison class sorting.
                  • Non-comparison sort:Instead of determining the relative order between elements by comparison, it can break through the time lower bound based on comparison sort and run in linear time, so it is also called linear time non-comparison sort.

                  Sorting algorithm classification

                  Algorithm complexity

                  Algorithm complexity

                  • Stable: If a was originally in front of b and a=b, a is still in front of b after sorting.
                  • Unstable: If a originally comes before b and a=b, a may come after b after sorting.
                  • Time complexity: The total number of operations on sorted data. Reflects what rule the number of operations presents when n changes.
                  • Spatial complexity: refers to the measure of the storage space required when the algorithm is executed in the computer, and it is also a function of the data size n.
                  ',8)]))}const u=o(s,[["render",l]]);export{b as __pageData,u as default}; +import{_ as t,a}from"./chunks/complexity.CSkvDr7k.js";import{_ as o,o as i,c as r,a3 as n}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Ten classic sorting algorithms","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/index.md","filePath":"src/article/sort/index.md","lastUpdated":1728921295000}'),s={name:"src/article/sort/index.md"};function l(c,e,m,d,h,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[n('

                  Ten classic sorting algorithms

                  The ten common sorting algorithms can be divided into two broad categories:

                  • Comparator sort:By comparison to determine the relative order between elements, because its time complexity can not break through O(nlogn), so it is also called nonlinear time comparison class sorting.
                  • Non-comparison sort:Instead of determining the relative order between elements by comparison, it can break through the time lower bound based on comparison sort and run in linear time, so it is also called linear time non-comparison sort.

                  Sorting algorithm classification

                  Algorithm complexity

                  Algorithm complexity

                  • Stable: If a was originally in front of b and a=b, a is still in front of b after sorting.
                  • Unstable: If a originally comes before b and a=b, a may come after b after sorting.
                  • Time complexity: The total number of operations on sorted data. Reflects what rule the number of operations presents when n changes.
                  • Spatial complexity: refers to the measure of the storage space required when the algorithm is executed in the computer, and it is also a function of the data size n.
                  ',8)]))}const u=o(s,[["render",l]]);export{b as __pageData,u as default}; diff --git a/assets/src_article_sort_index.md.ILCQfWPM.lean.js b/assets/src_article_sort_index.md.Du9jHICi.lean.js similarity index 97% rename from assets/src_article_sort_index.md.ILCQfWPM.lean.js rename to assets/src_article_sort_index.md.Du9jHICi.lean.js index d049d35e4e..d41e4b4318 100644 --- a/assets/src_article_sort_index.md.ILCQfWPM.lean.js +++ b/assets/src_article_sort_index.md.Du9jHICi.lean.js @@ -1 +1 @@ -import{_ as t,a}from"./chunks/complexity.CSkvDr7k.js";import{_ as o,o as i,c as r,a3 as n}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Ten classic sorting algorithms","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/index.md","filePath":"src/article/sort/index.md","lastUpdated":1728828157000}'),s={name:"src/article/sort/index.md"};function l(c,e,m,d,h,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[n('

                  Ten classic sorting algorithms

                  The ten common sorting algorithms can be divided into two broad categories:

                  • Comparator sort:By comparison to determine the relative order between elements, because its time complexity can not break through O(nlogn), so it is also called nonlinear time comparison class sorting.
                  • Non-comparison sort:Instead of determining the relative order between elements by comparison, it can break through the time lower bound based on comparison sort and run in linear time, so it is also called linear time non-comparison sort.

                  Sorting algorithm classification

                  Algorithm complexity

                  Algorithm complexity

                  • Stable: If a was originally in front of b and a=b, a is still in front of b after sorting.
                  • Unstable: If a originally comes before b and a=b, a may come after b after sorting.
                  • Time complexity: The total number of operations on sorted data. Reflects what rule the number of operations presents when n changes.
                  • Spatial complexity: refers to the measure of the storage space required when the algorithm is executed in the computer, and it is also a function of the data size n.
                  ',8)]))}const u=o(s,[["render",l]]);export{b as __pageData,u as default}; +import{_ as t,a}from"./chunks/complexity.CSkvDr7k.js";import{_ as o,o as i,c as r,a3 as n}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Ten classic sorting algorithms","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/index.md","filePath":"src/article/sort/index.md","lastUpdated":1728921295000}'),s={name:"src/article/sort/index.md"};function l(c,e,m,d,h,p){return i(),r("div",{"data-pagefind-body":!0},e[0]||(e[0]=[n('

                  Ten classic sorting algorithms

                  The ten common sorting algorithms can be divided into two broad categories:

                  • Comparator sort:By comparison to determine the relative order between elements, because its time complexity can not break through O(nlogn), so it is also called nonlinear time comparison class sorting.
                  • Non-comparison sort:Instead of determining the relative order between elements by comparison, it can break through the time lower bound based on comparison sort and run in linear time, so it is also called linear time non-comparison sort.

                  Sorting algorithm classification

                  Algorithm complexity

                  Algorithm complexity

                  • Stable: If a was originally in front of b and a=b, a is still in front of b after sorting.
                  • Unstable: If a originally comes before b and a=b, a may come after b after sorting.
                  • Time complexity: The total number of operations on sorted data. Reflects what rule the number of operations presents when n changes.
                  • Spatial complexity: refers to the measure of the storage space required when the algorithm is executed in the computer, and it is also a function of the data size n.
                  ',8)]))}const u=o(s,[["render",l]]);export{b as __pageData,u as default}; diff --git a/assets/src_article_sort_insert_index.md.DkXN_nPk.js b/assets/src_article_sort_insert_index.md.CBL5Zq0h.js similarity index 99% rename from assets/src_article_sort_insert_index.md.DkXN_nPk.js rename to assets/src_article_sort_insert_index.md.CBL5Zq0h.js index e0b6ad9ef6..7a6ea81199 100644 --- a/assets/src_article_sort_insert_index.md.DkXN_nPk.js +++ b/assets/src_article_sort_insert_index.md.CBL5Zq0h.js @@ -1,4 +1,4 @@ -import{_ as i}from"./chunks/insert.Bde3uDH4.js";import{_ as a,o as t,c as e,a3 as n}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Insert Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/insert/index.md","filePath":"src/article/sort/insert/index.md","lastUpdated":1728828157000}'),h={name:"src/article/sort/insert/index.md"};function l(p,s,r,k,d,o){return t(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

                  Insert Sort

                  Stable sorting algorithm, because no matter what data is entered is O(n2) time complexity, so when it is used, the smaller the data size, the better. The advantage is that no additional memory space is taken up. It works by building an ordered sequence and, for unsorted data, scanning from back to front in the sorted sequence, finding the appropriate position and inserting it.

                  Algorithm description

                  • Start with the first element, which can be considered to have been sorted;
                  • Take the next element and scan it from back to front in the already sorted sequence of elements;
                  • If the element (sorted) is larger than the new element, move the element to the next position;
                  • Repeat step 3 until you find a position where the sorted element is less than or equal to the new element;
                  • After inserting a new element into this position;
                  • Repeat Steps 2 to 5.

                  GIF presentation

                  Insert Sort

                  Code demo

                  ts
                  const insert = (list: number[]): number[] => {
                  +import{_ as i}from"./chunks/insert.Bde3uDH4.js";import{_ as a,o as t,c as e,a3 as n}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Insert Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/insert/index.md","filePath":"src/article/sort/insert/index.md","lastUpdated":1728921295000}'),h={name:"src/article/sort/insert/index.md"};function l(p,s,r,k,d,o){return t(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

                  Insert Sort

                  Stable sorting algorithm, because no matter what data is entered is O(n2) time complexity, so when it is used, the smaller the data size, the better. The advantage is that no additional memory space is taken up. It works by building an ordered sequence and, for unsorted data, scanning from back to front in the sorted sequence, finding the appropriate position and inserting it.

                  Algorithm description

                  • Start with the first element, which can be considered to have been sorted;
                  • Take the next element and scan it from back to front in the already sorted sequence of elements;
                  • If the element (sorted) is larger than the new element, move the element to the next position;
                  • Repeat step 3 until you find a position where the sorted element is less than or equal to the new element;
                  • After inserting a new element into this position;
                  • Repeat Steps 2 to 5.

                  GIF presentation

                  Insert Sort

                  Code demo

                  ts
                  const insert = (list: number[]): number[] => {
                     const size = list.length;
                     for (let i = 1; i < size; i++) {
                       const current = list[i];
                  diff --git a/assets/src_article_sort_insert_index.md.DkXN_nPk.lean.js b/assets/src_article_sort_insert_index.md.CBL5Zq0h.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_insert_index.md.DkXN_nPk.lean.js
                  rename to assets/src_article_sort_insert_index.md.CBL5Zq0h.lean.js
                  index e0b6ad9ef6..7a6ea81199 100644
                  --- a/assets/src_article_sort_insert_index.md.DkXN_nPk.lean.js
                  +++ b/assets/src_article_sort_insert_index.md.CBL5Zq0h.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/insert.Bde3uDH4.js";import{_ as a,o as t,c as e,a3 as n}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Insert Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/insert/index.md","filePath":"src/article/sort/insert/index.md","lastUpdated":1728828157000}'),h={name:"src/article/sort/insert/index.md"};function l(p,s,r,k,d,o){return t(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

                  Insert Sort

                  Stable sorting algorithm, because no matter what data is entered is O(n2) time complexity, so when it is used, the smaller the data size, the better. The advantage is that no additional memory space is taken up. It works by building an ordered sequence and, for unsorted data, scanning from back to front in the sorted sequence, finding the appropriate position and inserting it.

                  Algorithm description

                  • Start with the first element, which can be considered to have been sorted;
                  • Take the next element and scan it from back to front in the already sorted sequence of elements;
                  • If the element (sorted) is larger than the new element, move the element to the next position;
                  • Repeat step 3 until you find a position where the sorted element is less than or equal to the new element;
                  • After inserting a new element into this position;
                  • Repeat Steps 2 to 5.

                  GIF presentation

                  Insert Sort

                  Code demo

                  ts
                  const insert = (list: number[]): number[] => {
                  +import{_ as i}from"./chunks/insert.Bde3uDH4.js";import{_ as a,o as t,c as e,a3 as n}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Insert Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/insert/index.md","filePath":"src/article/sort/insert/index.md","lastUpdated":1728921295000}'),h={name:"src/article/sort/insert/index.md"};function l(p,s,r,k,d,o){return t(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n('

                  Insert Sort

                  Stable sorting algorithm, because no matter what data is entered is O(n2) time complexity, so when it is used, the smaller the data size, the better. The advantage is that no additional memory space is taken up. It works by building an ordered sequence and, for unsorted data, scanning from back to front in the sorted sequence, finding the appropriate position and inserting it.

                  Algorithm description

                  • Start with the first element, which can be considered to have been sorted;
                  • Take the next element and scan it from back to front in the already sorted sequence of elements;
                  • If the element (sorted) is larger than the new element, move the element to the next position;
                  • Repeat step 3 until you find a position where the sorted element is less than or equal to the new element;
                  • After inserting a new element into this position;
                  • Repeat Steps 2 to 5.

                  GIF presentation

                  Insert Sort

                  Code demo

                  ts
                  const insert = (list: number[]): number[] => {
                     const size = list.length;
                     for (let i = 1; i < size; i++) {
                       const current = list[i];
                  diff --git a/assets/src_article_sort_merge_index.md.BrDl4p8K.js b/assets/src_article_sort_merge_index.md.DR-N5gUH.js
                  similarity index 99%
                  rename from assets/src_article_sort_merge_index.md.BrDl4p8K.js
                  rename to assets/src_article_sort_merge_index.md.DR-N5gUH.js
                  index 4681f70954..22cfd6027c 100644
                  --- a/assets/src_article_sort_merge_index.md.BrDl4p8K.js
                  +++ b/assets/src_article_sort_merge_index.md.DR-N5gUH.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/merge.D_M4N_iU.js";import{_ as a,o as n,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Merge Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/merge/index.md","filePath":"src/article/sort/merge/index.md","lastUpdated":1728828157000}'),l={name:"src/article/sort/merge/index.md"};function k(e,s,p,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Merge Sort

                  Merge sort is an effective sort algorithm based on merge operation. This algorithm is a very typical application of Divide and Conquer. By combining the ordered subsequences, a completely ordered sequence is obtained. That is, each subsequence is ordered first, and then the subsequence segments are ordered. If two ordered tables are merged into one ordered table, it is called a 2-way merge.

                  Algorithm description

                  • Divide the input sequence of length n into two subsequences of length n/2;
                  • The two subsequences were merged and sorted respectively.
                  • Merge two sorted subsequences into one final sorted sequence.

                  GIF presentation

                  Merge Sort

                  Code demo

                  ts
                  const combine = (left: Array<number>, right: Array<number>) => {
                  +import{_ as i}from"./chunks/merge.D_M4N_iU.js";import{_ as a,o as n,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Merge Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/merge/index.md","filePath":"src/article/sort/merge/index.md","lastUpdated":1728921295000}'),l={name:"src/article/sort/merge/index.md"};function k(e,s,p,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Merge Sort

                  Merge sort is an effective sort algorithm based on merge operation. This algorithm is a very typical application of Divide and Conquer. By combining the ordered subsequences, a completely ordered sequence is obtained. That is, each subsequence is ordered first, and then the subsequence segments are ordered. If two ordered tables are merged into one ordered table, it is called a 2-way merge.

                  Algorithm description

                  • Divide the input sequence of length n into two subsequences of length n/2;
                  • The two subsequences were merged and sorted respectively.
                  • Merge two sorted subsequences into one final sorted sequence.

                  GIF presentation

                  Merge Sort

                  Code demo

                  ts
                  const combine = (left: Array<number>, right: Array<number>) => {
                     const list: Array<number> = [];
                     while (left.length > 0 && right.length > 0) {
                       if (left[0] <= right[0]) {
                  diff --git a/assets/src_article_sort_merge_index.md.BrDl4p8K.lean.js b/assets/src_article_sort_merge_index.md.DR-N5gUH.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_merge_index.md.BrDl4p8K.lean.js
                  rename to assets/src_article_sort_merge_index.md.DR-N5gUH.lean.js
                  index 4681f70954..22cfd6027c 100644
                  --- a/assets/src_article_sort_merge_index.md.BrDl4p8K.lean.js
                  +++ b/assets/src_article_sort_merge_index.md.DR-N5gUH.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/merge.D_M4N_iU.js";import{_ as a,o as n,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Merge Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/merge/index.md","filePath":"src/article/sort/merge/index.md","lastUpdated":1728828157000}'),l={name:"src/article/sort/merge/index.md"};function k(e,s,p,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Merge Sort

                  Merge sort is an effective sort algorithm based on merge operation. This algorithm is a very typical application of Divide and Conquer. By combining the ordered subsequences, a completely ordered sequence is obtained. That is, each subsequence is ordered first, and then the subsequence segments are ordered. If two ordered tables are merged into one ordered table, it is called a 2-way merge.

                  Algorithm description

                  • Divide the input sequence of length n into two subsequences of length n/2;
                  • The two subsequences were merged and sorted respectively.
                  • Merge two sorted subsequences into one final sorted sequence.

                  GIF presentation

                  Merge Sort

                  Code demo

                  ts
                  const combine = (left: Array<number>, right: Array<number>) => {
                  +import{_ as i}from"./chunks/merge.D_M4N_iU.js";import{_ as a,o as n,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Merge Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/merge/index.md","filePath":"src/article/sort/merge/index.md","lastUpdated":1728921295000}'),l={name:"src/article/sort/merge/index.md"};function k(e,s,p,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Merge Sort

                  Merge sort is an effective sort algorithm based on merge operation. This algorithm is a very typical application of Divide and Conquer. By combining the ordered subsequences, a completely ordered sequence is obtained. That is, each subsequence is ordered first, and then the subsequence segments are ordered. If two ordered tables are merged into one ordered table, it is called a 2-way merge.

                  Algorithm description

                  • Divide the input sequence of length n into two subsequences of length n/2;
                  • The two subsequences were merged and sorted respectively.
                  • Merge two sorted subsequences into one final sorted sequence.

                  GIF presentation

                  Merge Sort

                  Code demo

                  ts
                  const combine = (left: Array<number>, right: Array<number>) => {
                     const list: Array<number> = [];
                     while (left.length > 0 && right.length > 0) {
                       if (left[0] <= right[0]) {
                  diff --git a/assets/src_article_sort_quick_index.md.DR2SVz8M.js b/assets/src_article_sort_quick_index.md.B-15itZC.js
                  similarity index 99%
                  rename from assets/src_article_sort_quick_index.md.DR2SVz8M.js
                  rename to assets/src_article_sort_quick_index.md.B-15itZC.js
                  index e9ab213a91..3bcefc68c4 100644
                  --- a/assets/src_article_sort_quick_index.md.DR2SVz8M.js
                  +++ b/assets/src_article_sort_quick_index.md.B-15itZC.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/quick.WcLzRUPH.js";import{_ as a,o as n,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"Quick Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/quick/index.md","filePath":"src/article/sort/quick/index.md","lastUpdated":1728828157000}'),k={name:"src/article/sort/quick/index.md"};function l(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Quick Sort

                  The basic idea of quick sorting is that the records to be sorted are separated into two independent parts through one sort. The keywords of one part of the records are smaller than those of the other part. Then the two parts of the records can be sorted separately to achieve the entire sequence.

                  Algorithm description

                  Quicksort uses divide-and-conquer to divide a list into two sub-lists. The specific algorithm is described as follows:

                  • Picking out an element from the sequence, called a "pivot";
                  • Reorder the sequence so that all elements smaller than the base value are placed in front of the base value and all elements larger than the base value are placed behind the base value (the same number can go to either side). After the partition exits, the benchmark is in the middle of the sequence. This is called a partition operation;
                  • Recursively sorts subsequences of elements less than the base value and subsequences of elements greater than the base value.

                  GIF presentation

                  Quick Sort

                  Code demo

                  ts
                  /**
                  +import{_ as i}from"./chunks/quick.WcLzRUPH.js";import{_ as a,o as n,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"Quick Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/quick/index.md","filePath":"src/article/sort/quick/index.md","lastUpdated":1728921295000}'),k={name:"src/article/sort/quick/index.md"};function l(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Quick Sort

                  The basic idea of quick sorting is that the records to be sorted are separated into two independent parts through one sort. The keywords of one part of the records are smaller than those of the other part. Then the two parts of the records can be sorted separately to achieve the entire sequence.

                  Algorithm description

                  Quicksort uses divide-and-conquer to divide a list into two sub-lists. The specific algorithm is described as follows:

                  • Picking out an element from the sequence, called a "pivot";
                  • Reorder the sequence so that all elements smaller than the base value are placed in front of the base value and all elements larger than the base value are placed behind the base value (the same number can go to either side). After the partition exits, the benchmark is in the middle of the sequence. This is called a partition operation;
                  • Recursively sorts subsequences of elements less than the base value and subsequences of elements greater than the base value.

                  GIF presentation

                  Quick Sort

                  Code demo

                  ts
                  /**
                    * @description: Sets the base value pivot
                    * @param {Array} list
                    * @param {number} left
                  diff --git a/assets/src_article_sort_quick_index.md.DR2SVz8M.lean.js b/assets/src_article_sort_quick_index.md.B-15itZC.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_quick_index.md.DR2SVz8M.lean.js
                  rename to assets/src_article_sort_quick_index.md.B-15itZC.lean.js
                  index e9ab213a91..3bcefc68c4 100644
                  --- a/assets/src_article_sort_quick_index.md.DR2SVz8M.lean.js
                  +++ b/assets/src_article_sort_quick_index.md.B-15itZC.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/quick.WcLzRUPH.js";import{_ as a,o as n,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"Quick Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/quick/index.md","filePath":"src/article/sort/quick/index.md","lastUpdated":1728828157000}'),k={name:"src/article/sort/quick/index.md"};function l(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Quick Sort

                  The basic idea of quick sorting is that the records to be sorted are separated into two independent parts through one sort. The keywords of one part of the records are smaller than those of the other part. Then the two parts of the records can be sorted separately to achieve the entire sequence.

                  Algorithm description

                  Quicksort uses divide-and-conquer to divide a list into two sub-lists. The specific algorithm is described as follows:

                  • Picking out an element from the sequence, called a "pivot";
                  • Reorder the sequence so that all elements smaller than the base value are placed in front of the base value and all elements larger than the base value are placed behind the base value (the same number can go to either side). After the partition exits, the benchmark is in the middle of the sequence. This is called a partition operation;
                  • Recursively sorts subsequences of elements less than the base value and subsequences of elements greater than the base value.

                  GIF presentation

                  Quick Sort

                  Code demo

                  ts
                  /**
                  +import{_ as i}from"./chunks/quick.WcLzRUPH.js";import{_ as a,o as n,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"Quick Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/quick/index.md","filePath":"src/article/sort/quick/index.md","lastUpdated":1728921295000}'),k={name:"src/article/sort/quick/index.md"};function l(p,s,e,r,E,d){return n(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Quick Sort

                  The basic idea of quick sorting is that the records to be sorted are separated into two independent parts through one sort. The keywords of one part of the records are smaller than those of the other part. Then the two parts of the records can be sorted separately to achieve the entire sequence.

                  Algorithm description

                  Quicksort uses divide-and-conquer to divide a list into two sub-lists. The specific algorithm is described as follows:

                  • Picking out an element from the sequence, called a "pivot";
                  • Reorder the sequence so that all elements smaller than the base value are placed in front of the base value and all elements larger than the base value are placed behind the base value (the same number can go to either side). After the partition exits, the benchmark is in the middle of the sequence. This is called a partition operation;
                  • Recursively sorts subsequences of elements less than the base value and subsequences of elements greater than the base value.

                  GIF presentation

                  Quick Sort

                  Code demo

                  ts
                  /**
                    * @description: Sets the base value pivot
                    * @param {Array} list
                    * @param {number} left
                  diff --git a/assets/src_article_sort_radix_index.md.BfE2sE6Y.js b/assets/src_article_sort_radix_index.md.DYGHdCvy.js
                  similarity index 99%
                  rename from assets/src_article_sort_radix_index.md.BfE2sE6Y.js
                  rename to assets/src_article_sort_radix_index.md.DYGHdCvy.js
                  index 42404c62eb..d16a110f51 100644
                  --- a/assets/src_article_sort_radix_index.md.BfE2sE6Y.js
                  +++ b/assets/src_article_sort_radix_index.md.DYGHdCvy.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/radix.CHOmrmB0.js";import{_ as a,o as t,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Radix Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/radix/index.md","filePath":"src/article/sort/radix/index.md","lastUpdated":1728828157000}'),k={name:"src/article/sort/radix/index.md"};function l(p,s,e,r,E,d){return t(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

                  Radix Sort

                  Radix sort is sorted by the lowest order first, and then collected; Then sort by high order, and then collect; And so on until you reach the top. Sometimes properties are prioritized, first by low priority and then by high priority. The final order is that the higher priority comes first and the lower priority comes first if the higher priority is the same. Bucket sort extension, similar to specifying bucket sort by bit, but can take advantage of the count sort for a small range of numbers.

                  Algorithm description

                  • Get the largest number in the array, and get the number of bits;
                  • arr is the original array, and each bit is taken from the lowest point to form radix array.
                  • radix was sorted by counting (taking advantage of the feature that counting sort is suitable for a small range of numbers);

                  GIF presentation

                  Radix Sort

                  Code demo

                  ts
                  const getMax = (list: Array<number>) => {
                  +import{_ as i}from"./chunks/radix.CHOmrmB0.js";import{_ as a,o as t,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Radix Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/radix/index.md","filePath":"src/article/sort/radix/index.md","lastUpdated":1728921295000}'),k={name:"src/article/sort/radix/index.md"};function l(p,s,e,r,E,d){return t(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

                  Radix Sort

                  Radix sort is sorted by the lowest order first, and then collected; Then sort by high order, and then collect; And so on until you reach the top. Sometimes properties are prioritized, first by low priority and then by high priority. The final order is that the higher priority comes first and the lower priority comes first if the higher priority is the same. Bucket sort extension, similar to specifying bucket sort by bit, but can take advantage of the count sort for a small range of numbers.

                  Algorithm description

                  • Get the largest number in the array, and get the number of bits;
                  • arr is the original array, and each bit is taken from the lowest point to form radix array.
                  • radix was sorted by counting (taking advantage of the feature that counting sort is suitable for a small range of numbers);

                  GIF presentation

                  Radix Sort

                  Code demo

                  ts
                  const getMax = (list: Array<number>) => {
                     let max = list[0];
                     for (let i = 0; i < list.length; i++) {
                       if (max < list[i]) {
                  diff --git a/assets/src_article_sort_radix_index.md.BfE2sE6Y.lean.js b/assets/src_article_sort_radix_index.md.DYGHdCvy.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_radix_index.md.BfE2sE6Y.lean.js
                  rename to assets/src_article_sort_radix_index.md.DYGHdCvy.lean.js
                  index 42404c62eb..d16a110f51 100644
                  --- a/assets/src_article_sort_radix_index.md.BfE2sE6Y.lean.js
                  +++ b/assets/src_article_sort_radix_index.md.DYGHdCvy.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/radix.CHOmrmB0.js";import{_ as a,o as t,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Radix Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/radix/index.md","filePath":"src/article/sort/radix/index.md","lastUpdated":1728828157000}'),k={name:"src/article/sort/radix/index.md"};function l(p,s,e,r,E,d){return t(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

                  Radix Sort

                  Radix sort is sorted by the lowest order first, and then collected; Then sort by high order, and then collect; And so on until you reach the top. Sometimes properties are prioritized, first by low priority and then by high priority. The final order is that the higher priority comes first and the lower priority comes first if the higher priority is the same. Bucket sort extension, similar to specifying bucket sort by bit, but can take advantage of the count sort for a small range of numbers.

                  Algorithm description

                  • Get the largest number in the array, and get the number of bits;
                  • arr is the original array, and each bit is taken from the lowest point to form radix array.
                  • radix was sorted by counting (taking advantage of the feature that counting sort is suitable for a small range of numbers);

                  GIF presentation

                  Radix Sort

                  Code demo

                  ts
                  const getMax = (list: Array<number>) => {
                  +import{_ as i}from"./chunks/radix.CHOmrmB0.js";import{_ as a,o as t,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"Radix Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/radix/index.md","filePath":"src/article/sort/radix/index.md","lastUpdated":1728921295000}'),k={name:"src/article/sort/radix/index.md"};function l(p,s,e,r,E,d){return t(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h('

                  Radix Sort

                  Radix sort is sorted by the lowest order first, and then collected; Then sort by high order, and then collect; And so on until you reach the top. Sometimes properties are prioritized, first by low priority and then by high priority. The final order is that the higher priority comes first and the lower priority comes first if the higher priority is the same. Bucket sort extension, similar to specifying bucket sort by bit, but can take advantage of the count sort for a small range of numbers.

                  Algorithm description

                  • Get the largest number in the array, and get the number of bits;
                  • arr is the original array, and each bit is taken from the lowest point to form radix array.
                  • radix was sorted by counting (taking advantage of the feature that counting sort is suitable for a small range of numbers);

                  GIF presentation

                  Radix Sort

                  Code demo

                  ts
                  const getMax = (list: Array<number>) => {
                     let max = list[0];
                     for (let i = 0; i < list.length; i++) {
                       if (max < list[i]) {
                  diff --git a/assets/src_article_sort_select_index.md.D6mV4SPJ.js b/assets/src_article_sort_select_index.md.sRykeoeT.js
                  similarity index 99%
                  rename from assets/src_article_sort_select_index.md.D6mV4SPJ.js
                  rename to assets/src_article_sort_select_index.md.sRykeoeT.js
                  index f89529b8de..52535c8bc0 100644
                  --- a/assets/src_article_sort_select_index.md.D6mV4SPJ.js
                  +++ b/assets/src_article_sort_select_index.md.sRykeoeT.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/select.BGReufCV.js";import{_ as a,o as t,c as n,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Selection Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/select/index.md","filePath":"src/article/sort/select/index.md","lastUpdated":1728828157000}'),h={name:"src/article/sort/select/index.md"};function l(k,s,r,p,d,o){return t(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e('

                  Selection Sort

                  Select-sort is a simple and intuitive sorting algorithm. It works by first finding the smallest (large) element in the unsorted sequence and storing it at the beginning of the sorted sequence, then continuing to find the smallest (large) element from the remaining unsorted elements and placing it at the end of the sorted sequence. And so on until all the elements are sorted.

                  Algorithm description

                  Ordering results can be obtained by direct selection sorting of n records through n-1 direct selection sorting. The specific algorithm is described as follows:

                  • Initial state: disordered region is R[1..n], ordered region is empty;
                  • i sort (i=1,2,3... n-1) At the beginning, the current ordered and disordered regions are R[1..i-1] and R(i.. n). The run sort selects the record R[k] with the smallest keyword from the current unordered area and swaps it with the first record R in the unordered area, so that R[1..i] and R[i+1..n) become a new ordered area with 1 more records and a new unordered area with 1 less records, respectively.
                  • n-1 is done. The array is ordered.

                  GIF presentation

                  Selection Sort

                  Code demo

                  js
                  const select = (list: number[]): number[] => {
                  +import{_ as i}from"./chunks/select.BGReufCV.js";import{_ as a,o as t,c as n,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Selection Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/select/index.md","filePath":"src/article/sort/select/index.md","lastUpdated":1728921295000}'),h={name:"src/article/sort/select/index.md"};function l(k,s,r,p,d,o){return t(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e('

                  Selection Sort

                  Select-sort is a simple and intuitive sorting algorithm. It works by first finding the smallest (large) element in the unsorted sequence and storing it at the beginning of the sorted sequence, then continuing to find the smallest (large) element from the remaining unsorted elements and placing it at the end of the sorted sequence. And so on until all the elements are sorted.

                  Algorithm description

                  Ordering results can be obtained by direct selection sorting of n records through n-1 direct selection sorting. The specific algorithm is described as follows:

                  • Initial state: disordered region is R[1..n], ordered region is empty;
                  • i sort (i=1,2,3... n-1) At the beginning, the current ordered and disordered regions are R[1..i-1] and R(i.. n). The run sort selects the record R[k] with the smallest keyword from the current unordered area and swaps it with the first record R in the unordered area, so that R[1..i] and R[i+1..n) become a new ordered area with 1 more records and a new unordered area with 1 less records, respectively.
                  • n-1 is done. The array is ordered.

                  GIF presentation

                  Selection Sort

                  Code demo

                  js
                  const select = (list: number[]): number[] => {
                     const size = list.length;
                     for (let i = 0; i < size; i++) {
                       let minIndex = i;
                  diff --git a/assets/src_article_sort_select_index.md.D6mV4SPJ.lean.js b/assets/src_article_sort_select_index.md.sRykeoeT.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_select_index.md.D6mV4SPJ.lean.js
                  rename to assets/src_article_sort_select_index.md.sRykeoeT.lean.js
                  index f89529b8de..52535c8bc0 100644
                  --- a/assets/src_article_sort_select_index.md.D6mV4SPJ.lean.js
                  +++ b/assets/src_article_sort_select_index.md.sRykeoeT.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/select.BGReufCV.js";import{_ as a,o as t,c as n,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Selection Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/select/index.md","filePath":"src/article/sort/select/index.md","lastUpdated":1728828157000}'),h={name:"src/article/sort/select/index.md"};function l(k,s,r,p,d,o){return t(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e('

                  Selection Sort

                  Select-sort is a simple and intuitive sorting algorithm. It works by first finding the smallest (large) element in the unsorted sequence and storing it at the beginning of the sorted sequence, then continuing to find the smallest (large) element from the remaining unsorted elements and placing it at the end of the sorted sequence. And so on until all the elements are sorted.

                  Algorithm description

                  Ordering results can be obtained by direct selection sorting of n records through n-1 direct selection sorting. The specific algorithm is described as follows:

                  • Initial state: disordered region is R[1..n], ordered region is empty;
                  • i sort (i=1,2,3... n-1) At the beginning, the current ordered and disordered regions are R[1..i-1] and R(i.. n). The run sort selects the record R[k] with the smallest keyword from the current unordered area and swaps it with the first record R in the unordered area, so that R[1..i] and R[i+1..n) become a new ordered area with 1 more records and a new unordered area with 1 less records, respectively.
                  • n-1 is done. The array is ordered.

                  GIF presentation

                  Selection Sort

                  Code demo

                  js
                  const select = (list: number[]): number[] => {
                  +import{_ as i}from"./chunks/select.BGReufCV.js";import{_ as a,o as t,c as n,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Selection Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/select/index.md","filePath":"src/article/sort/select/index.md","lastUpdated":1728921295000}'),h={name:"src/article/sort/select/index.md"};function l(k,s,r,p,d,o){return t(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e('

                  Selection Sort

                  Select-sort is a simple and intuitive sorting algorithm. It works by first finding the smallest (large) element in the unsorted sequence and storing it at the beginning of the sorted sequence, then continuing to find the smallest (large) element from the remaining unsorted elements and placing it at the end of the sorted sequence. And so on until all the elements are sorted.

                  Algorithm description

                  Ordering results can be obtained by direct selection sorting of n records through n-1 direct selection sorting. The specific algorithm is described as follows:

                  • Initial state: disordered region is R[1..n], ordered region is empty;
                  • i sort (i=1,2,3... n-1) At the beginning, the current ordered and disordered regions are R[1..i-1] and R(i.. n). The run sort selects the record R[k] with the smallest keyword from the current unordered area and swaps it with the first record R in the unordered area, so that R[1..i] and R[i+1..n) become a new ordered area with 1 more records and a new unordered area with 1 less records, respectively.
                  • n-1 is done. The array is ordered.

                  GIF presentation

                  Selection Sort

                  Code demo

                  js
                  const select = (list: number[]): number[] => {
                     const size = list.length;
                     for (let i = 0; i < size; i++) {
                       let minIndex = i;
                  diff --git a/assets/src_article_sort_shell_index.md.D333S2vN.js b/assets/src_article_sort_shell_index.md.H4IG1J-3.js
                  similarity index 99%
                  rename from assets/src_article_sort_shell_index.md.D333S2vN.js
                  rename to assets/src_article_sort_shell_index.md.H4IG1J-3.js
                  index a2d3e63295..d0d8a1e2fb 100644
                  --- a/assets/src_article_sort_shell_index.md.D333S2vN.js
                  +++ b/assets/src_article_sort_shell_index.md.H4IG1J-3.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/shell.CGEkKxrp.js";import{_ as a,o as n,c as e,a3 as t}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Shell Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/shell/index.md","filePath":"src/article/sort/shell/index.md","lastUpdated":1728828157000}'),l={name:"src/article/sort/shell/index.md"};function h(p,s,k,r,d,o){return n(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Shell Sort

                  Shell was invented in 1959, and the first breakthrough O(n2) sorting algorithm was an improved version of simple insertion sorting. It differs from insertion sort in that it gives preference to more distant elements. Hill sort is also called reduced increment sort.

                  Algorithm description

                  First, the whole record sequence to be sorted is divided into several sub-sequences for direct insertion sorting. The specific algorithm is described as follows:

                  • Select an incremental sequence t1, t2,... tk, wherein ti> tj, tk=1;
                  • According to the number of incremental sequences k, the sequence is sorted by k passes.
                  • For each sequence, according to the corresponding increment ti, the sequence to be sorted is divided into several sub-sequences with length m, and each sub-table is sorted by direct insertion. When the increment factor is only 1, the entire sequence is treated as a table, and the length of the table is the length of the entire sequence.

                  GIF presentation

                  Shell Sort

                  Code implementation

                  js
                  /**
                  +import{_ as i}from"./chunks/shell.CGEkKxrp.js";import{_ as a,o as n,c as e,a3 as t}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Shell Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/shell/index.md","filePath":"src/article/sort/shell/index.md","lastUpdated":1728921295000}'),l={name:"src/article/sort/shell/index.md"};function h(p,s,k,r,d,o){return n(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Shell Sort

                  Shell was invented in 1959, and the first breakthrough O(n2) sorting algorithm was an improved version of simple insertion sorting. It differs from insertion sort in that it gives preference to more distant elements. Hill sort is also called reduced increment sort.

                  Algorithm description

                  First, the whole record sequence to be sorted is divided into several sub-sequences for direct insertion sorting. The specific algorithm is described as follows:

                  • Select an incremental sequence t1, t2,... tk, wherein ti> tj, tk=1;
                  • According to the number of incremental sequences k, the sequence is sorted by k passes.
                  • For each sequence, according to the corresponding increment ti, the sequence to be sorted is divided into several sub-sequences with length m, and each sub-table is sorted by direct insertion. When the increment factor is only 1, the entire sequence is treated as a table, and the length of the table is the length of the entire sequence.

                  GIF presentation

                  Shell Sort

                  Code implementation

                  js
                  /**
                    * @description: Hill sort is an improved version of simple insertion sort. It differs from insertion sort in that it gives preference to more distant elements. Hill sort is also called reduced increment sort.
                    * @param {Array} list
                    * @return {Array}
                  diff --git a/assets/src_article_sort_shell_index.md.D333S2vN.lean.js b/assets/src_article_sort_shell_index.md.H4IG1J-3.lean.js
                  similarity index 99%
                  rename from assets/src_article_sort_shell_index.md.D333S2vN.lean.js
                  rename to assets/src_article_sort_shell_index.md.H4IG1J-3.lean.js
                  index a2d3e63295..d0d8a1e2fb 100644
                  --- a/assets/src_article_sort_shell_index.md.D333S2vN.lean.js
                  +++ b/assets/src_article_sort_shell_index.md.H4IG1J-3.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i}from"./chunks/shell.CGEkKxrp.js";import{_ as a,o as n,c as e,a3 as t}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Shell Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/shell/index.md","filePath":"src/article/sort/shell/index.md","lastUpdated":1728828157000}'),l={name:"src/article/sort/shell/index.md"};function h(p,s,k,r,d,o){return n(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Shell Sort

                  Shell was invented in 1959, and the first breakthrough O(n2) sorting algorithm was an improved version of simple insertion sorting. It differs from insertion sort in that it gives preference to more distant elements. Hill sort is also called reduced increment sort.

                  Algorithm description

                  First, the whole record sequence to be sorted is divided into several sub-sequences for direct insertion sorting. The specific algorithm is described as follows:

                  • Select an incremental sequence t1, t2,... tk, wherein ti> tj, tk=1;
                  • According to the number of incremental sequences k, the sequence is sorted by k passes.
                  • For each sequence, according to the corresponding increment ti, the sequence to be sorted is divided into several sub-sequences with length m, and each sub-table is sorted by direct insertion. When the increment factor is only 1, the entire sequence is treated as a table, and the length of the table is the length of the entire sequence.

                  GIF presentation

                  Shell Sort

                  Code implementation

                  js
                  /**
                  +import{_ as i}from"./chunks/shell.CGEkKxrp.js";import{_ as a,o as n,c as e,a3 as t}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Shell Sort","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/sort/shell/index.md","filePath":"src/article/sort/shell/index.md","lastUpdated":1728921295000}'),l={name:"src/article/sort/shell/index.md"};function h(p,s,k,r,d,o){return n(),e("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  Shell Sort

                  Shell was invented in 1959, and the first breakthrough O(n2) sorting algorithm was an improved version of simple insertion sorting. It differs from insertion sort in that it gives preference to more distant elements. Hill sort is also called reduced increment sort.

                  Algorithm description

                  First, the whole record sequence to be sorted is divided into several sub-sequences for direct insertion sorting. The specific algorithm is described as follows:

                  • Select an incremental sequence t1, t2,... tk, wherein ti> tj, tk=1;
                  • According to the number of incremental sequences k, the sequence is sorted by k passes.
                  • For each sequence, according to the corresponding increment ti, the sequence to be sorted is divided into several sub-sequences with length m, and each sub-table is sorted by direct insertion. When the increment factor is only 1, the entire sequence is treated as a table, and the length of the table is the length of the entire sequence.

                  GIF presentation

                  Shell Sort

                  Code implementation

                  js
                  /**
                    * @description: Hill sort is an improved version of simple insertion sort. It differs from insertion sort in that it gives preference to more distant elements. Hill sort is also called reduced increment sort.
                    * @param {Array} list
                    * @return {Array}
                  diff --git a/assets/src_article_typescript_calculate.md.xkHvMeV2.js b/assets/src_article_typescript_calculate.md.C7yhKz7X.js
                  similarity index 99%
                  rename from assets/src_article_typescript_calculate.md.xkHvMeV2.js
                  rename to assets/src_article_typescript_calculate.md.C7yhKz7X.js
                  index 2bc6db50a7..f3b631efab 100644
                  --- a/assets/src_article_typescript_calculate.md.xkHvMeV2.js
                  +++ b/assets/src_article_typescript_calculate.md.C7yhKz7X.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"数组长度做计数","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/calculate.md","filePath":"src/article/typescript/calculate.md","lastUpdated":1728828157000}'),k={name:"src/article/typescript/calculate.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  数组长度做计数

                  类型系统不是图灵完备,各种逻辑都能写么,但好像没发现数值相关的逻辑。

                  没错,数值相关的逻辑比较绕,被我单独摘了出来,就是这节要讲的内容。

                  这是类型体操的第四个套路:数组长度做计数。

                  TypeScript 类型系统没有加减乘除运算符,怎么做数值运算呢?

                  不知道大家有没有注意到数组类型取 length 就是数值。

                  比如:

                  ts
                  type num1 = [unknown]['length'];
                  +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"数组长度做计数","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/calculate.md","filePath":"src/article/typescript/calculate.md","lastUpdated":1728921295000}'),k={name:"src/article/typescript/calculate.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  数组长度做计数

                  类型系统不是图灵完备,各种逻辑都能写么,但好像没发现数值相关的逻辑。

                  没错,数值相关的逻辑比较绕,被我单独摘了出来,就是这节要讲的内容。

                  这是类型体操的第四个套路:数组长度做计数。

                  TypeScript 类型系统没有加减乘除运算符,怎么做数值运算呢?

                  不知道大家有没有注意到数组类型取 length 就是数值。

                  比如:

                  ts
                  type num1 = [unknown]['length'];
                   // type num1 = 1
                   type num2 = [unknown, unknown]['length'];
                   // type num1 = 2
                  diff --git a/assets/src_article_typescript_calculate.md.xkHvMeV2.lean.js b/assets/src_article_typescript_calculate.md.C7yhKz7X.lean.js
                  similarity index 99%
                  rename from assets/src_article_typescript_calculate.md.xkHvMeV2.lean.js
                  rename to assets/src_article_typescript_calculate.md.C7yhKz7X.lean.js
                  index 2bc6db50a7..f3b631efab 100644
                  --- a/assets/src_article_typescript_calculate.md.xkHvMeV2.lean.js
                  +++ b/assets/src_article_typescript_calculate.md.C7yhKz7X.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"数组长度做计数","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/calculate.md","filePath":"src/article/typescript/calculate.md","lastUpdated":1728828157000}'),k={name:"src/article/typescript/calculate.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  数组长度做计数

                  类型系统不是图灵完备,各种逻辑都能写么,但好像没发现数值相关的逻辑。

                  没错,数值相关的逻辑比较绕,被我单独摘了出来,就是这节要讲的内容。

                  这是类型体操的第四个套路:数组长度做计数。

                  TypeScript 类型系统没有加减乘除运算符,怎么做数值运算呢?

                  不知道大家有没有注意到数组类型取 length 就是数值。

                  比如:

                  ts
                  type num1 = [unknown]['length'];
                  +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"数组长度做计数","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/calculate.md","filePath":"src/article/typescript/calculate.md","lastUpdated":1728921295000}'),k={name:"src/article/typescript/calculate.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  数组长度做计数

                  类型系统不是图灵完备,各种逻辑都能写么,但好像没发现数值相关的逻辑。

                  没错,数值相关的逻辑比较绕,被我单独摘了出来,就是这节要讲的内容。

                  这是类型体操的第四个套路:数组长度做计数。

                  TypeScript 类型系统没有加减乘除运算符,怎么做数值运算呢?

                  不知道大家有没有注意到数组类型取 length 就是数值。

                  比如:

                  ts
                  type num1 = [unknown]['length'];
                   // type num1 = 1
                   type num2 = [unknown, unknown]['length'];
                   // type num1 = 2
                  diff --git a/assets/src_article_typescript_index.md.DQFvubag.js b/assets/src_article_typescript_index.md.DeH7pgUe.js
                  similarity index 99%
                  rename from assets/src_article_typescript_index.md.DQFvubag.js
                  rename to assets/src_article_typescript_index.md.DeH7pgUe.js
                  index 0c4c9713a0..e6b63230a9 100644
                  --- a/assets/src_article_typescript_index.md.DQFvubag.js
                  +++ b/assets/src_article_typescript_index.md.DeH7pgUe.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 的类型系统","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/index.md","filePath":"src/article/typescript/index.md","lastUpdated":1728828157000}'),k={name:"src/article/typescript/index.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  TypeScript 的类型系统

                  一。类型是什么

                  类型具体点来说就是指 number、boolean、string 等基础类型和 Object、Function 等复合类型,它们是编程语言提供的对不同内容的抽象:

                  • 不同类型变量占据的内存大小不同: boolean 类型的变量会分配 4 个字节的内存,而 number 类型的变量则会分配 8 个字节的内存,给变量声明了不同的类型就代表了会占据不同的内存空间。

                  • 不同类型变量可做的操作不同: number 类型可以做加减乘除等运算,boolean 就不可以,复合类型中不同类型的对象可用的方法不同,比如 Date 和 RegExp,变量的类型不同代表可以对该变量做的操作就不同。

                  有了类型,那我们的操作必须和类型相匹配,否则就会报错,这就是类型检查。

                  如果能保证对某种类型只做该类型允许的操作,这就叫做类型安全。

                  类型检查可以在运行时做,也可以运行之前的编译期做。这是两种不同的类型,前者叫做动态类型检查,后者叫做静态类型检查。

                  两种类型检查各有优缺点。动态类型检查 在源码中不保留类型信息,对某个变量赋什么值、做什么操作都是允许的,写代码很灵活。但这也埋下了类型不安全的隐患,比如对 string 做了乘除,对 Date 对象调用了 exec 方法,这些都是运行时才能检查出来的错误。

                  其中,最常见的错误应该是“null is not an object”、“undefined is not a function”之类的了,写代码时没发现类型不匹配,到了运行的时候才发现,就会有很多这种报错。

                  所以,动态类型虽然代码写起来简单,但代码中很容易藏着一些类型不匹配的隐患。

                  静态类型检查则是在源码中保留类型信息,声明变量要指定类型,对变量做的操作要和类型匹配,会有专门的编译器在编译期间做检查。

                  静态类型给写代码增加了一些难度,因为你除了要考虑代码要表达的逻辑之外,还要考虑类型逻辑:变量是什么类型的、是不是匹配、要不要做类型转换等。

                  不过,静态类型也消除了类型不安全的隐患,因为在编译期间就做了类型检查,就不会出现对 string 做了乘除,调用了 Date 的 exec 方法这类问题。

                  所以,静态类型虽然代码写起来要考虑的问题多一些,会复杂一些,但是却消除了代码中潜藏类型不安全问题的可能。

                  知道了动态类型检查和静态类型检查的区别,我们自然可以得出这样的结论:

                  动态类型只适合简单的场景,对于大项目却不太合适,因为代码中可能藏着的隐患太多了,万一线上报一个类型不匹配的错误,那可能就是大问题。

                  而静态类型虽然会增加写代码的成本,但是却能更好的保证代码的健壮性,减少 Bug 率。

                  所以,大型项目注定会用静态类型语言开发。

                  二。类型系统的分类

                  1.简单的类型系统

                  变量、函数、类等都可以声明类型,编译器会基于声明的类型做类型检查,类型不匹配时会报错。

                  这是最基础的类型系统,能保证类型安全,但有些死板。

                  比如一个 add 函数既可以做整数加法、又可以做浮点数加法,却需要声明两个函数:

                  c
                  int add(int a, int b) {
                  +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 的类型系统","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/index.md","filePath":"src/article/typescript/index.md","lastUpdated":1728921295000}'),k={name:"src/article/typescript/index.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  TypeScript 的类型系统

                  一。类型是什么

                  类型具体点来说就是指 number、boolean、string 等基础类型和 Object、Function 等复合类型,它们是编程语言提供的对不同内容的抽象:

                  • 不同类型变量占据的内存大小不同: boolean 类型的变量会分配 4 个字节的内存,而 number 类型的变量则会分配 8 个字节的内存,给变量声明了不同的类型就代表了会占据不同的内存空间。

                  • 不同类型变量可做的操作不同: number 类型可以做加减乘除等运算,boolean 就不可以,复合类型中不同类型的对象可用的方法不同,比如 Date 和 RegExp,变量的类型不同代表可以对该变量做的操作就不同。

                  有了类型,那我们的操作必须和类型相匹配,否则就会报错,这就是类型检查。

                  如果能保证对某种类型只做该类型允许的操作,这就叫做类型安全。

                  类型检查可以在运行时做,也可以运行之前的编译期做。这是两种不同的类型,前者叫做动态类型检查,后者叫做静态类型检查。

                  两种类型检查各有优缺点。动态类型检查 在源码中不保留类型信息,对某个变量赋什么值、做什么操作都是允许的,写代码很灵活。但这也埋下了类型不安全的隐患,比如对 string 做了乘除,对 Date 对象调用了 exec 方法,这些都是运行时才能检查出来的错误。

                  其中,最常见的错误应该是“null is not an object”、“undefined is not a function”之类的了,写代码时没发现类型不匹配,到了运行的时候才发现,就会有很多这种报错。

                  所以,动态类型虽然代码写起来简单,但代码中很容易藏着一些类型不匹配的隐患。

                  静态类型检查则是在源码中保留类型信息,声明变量要指定类型,对变量做的操作要和类型匹配,会有专门的编译器在编译期间做检查。

                  静态类型给写代码增加了一些难度,因为你除了要考虑代码要表达的逻辑之外,还要考虑类型逻辑:变量是什么类型的、是不是匹配、要不要做类型转换等。

                  不过,静态类型也消除了类型不安全的隐患,因为在编译期间就做了类型检查,就不会出现对 string 做了乘除,调用了 Date 的 exec 方法这类问题。

                  所以,静态类型虽然代码写起来要考虑的问题多一些,会复杂一些,但是却消除了代码中潜藏类型不安全问题的可能。

                  知道了动态类型检查和静态类型检查的区别,我们自然可以得出这样的结论:

                  动态类型只适合简单的场景,对于大项目却不太合适,因为代码中可能藏着的隐患太多了,万一线上报一个类型不匹配的错误,那可能就是大问题。

                  而静态类型虽然会增加写代码的成本,但是却能更好的保证代码的健壮性,减少 Bug 率。

                  所以,大型项目注定会用静态类型语言开发。

                  二。类型系统的分类

                  1.简单的类型系统

                  变量、函数、类等都可以声明类型,编译器会基于声明的类型做类型检查,类型不匹配时会报错。

                  这是最基础的类型系统,能保证类型安全,但有些死板。

                  比如一个 add 函数既可以做整数加法、又可以做浮点数加法,却需要声明两个函数:

                  c
                  int add(int a, int b) {
                       return a + b;
                   }
                   
                  diff --git a/assets/src_article_typescript_index.md.DQFvubag.lean.js b/assets/src_article_typescript_index.md.DeH7pgUe.lean.js
                  similarity index 99%
                  rename from assets/src_article_typescript_index.md.DQFvubag.lean.js
                  rename to assets/src_article_typescript_index.md.DeH7pgUe.lean.js
                  index 0c4c9713a0..e6b63230a9 100644
                  --- a/assets/src_article_typescript_index.md.DQFvubag.lean.js
                  +++ b/assets/src_article_typescript_index.md.DeH7pgUe.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 的类型系统","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/index.md","filePath":"src/article/typescript/index.md","lastUpdated":1728828157000}'),k={name:"src/article/typescript/index.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  TypeScript 的类型系统

                  一。类型是什么

                  类型具体点来说就是指 number、boolean、string 等基础类型和 Object、Function 等复合类型,它们是编程语言提供的对不同内容的抽象:

                  • 不同类型变量占据的内存大小不同: boolean 类型的变量会分配 4 个字节的内存,而 number 类型的变量则会分配 8 个字节的内存,给变量声明了不同的类型就代表了会占据不同的内存空间。

                  • 不同类型变量可做的操作不同: number 类型可以做加减乘除等运算,boolean 就不可以,复合类型中不同类型的对象可用的方法不同,比如 Date 和 RegExp,变量的类型不同代表可以对该变量做的操作就不同。

                  有了类型,那我们的操作必须和类型相匹配,否则就会报错,这就是类型检查。

                  如果能保证对某种类型只做该类型允许的操作,这就叫做类型安全。

                  类型检查可以在运行时做,也可以运行之前的编译期做。这是两种不同的类型,前者叫做动态类型检查,后者叫做静态类型检查。

                  两种类型检查各有优缺点。动态类型检查 在源码中不保留类型信息,对某个变量赋什么值、做什么操作都是允许的,写代码很灵活。但这也埋下了类型不安全的隐患,比如对 string 做了乘除,对 Date 对象调用了 exec 方法,这些都是运行时才能检查出来的错误。

                  其中,最常见的错误应该是“null is not an object”、“undefined is not a function”之类的了,写代码时没发现类型不匹配,到了运行的时候才发现,就会有很多这种报错。

                  所以,动态类型虽然代码写起来简单,但代码中很容易藏着一些类型不匹配的隐患。

                  静态类型检查则是在源码中保留类型信息,声明变量要指定类型,对变量做的操作要和类型匹配,会有专门的编译器在编译期间做检查。

                  静态类型给写代码增加了一些难度,因为你除了要考虑代码要表达的逻辑之外,还要考虑类型逻辑:变量是什么类型的、是不是匹配、要不要做类型转换等。

                  不过,静态类型也消除了类型不安全的隐患,因为在编译期间就做了类型检查,就不会出现对 string 做了乘除,调用了 Date 的 exec 方法这类问题。

                  所以,静态类型虽然代码写起来要考虑的问题多一些,会复杂一些,但是却消除了代码中潜藏类型不安全问题的可能。

                  知道了动态类型检查和静态类型检查的区别,我们自然可以得出这样的结论:

                  动态类型只适合简单的场景,对于大项目却不太合适,因为代码中可能藏着的隐患太多了,万一线上报一个类型不匹配的错误,那可能就是大问题。

                  而静态类型虽然会增加写代码的成本,但是却能更好的保证代码的健壮性,减少 Bug 率。

                  所以,大型项目注定会用静态类型语言开发。

                  二。类型系统的分类

                  1.简单的类型系统

                  变量、函数、类等都可以声明类型,编译器会基于声明的类型做类型检查,类型不匹配时会报错。

                  这是最基础的类型系统,能保证类型安全,但有些死板。

                  比如一个 add 函数既可以做整数加法、又可以做浮点数加法,却需要声明两个函数:

                  c
                  int add(int a, int b) {
                  +import{_ as i,o as a,c as h,a3 as n}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 的类型系统","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/index.md","filePath":"src/article/typescript/index.md","lastUpdated":1728921295000}'),k={name:"src/article/typescript/index.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  TypeScript 的类型系统

                  一。类型是什么

                  类型具体点来说就是指 number、boolean、string 等基础类型和 Object、Function 等复合类型,它们是编程语言提供的对不同内容的抽象:

                  • 不同类型变量占据的内存大小不同: boolean 类型的变量会分配 4 个字节的内存,而 number 类型的变量则会分配 8 个字节的内存,给变量声明了不同的类型就代表了会占据不同的内存空间。

                  • 不同类型变量可做的操作不同: number 类型可以做加减乘除等运算,boolean 就不可以,复合类型中不同类型的对象可用的方法不同,比如 Date 和 RegExp,变量的类型不同代表可以对该变量做的操作就不同。

                  有了类型,那我们的操作必须和类型相匹配,否则就会报错,这就是类型检查。

                  如果能保证对某种类型只做该类型允许的操作,这就叫做类型安全。

                  类型检查可以在运行时做,也可以运行之前的编译期做。这是两种不同的类型,前者叫做动态类型检查,后者叫做静态类型检查。

                  两种类型检查各有优缺点。动态类型检查 在源码中不保留类型信息,对某个变量赋什么值、做什么操作都是允许的,写代码很灵活。但这也埋下了类型不安全的隐患,比如对 string 做了乘除,对 Date 对象调用了 exec 方法,这些都是运行时才能检查出来的错误。

                  其中,最常见的错误应该是“null is not an object”、“undefined is not a function”之类的了,写代码时没发现类型不匹配,到了运行的时候才发现,就会有很多这种报错。

                  所以,动态类型虽然代码写起来简单,但代码中很容易藏着一些类型不匹配的隐患。

                  静态类型检查则是在源码中保留类型信息,声明变量要指定类型,对变量做的操作要和类型匹配,会有专门的编译器在编译期间做检查。

                  静态类型给写代码增加了一些难度,因为你除了要考虑代码要表达的逻辑之外,还要考虑类型逻辑:变量是什么类型的、是不是匹配、要不要做类型转换等。

                  不过,静态类型也消除了类型不安全的隐患,因为在编译期间就做了类型检查,就不会出现对 string 做了乘除,调用了 Date 的 exec 方法这类问题。

                  所以,静态类型虽然代码写起来要考虑的问题多一些,会复杂一些,但是却消除了代码中潜藏类型不安全问题的可能。

                  知道了动态类型检查和静态类型检查的区别,我们自然可以得出这样的结论:

                  动态类型只适合简单的场景,对于大项目却不太合适,因为代码中可能藏着的隐患太多了,万一线上报一个类型不匹配的错误,那可能就是大问题。

                  而静态类型虽然会增加写代码的成本,但是却能更好的保证代码的健壮性,减少 Bug 率。

                  所以,大型项目注定会用静态类型语言开发。

                  二。类型系统的分类

                  1.简单的类型系统

                  变量、函数、类等都可以声明类型,编译器会基于声明的类型做类型检查,类型不匹配时会报错。

                  这是最基础的类型系统,能保证类型安全,但有些死板。

                  比如一个 add 函数既可以做整数加法、又可以做浮点数加法,却需要声明两个函数:

                  c
                  int add(int a, int b) {
                       return a + b;
                   }
                   
                  diff --git a/assets/src_article_typescript_pattern.md.ChySx5n3.js b/assets/src_article_typescript_pattern.md.3sU5fRCA.js
                  similarity index 99%
                  rename from assets/src_article_typescript_pattern.md.ChySx5n3.js
                  rename to assets/src_article_typescript_pattern.md.3sU5fRCA.js
                  index 3feac9a72f..649f09cded 100644
                  --- a/assets/src_article_typescript_pattern.md.ChySx5n3.js
                  +++ b/assets/src_article_typescript_pattern.md.3sU5fRCA.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"模式匹配提取","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/pattern.md","filePath":"src/article/typescript/pattern.md","lastUpdated":1728828157000}'),n={name:"src/article/typescript/pattern.md"};function k(p,s,l,e,r,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  模式匹配提取

                  字符串可以和正则做模式匹配,找到匹配的部分,提取子组,之后可以用 1,2 等引用匹配的子组。

                  ts
                  'abc'.replace(/a(b)c/, '$1,$1,$1');
                  +import{_ as i,o as a,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"模式匹配提取","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/pattern.md","filePath":"src/article/typescript/pattern.md","lastUpdated":1728921295000}'),n={name:"src/article/typescript/pattern.md"};function k(p,s,l,e,r,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  模式匹配提取

                  字符串可以和正则做模式匹配,找到匹配的部分,提取子组,之后可以用 1,2 等引用匹配的子组。

                  ts
                  'abc'.replace(/a(b)c/, '$1,$1,$1');
                   // 'b,b,b'

                  Typescript 的类型也同样可以做模式匹配。

                  比如这样一个 Promise 类型:

                  ts
                  type p = Promise<'value'>;

                  我们想提取 value 的类型,可以这样做:

                  ts
                  type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

                  通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

                  ts
                  // type GetValueResult = 'value'
                   type GetValueResult = GetValueType<Promise<'value'>>;

                  这就是 Typescript 类型的模式匹配:

                  Typescript 类型的模式匹配是通过 extends 对类型参数做匹配,结果保存到通过 infer 声明的局部类型变量里,如果匹配就能从该局部变量里拿到提取出的类型。

                  这个模式匹配的套路有多有用呢?我们来看下在数组、字符串、函数、构造器等类型里的应用。

                  1.数组类型

                  提取第一个元素

                  数组类型想提取第一个元素的类型怎么做呢?

                  ts
                  type arr = [1, 2, 3];

                  用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

                  ts
                  type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never;

                  类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unkown 也就是可以是任何值。

                  any 和 unknown 的区别:any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

                  对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never;
                   type GetFirstValue = GetFirst<[1, 2, 3]>;
                  diff --git a/assets/src_article_typescript_pattern.md.ChySx5n3.lean.js b/assets/src_article_typescript_pattern.md.3sU5fRCA.lean.js
                  similarity index 99%
                  rename from assets/src_article_typescript_pattern.md.ChySx5n3.lean.js
                  rename to assets/src_article_typescript_pattern.md.3sU5fRCA.lean.js
                  index 3feac9a72f..649f09cded 100644
                  --- a/assets/src_article_typescript_pattern.md.ChySx5n3.lean.js
                  +++ b/assets/src_article_typescript_pattern.md.3sU5fRCA.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"模式匹配提取","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/pattern.md","filePath":"src/article/typescript/pattern.md","lastUpdated":1728828157000}'),n={name:"src/article/typescript/pattern.md"};function k(p,s,l,e,r,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  模式匹配提取

                  字符串可以和正则做模式匹配,找到匹配的部分,提取子组,之后可以用 1,2 等引用匹配的子组。

                  ts
                  'abc'.replace(/a(b)c/, '$1,$1,$1');
                  +import{_ as i,o as a,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"模式匹配提取","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/pattern.md","filePath":"src/article/typescript/pattern.md","lastUpdated":1728921295000}'),n={name:"src/article/typescript/pattern.md"};function k(p,s,l,e,r,d){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  模式匹配提取

                  字符串可以和正则做模式匹配,找到匹配的部分,提取子组,之后可以用 1,2 等引用匹配的子组。

                  ts
                  'abc'.replace(/a(b)c/, '$1,$1,$1');
                   // 'b,b,b'

                  Typescript 的类型也同样可以做模式匹配。

                  比如这样一个 Promise 类型:

                  ts
                  type p = Promise<'value'>;

                  我们想提取 value 的类型,可以这样做:

                  ts
                  type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

                  通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

                  ts
                  // type GetValueResult = 'value'
                   type GetValueResult = GetValueType<Promise<'value'>>;

                  这就是 Typescript 类型的模式匹配:

                  Typescript 类型的模式匹配是通过 extends 对类型参数做匹配,结果保存到通过 infer 声明的局部类型变量里,如果匹配就能从该局部变量里拿到提取出的类型。

                  这个模式匹配的套路有多有用呢?我们来看下在数组、字符串、函数、构造器等类型里的应用。

                  1.数组类型

                  提取第一个元素

                  数组类型想提取第一个元素的类型怎么做呢?

                  ts
                  type arr = [1, 2, 3];

                  用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

                  ts
                  type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never;

                  类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unkown 也就是可以是任何值。

                  any 和 unknown 的区别:any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

                  对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type GetFirst<Arr extends unknown[]> = Arr extends [infer First, ...unknown[]] ? First : never;
                   type GetFirstValue = GetFirst<[1, 2, 3]>;
                  diff --git a/assets/src_article_typescript_reconstruction.md.CohgiGIS.js b/assets/src_article_typescript_reconstruction.md.CSOt7yMn.js
                  similarity index 99%
                  rename from assets/src_article_typescript_reconstruction.md.CohgiGIS.js
                  rename to assets/src_article_typescript_reconstruction.md.CSOt7yMn.js
                  index 4afd8d4bda..45a2b7c96d 100644
                  --- a/assets/src_article_typescript_reconstruction.md.CohgiGIS.js
                  +++ b/assets/src_article_typescript_reconstruction.md.CSOt7yMn.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"重新构造做变换","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/reconstruction.md","filePath":"src/article/typescript/reconstruction.md","lastUpdated":1728828157000}'),k={name:"src/article/typescript/reconstruction.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

                  重新构造做变换

                  类型编程主要的目的就是对类型做各种转换,那么如何对类型做修改呢?

                  TypeScript 类型系统支持 3 种可以声明任意类型的变量:type、infer、类型参数。

                  type 叫做类型别名,其实就是声明一个变量存储某个类型:

                  ts
                  type ttt = Promise<number>;

                  infer 用于类型的提取,然后存到一个变量里,相当于局部变量:

                  ts
                  type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

                  类型参数用于接受具体的类型,在类型运算中也相当于局部变量:

                  ts
                  type isTwo<T> = T extends 2 ? true : false;

                  但是,严格来说这三种也都不叫变量,因为它们不能被重新赋值。

                  TypeScript 设计可以做类型编程的类型系统的目的就是为了产生各种复杂的类型,那不能修改怎么产生新类型呢?

                  答案是重新构造。

                  这就涉及到了第二个类型体操套路:重新构造做变换。

                  重新构造

                  TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。

                  数组、字符串、函数等类型的重新构造比较简单。

                  索引类型,也就是多个元素的聚合类型的重新构造复杂一些,涉及到了映射类型的语法。

                  我们先从简单的开始:

                  数组类型的重新构造

                  Push

                  有这样一个元组类型:

                  ts
                  type tuple = [1, 2, 3];

                  我想给这个元组类型再添加一些类型,怎么做呢?

                  TypeScript 类型变量不支持修改,我们可以构造一个新的元组类型:

                  ts
                  type Push<Arr extends unknown[], Ele> = [...Arr, Ele];

                  类型参数 Arr 是要修改的数组/元组类型,元素的类型任意,也就是 unknown。

                  类型参数 Ele 是添加的元素的类型。

                  返回的是用 Arr 已有的元素加上 Ele 构造的新的元组类型。

                  ts
                  type PushResult = Push<[1, 2, 3], 4>;
                  +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"重新构造做变换","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/reconstruction.md","filePath":"src/article/typescript/reconstruction.md","lastUpdated":1728921295000}'),k={name:"src/article/typescript/reconstruction.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

                  重新构造做变换

                  类型编程主要的目的就是对类型做各种转换,那么如何对类型做修改呢?

                  TypeScript 类型系统支持 3 种可以声明任意类型的变量:type、infer、类型参数。

                  type 叫做类型别名,其实就是声明一个变量存储某个类型:

                  ts
                  type ttt = Promise<number>;

                  infer 用于类型的提取,然后存到一个变量里,相当于局部变量:

                  ts
                  type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

                  类型参数用于接受具体的类型,在类型运算中也相当于局部变量:

                  ts
                  type isTwo<T> = T extends 2 ? true : false;

                  但是,严格来说这三种也都不叫变量,因为它们不能被重新赋值。

                  TypeScript 设计可以做类型编程的类型系统的目的就是为了产生各种复杂的类型,那不能修改怎么产生新类型呢?

                  答案是重新构造。

                  这就涉及到了第二个类型体操套路:重新构造做变换。

                  重新构造

                  TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。

                  数组、字符串、函数等类型的重新构造比较简单。

                  索引类型,也就是多个元素的聚合类型的重新构造复杂一些,涉及到了映射类型的语法。

                  我们先从简单的开始:

                  数组类型的重新构造

                  Push

                  有这样一个元组类型:

                  ts
                  type tuple = [1, 2, 3];

                  我想给这个元组类型再添加一些类型,怎么做呢?

                  TypeScript 类型变量不支持修改,我们可以构造一个新的元组类型:

                  ts
                  type Push<Arr extends unknown[], Ele> = [...Arr, Ele];

                  类型参数 Arr 是要修改的数组/元组类型,元素的类型任意,也就是 unknown。

                  类型参数 Ele 是添加的元素的类型。

                  返回的是用 Arr 已有的元素加上 Ele 构造的新的元组类型。

                  ts
                  type PushResult = Push<[1, 2, 3], 4>;
                   // type PushResult = [1,2,3,4]

                  这就是数组/元组的重新构造。

                  数组和元组的区别:数组类型是指任意多个同一类型的元素构成的,比如 number[]Array<number>,而元组则是数量固定,类型可以不同的元素构成的,比如 [1, true, 'name']

                  Unshift

                  可以在后面添加,同样也可以在前面添加:

                  ts
                  type Unshift<Arr extends unknown[], Ele> = [Ele, ...Arr];

                  Zip

                  有这样两个元组:

                  ts
                  type tuple1 = [1, 2];
                   type tuple2 = ['name', 'value'];

                  我们想把它们合并成这样的元组:

                  ts
                  type tuple = [[1, 'name'], [2, 'value']];

                  思路很容易想到,提取元组中的两个元素,构造成新的元组:

                  ts
                  type Zip<One extends [unknown, unknown], Other extends [unknown, unknown]> = One extends [
                     infer OneFirst,
                  diff --git a/assets/src_article_typescript_reconstruction.md.CohgiGIS.lean.js b/assets/src_article_typescript_reconstruction.md.CSOt7yMn.lean.js
                  similarity index 99%
                  rename from assets/src_article_typescript_reconstruction.md.CohgiGIS.lean.js
                  rename to assets/src_article_typescript_reconstruction.md.CSOt7yMn.lean.js
                  index 4afd8d4bda..45a2b7c96d 100644
                  --- a/assets/src_article_typescript_reconstruction.md.CohgiGIS.lean.js
                  +++ b/assets/src_article_typescript_reconstruction.md.CSOt7yMn.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"重新构造做变换","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/reconstruction.md","filePath":"src/article/typescript/reconstruction.md","lastUpdated":1728828157000}'),k={name:"src/article/typescript/reconstruction.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

                  重新构造做变换

                  类型编程主要的目的就是对类型做各种转换,那么如何对类型做修改呢?

                  TypeScript 类型系统支持 3 种可以声明任意类型的变量:type、infer、类型参数。

                  type 叫做类型别名,其实就是声明一个变量存储某个类型:

                  ts
                  type ttt = Promise<number>;

                  infer 用于类型的提取,然后存到一个变量里,相当于局部变量:

                  ts
                  type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

                  类型参数用于接受具体的类型,在类型运算中也相当于局部变量:

                  ts
                  type isTwo<T> = T extends 2 ? true : false;

                  但是,严格来说这三种也都不叫变量,因为它们不能被重新赋值。

                  TypeScript 设计可以做类型编程的类型系统的目的就是为了产生各种复杂的类型,那不能修改怎么产生新类型呢?

                  答案是重新构造。

                  这就涉及到了第二个类型体操套路:重新构造做变换。

                  重新构造

                  TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。

                  数组、字符串、函数等类型的重新构造比较简单。

                  索引类型,也就是多个元素的聚合类型的重新构造复杂一些,涉及到了映射类型的语法。

                  我们先从简单的开始:

                  数组类型的重新构造

                  Push

                  有这样一个元组类型:

                  ts
                  type tuple = [1, 2, 3];

                  我想给这个元组类型再添加一些类型,怎么做呢?

                  TypeScript 类型变量不支持修改,我们可以构造一个新的元组类型:

                  ts
                  type Push<Arr extends unknown[], Ele> = [...Arr, Ele];

                  类型参数 Arr 是要修改的数组/元组类型,元素的类型任意,也就是 unknown。

                  类型参数 Ele 是添加的元素的类型。

                  返回的是用 Arr 已有的元素加上 Ele 构造的新的元组类型。

                  ts
                  type PushResult = Push<[1, 2, 3], 4>;
                  +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"重新构造做变换","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/reconstruction.md","filePath":"src/article/typescript/reconstruction.md","lastUpdated":1728921295000}'),k={name:"src/article/typescript/reconstruction.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

                  重新构造做变换

                  类型编程主要的目的就是对类型做各种转换,那么如何对类型做修改呢?

                  TypeScript 类型系统支持 3 种可以声明任意类型的变量:type、infer、类型参数。

                  type 叫做类型别名,其实就是声明一个变量存储某个类型:

                  ts
                  type ttt = Promise<number>;

                  infer 用于类型的提取,然后存到一个变量里,相当于局部变量:

                  ts
                  type GetValueType<P> = P extends Promise<infer Value> ? Value : never;

                  类型参数用于接受具体的类型,在类型运算中也相当于局部变量:

                  ts
                  type isTwo<T> = T extends 2 ? true : false;

                  但是,严格来说这三种也都不叫变量,因为它们不能被重新赋值。

                  TypeScript 设计可以做类型编程的类型系统的目的就是为了产生各种复杂的类型,那不能修改怎么产生新类型呢?

                  答案是重新构造。

                  这就涉及到了第二个类型体操套路:重新构造做变换。

                  重新构造

                  TypeScript 的 type、infer、类型参数声明的变量都不能修改,想对类型做各种变换产生新的类型就需要重新构造。

                  数组、字符串、函数等类型的重新构造比较简单。

                  索引类型,也就是多个元素的聚合类型的重新构造复杂一些,涉及到了映射类型的语法。

                  我们先从简单的开始:

                  数组类型的重新构造

                  Push

                  有这样一个元组类型:

                  ts
                  type tuple = [1, 2, 3];

                  我想给这个元组类型再添加一些类型,怎么做呢?

                  TypeScript 类型变量不支持修改,我们可以构造一个新的元组类型:

                  ts
                  type Push<Arr extends unknown[], Ele> = [...Arr, Ele];

                  类型参数 Arr 是要修改的数组/元组类型,元素的类型任意,也就是 unknown。

                  类型参数 Ele 是添加的元素的类型。

                  返回的是用 Arr 已有的元素加上 Ele 构造的新的元组类型。

                  ts
                  type PushResult = Push<[1, 2, 3], 4>;
                   // type PushResult = [1,2,3,4]

                  这就是数组/元组的重新构造。

                  数组和元组的区别:数组类型是指任意多个同一类型的元素构成的,比如 number[]Array<number>,而元组则是数量固定,类型可以不同的元素构成的,比如 [1, true, 'name']

                  Unshift

                  可以在后面添加,同样也可以在前面添加:

                  ts
                  type Unshift<Arr extends unknown[], Ele> = [Ele, ...Arr];

                  Zip

                  有这样两个元组:

                  ts
                  type tuple1 = [1, 2];
                   type tuple2 = ['name', 'value'];

                  我们想把它们合并成这样的元组:

                  ts
                  type tuple = [[1, 'name'], [2, 'value']];

                  思路很容易想到,提取元组中的两个元素,构造成新的元组:

                  ts
                  type Zip<One extends [unknown, unknown], Other extends [unknown, unknown]> = One extends [
                     infer OneFirst,
                  diff --git a/assets/src_article_typescript_recursion.md.PrJfeezf.js b/assets/src_article_typescript_recursion.md.BD02XaoF.js
                  similarity index 99%
                  rename from assets/src_article_typescript_recursion.md.PrJfeezf.js
                  rename to assets/src_article_typescript_recursion.md.BD02XaoF.js
                  index 69704ed98e..df47e8f829 100644
                  --- a/assets/src_article_typescript_recursion.md.PrJfeezf.js
                  +++ b/assets/src_article_typescript_recursion.md.BD02XaoF.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"递归复用","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/recursion.md","filePath":"src/article/typescript/recursion.md","lastUpdated":1728828157000}'),n={name:"src/article/typescript/recursion.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

                  递归复用

                  递归是把问题分解为一系列相似的小问题,通过函数不断调用自身来解决这一个个小问题,直到满足结束条件,就完成了问题的求解。

                  TypeScript 的高级类型支持类型参数,可以做各种类型运算逻辑,返回新的类型,和函数调用是对应的,自然也支持递归。

                  TypeScript 类型系统不支持循环,但支持递归。当处理数量(个数、长度、层数)不固定的类型的时候,可以只处理一个类型,然后递归的调用自身处理下一个类型,直到结束条件也就是所有的类型都处理完了,就完成了不确定数量的类型编程,达到循环的效果。

                  既然提到了数组、字符串、对象等类型,那么我们就来看一下这些类型的递归案例吧。

                  Promise 的递归复用

                  DeepPromiseValueType

                  先用 Promise 热热身,实现一个提取不确定层数的 Promise 中的 value 类型的高级类型。

                  ts
                  type ttt = Promise<Promise<Promise<Record<string, any>>>>;

                  这里是 3 层 Promise,value 类型是索引类型。

                  数量不确定,一涉及到这个就要想到用递归来做,每次只处理一层的提取,然后剩下的到下次递归做,直到结束条件。

                  所以高级类型是这样的:

                  ts
                  type DeepPromiseValueType<P extends Promise<unknown>> =
                  +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"递归复用","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/recursion.md","filePath":"src/article/typescript/recursion.md","lastUpdated":1728921295000}'),n={name:"src/article/typescript/recursion.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

                  递归复用

                  递归是把问题分解为一系列相似的小问题,通过函数不断调用自身来解决这一个个小问题,直到满足结束条件,就完成了问题的求解。

                  TypeScript 的高级类型支持类型参数,可以做各种类型运算逻辑,返回新的类型,和函数调用是对应的,自然也支持递归。

                  TypeScript 类型系统不支持循环,但支持递归。当处理数量(个数、长度、层数)不固定的类型的时候,可以只处理一个类型,然后递归的调用自身处理下一个类型,直到结束条件也就是所有的类型都处理完了,就完成了不确定数量的类型编程,达到循环的效果。

                  既然提到了数组、字符串、对象等类型,那么我们就来看一下这些类型的递归案例吧。

                  Promise 的递归复用

                  DeepPromiseValueType

                  先用 Promise 热热身,实现一个提取不确定层数的 Promise 中的 value 类型的高级类型。

                  ts
                  type ttt = Promise<Promise<Promise<Record<string, any>>>>;

                  这里是 3 层 Promise,value 类型是索引类型。

                  数量不确定,一涉及到这个就要想到用递归来做,每次只处理一层的提取,然后剩下的到下次递归做,直到结束条件。

                  所以高级类型是这样的:

                  ts
                  type DeepPromiseValueType<P extends Promise<unknown>> =
                     P extends Promise<infer ValueType>
                       ? ValueType extends Promise<unknown>
                         ? DeepPromiseValueType<ValueType>
                  diff --git a/assets/src_article_typescript_recursion.md.PrJfeezf.lean.js b/assets/src_article_typescript_recursion.md.BD02XaoF.lean.js
                  similarity index 99%
                  rename from assets/src_article_typescript_recursion.md.PrJfeezf.lean.js
                  rename to assets/src_article_typescript_recursion.md.BD02XaoF.lean.js
                  index 69704ed98e..df47e8f829 100644
                  --- a/assets/src_article_typescript_recursion.md.PrJfeezf.lean.js
                  +++ b/assets/src_article_typescript_recursion.md.BD02XaoF.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"递归复用","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/recursion.md","filePath":"src/article/typescript/recursion.md","lastUpdated":1728828157000}'),n={name:"src/article/typescript/recursion.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

                  递归复用

                  递归是把问题分解为一系列相似的小问题,通过函数不断调用自身来解决这一个个小问题,直到满足结束条件,就完成了问题的求解。

                  TypeScript 的高级类型支持类型参数,可以做各种类型运算逻辑,返回新的类型,和函数调用是对应的,自然也支持递归。

                  TypeScript 类型系统不支持循环,但支持递归。当处理数量(个数、长度、层数)不固定的类型的时候,可以只处理一个类型,然后递归的调用自身处理下一个类型,直到结束条件也就是所有的类型都处理完了,就完成了不确定数量的类型编程,达到循环的效果。

                  既然提到了数组、字符串、对象等类型,那么我们就来看一下这些类型的递归案例吧。

                  Promise 的递归复用

                  DeepPromiseValueType

                  先用 Promise 热热身,实现一个提取不确定层数的 Promise 中的 value 类型的高级类型。

                  ts
                  type ttt = Promise<Promise<Promise<Record<string, any>>>>;

                  这里是 3 层 Promise,value 类型是索引类型。

                  数量不确定,一涉及到这个就要想到用递归来做,每次只处理一层的提取,然后剩下的到下次递归做,直到结束条件。

                  所以高级类型是这样的:

                  ts
                  type DeepPromiseValueType<P extends Promise<unknown>> =
                  +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"递归复用","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/recursion.md","filePath":"src/article/typescript/recursion.md","lastUpdated":1728921295000}'),n={name:"src/article/typescript/recursion.md"};function t(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

                  递归复用

                  递归是把问题分解为一系列相似的小问题,通过函数不断调用自身来解决这一个个小问题,直到满足结束条件,就完成了问题的求解。

                  TypeScript 的高级类型支持类型参数,可以做各种类型运算逻辑,返回新的类型,和函数调用是对应的,自然也支持递归。

                  TypeScript 类型系统不支持循环,但支持递归。当处理数量(个数、长度、层数)不固定的类型的时候,可以只处理一个类型,然后递归的调用自身处理下一个类型,直到结束条件也就是所有的类型都处理完了,就完成了不确定数量的类型编程,达到循环的效果。

                  既然提到了数组、字符串、对象等类型,那么我们就来看一下这些类型的递归案例吧。

                  Promise 的递归复用

                  DeepPromiseValueType

                  先用 Promise 热热身,实现一个提取不确定层数的 Promise 中的 value 类型的高级类型。

                  ts
                  type ttt = Promise<Promise<Promise<Record<string, any>>>>;

                  这里是 3 层 Promise,value 类型是索引类型。

                  数量不确定,一涉及到这个就要想到用递归来做,每次只处理一层的提取,然后剩下的到下次递归做,直到结束条件。

                  所以高级类型是这样的:

                  ts
                  type DeepPromiseValueType<P extends Promise<unknown>> =
                     P extends Promise<infer ValueType>
                       ? ValueType extends Promise<unknown>
                         ? DeepPromiseValueType<ValueType>
                  diff --git a/assets/src_article_typescript_unionType.md.D4NH8xmg.js b/assets/src_article_typescript_unionType.md.BKfC5bWe.js
                  similarity index 99%
                  rename from assets/src_article_typescript_unionType.md.D4NH8xmg.js
                  rename to assets/src_article_typescript_unionType.md.BKfC5bWe.js
                  index 29c9b63d76..6f816118d7 100644
                  --- a/assets/src_article_typescript_unionType.md.D4NH8xmg.js
                  +++ b/assets/src_article_typescript_unionType.md.BKfC5bWe.js
                  @@ -1 +1 @@
                  -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"分布式条件类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/unionType.md","filePath":"src/article/typescript/unionType.md","lastUpdated":1728828157000}'),k={name:"src/article/typescript/unionType.md"};function n(p,s,l,e,d,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  分布式条件类型

                  当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。

                  比如这样一个联合类型:

                  ts
                  type Union = 'a' | 'b' | 'c';

                  我们想把其中的 a 大写,就可以这样写:

                  ts
                  type UppercaseA<Item extends string> = Item extends 'a' ? Uppercase<Item> : Item;
                  ts
                  type result = UppercaseA<Union>;\n// type result = 'A' | 'b' | 'c';

                  可以看到,我们类型参数 Item 约束为 string,条件类型的判断中也是判断是否是 a,但传入的是联合类型。

                  这就是 TypeScript 对联合类型在条件类型中使用时的特殊处理:会把联合类型的每一个元素单独传入做类型计算,最后合并。

                  这和联合类型遇到字符串时的处理一样:

                  这样确实是简化了类型编程逻辑的,不需要递归提取每个元素再处理。

                  TypeScript 之所以这样处理联合类型也很容易理解,因为联合类型的每个元素都是互不相关的,不像数组、索引、字符串那样元素之间是有关系的。所以设计成了每一个单独处理,最后合并。

                  知道了 TypeScript 怎么处理的联合类型,趁热打铁来练习一下:

                  CamelcaseUnion

                  Camelcase 我们实现过,就是提取字符串中的字符,首字母大写以后重新构造一个新的。

                  ts
                  type Camelcase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${Camelcase<Rest>}`\n  : Str;

                  提取 _ 左右的字符,把右边字符大写之后构造成新的字符串,余下的字符串递归处理。

                  ts
                  type CamelcaseResult = Camelcase<'aa_aa_aa'>;\n// type CamelcaseResult = 'aaAaAa'

                  如果是对字符串数组做 Camelcase,那就要递归处理每一个元素:

                  ts
                  type CamelcaseArr<Arr extends unknown[]> = Arr extends [infer Item, ...infer RestArr]\n  ? [Camelcase<Item & string>, ...CamelcaseArr<RestArr>]\n  : [];

                  类型参数 Arr 为待处理数组。

                  递归提取每一个元素做 Camelcase,因为 Camelcase 要求传入 string,这里要 & string 来变成 string 类型。

                  那如果是联合类型呢?

                  联合类型不需要递归提取每个元素,TypeScript 内部会把每一个元素传入单独做计算,之后把每个元素的计算结果合并成联合类型。

                  ts
                  type CamelcaseUnion<Item extends string> = Item extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${CamelcaseUnion<Rest>}`\n  : Item;

                  这不和单个字符串的处理没区别么?

                  没错,对联合类型的处理和对单个类型的处理没什么区别,TypeScript 会把每个单独的类型拆开传入。不需要像数组类型那样需要递归提取每个元素做处理。

                  确实简化了很多,好像都是优点?

                  也不全是,其实这样处理也增加了一些认知成本,不信我们再来看个例子:

                  IsUnion

                  判断联合类型我们会这样写:

                  ts
                  type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

                  当传入联合类型时,会返回 true:

                  ts
                  type IsUnionResult = IsUnion<'a' | 'b' 'c'>\n// type IsUnionResult = true

                  当传入其他类型时,会返回 false:

                  ts
                  type IsUnionResult = IsUnion<['a' | 'b' 'c']>\n// type IsUnionResult = false

                  这就是分布式条件类型带来的认知成本。

                  我们先来看这样一个类型:

                  ts
                  type TestUnion<A, B = A> = A extends A ? { a: A; b: B } : never;\n\ntype TestUnionResult = TestUnion<'a' | 'b' | 'c'>;

                  传入联合类型 'a' | 'b' | 'c' 的时候,结果是这样的:

                  A 和 B 都是同一个联合类型,为啥值还不一样呢?

                  因为条件类型中如果左边的类型是联合类型,会把每个元素单独传入做计算,而右边不会。

                  所以 A 是 'a' 的时候,B 是 'a' | 'b' | 'c',A 是 'b' 的时候,B 是 'a' | 'b' | 'c'。。。

                  那么利用这个特点就可以实现 Union 类型的判断:

                  ts
                  type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

                  类型参数 A、B 是待判断的联合类型,B 默认值为 A,也就是同一个类型。

                  A extends A 这段看似没啥意义,主要是为了触发分布式条件类型,让 A 的每个类型单独传入。

                  [B] extends [A] 这样不直接写 B 就可以避免触发分布式条件类型,那么 B 就是整个联合类型。

                  B 是联合类型整体,而 A 是单个类型,自然不成立,而其它类型没有这种特殊处理,A 和 B 都是同一个,怎么判断都成立。

                  利用这个特点就可以判断出是否是联合类型。

                  其中有两个点比较困惑,我们重点记一下:

                  当 A 是联合类型时:

                  A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。

                  A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。

                  理解了这两点,分布式条件类型就算掌握了。

                  BEM

                  bem 是 css 命名规范,用 block__element--modifier 的形式来描述某个区块下面的某个元素的某个状态的样式。

                  那么我们可以写这样一个高级类型,传入 block、element、modifier,返回构造出的 class 名:

                  这样使用:

                  ts
                  type bemResult = BEM<'guang', ['aaa', 'bbb'], ['warning', 'success']>;

                  它的实现就是三部分的合并,但传入的是数组,要递归遍历取出每一个元素来和其他部分组合,这样太麻烦了。

                  而如果是联合类型就不用递归遍历了,因为联合类型遇到字符串也是会单独每个元素单独传入做处理。

                  数组转联合类型可以这样写:

                  ts
                  type union = ['aaa', 'bbb'][number];\n// type union = 'aaa' | 'bbb'

                  那么 BEM 就可以这样实现:

                  ts
                  type BEM<\n  Block extends string,\n  Element extends string[],\n  Modifiers extends string[],\n> = `${Block}__${Element[number]}--${Modifiers[number]}`;

                  类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

                  构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

                  字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

                  ts
                  type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;\n// type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

                  可以看到,用好了联合类型,确实能简化类型编程逻辑。

                  AllCombinations

                  我们再来实现一个全组合的高级类型,也是联合类型相关的:

                  希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

                  这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

                  比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

                  任何两个类型的组合有四种:A、B、AB、BA

                  ts
                  type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

                  然后构造出来的字符串再和其他字符串组合。

                  所以全组合的高级类型就是这样:

                  ts
                  type AllCombinations<A extends string, B extends string = A> = A extends A\n  ? Combination<A, AllCombinations<Exclude<B, A>>>\n  : never;

                  类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

                  A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

                  A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

                  而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

                  总结

                  联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

                  条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

                  有两点特别要注意:

                  • A extends A 不是没意义,意义是取出联合类型中的单个类型放入 A

                  • A extends A 才是分布式条件类型, [A] extends [A] 就不是了,只有左边是单独的类型参数才可以。

                  我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

                  ',91)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"分布式条件类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/unionType.md","filePath":"src/article/typescript/unionType.md","lastUpdated":1728921295000}'),k={name:"src/article/typescript/unionType.md"};function n(p,s,l,e,d,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  分布式条件类型

                  当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。

                  比如这样一个联合类型:

                  ts
                  type Union = 'a' | 'b' | 'c';

                  我们想把其中的 a 大写,就可以这样写:

                  ts
                  type UppercaseA<Item extends string> = Item extends 'a' ? Uppercase<Item> : Item;
                  ts
                  type result = UppercaseA<Union>;\n// type result = 'A' | 'b' | 'c';

                  可以看到,我们类型参数 Item 约束为 string,条件类型的判断中也是判断是否是 a,但传入的是联合类型。

                  这就是 TypeScript 对联合类型在条件类型中使用时的特殊处理:会把联合类型的每一个元素单独传入做类型计算,最后合并。

                  这和联合类型遇到字符串时的处理一样:

                  这样确实是简化了类型编程逻辑的,不需要递归提取每个元素再处理。

                  TypeScript 之所以这样处理联合类型也很容易理解,因为联合类型的每个元素都是互不相关的,不像数组、索引、字符串那样元素之间是有关系的。所以设计成了每一个单独处理,最后合并。

                  知道了 TypeScript 怎么处理的联合类型,趁热打铁来练习一下:

                  CamelcaseUnion

                  Camelcase 我们实现过,就是提取字符串中的字符,首字母大写以后重新构造一个新的。

                  ts
                  type Camelcase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${Camelcase<Rest>}`\n  : Str;

                  提取 _ 左右的字符,把右边字符大写之后构造成新的字符串,余下的字符串递归处理。

                  ts
                  type CamelcaseResult = Camelcase<'aa_aa_aa'>;\n// type CamelcaseResult = 'aaAaAa'

                  如果是对字符串数组做 Camelcase,那就要递归处理每一个元素:

                  ts
                  type CamelcaseArr<Arr extends unknown[]> = Arr extends [infer Item, ...infer RestArr]\n  ? [Camelcase<Item & string>, ...CamelcaseArr<RestArr>]\n  : [];

                  类型参数 Arr 为待处理数组。

                  递归提取每一个元素做 Camelcase,因为 Camelcase 要求传入 string,这里要 & string 来变成 string 类型。

                  那如果是联合类型呢?

                  联合类型不需要递归提取每个元素,TypeScript 内部会把每一个元素传入单独做计算,之后把每个元素的计算结果合并成联合类型。

                  ts
                  type CamelcaseUnion<Item extends string> = Item extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${CamelcaseUnion<Rest>}`\n  : Item;

                  这不和单个字符串的处理没区别么?

                  没错,对联合类型的处理和对单个类型的处理没什么区别,TypeScript 会把每个单独的类型拆开传入。不需要像数组类型那样需要递归提取每个元素做处理。

                  确实简化了很多,好像都是优点?

                  也不全是,其实这样处理也增加了一些认知成本,不信我们再来看个例子:

                  IsUnion

                  判断联合类型我们会这样写:

                  ts
                  type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

                  当传入联合类型时,会返回 true:

                  ts
                  type IsUnionResult = IsUnion<'a' | 'b' 'c'>\n// type IsUnionResult = true

                  当传入其他类型时,会返回 false:

                  ts
                  type IsUnionResult = IsUnion<['a' | 'b' 'c']>\n// type IsUnionResult = false

                  这就是分布式条件类型带来的认知成本。

                  我们先来看这样一个类型:

                  ts
                  type TestUnion<A, B = A> = A extends A ? { a: A; b: B } : never;\n\ntype TestUnionResult = TestUnion<'a' | 'b' | 'c'>;

                  传入联合类型 'a' | 'b' | 'c' 的时候,结果是这样的:

                  A 和 B 都是同一个联合类型,为啥值还不一样呢?

                  因为条件类型中如果左边的类型是联合类型,会把每个元素单独传入做计算,而右边不会。

                  所以 A 是 'a' 的时候,B 是 'a' | 'b' | 'c',A 是 'b' 的时候,B 是 'a' | 'b' | 'c'。。。

                  那么利用这个特点就可以实现 Union 类型的判断:

                  ts
                  type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

                  类型参数 A、B 是待判断的联合类型,B 默认值为 A,也就是同一个类型。

                  A extends A 这段看似没啥意义,主要是为了触发分布式条件类型,让 A 的每个类型单独传入。

                  [B] extends [A] 这样不直接写 B 就可以避免触发分布式条件类型,那么 B 就是整个联合类型。

                  B 是联合类型整体,而 A 是单个类型,自然不成立,而其它类型没有这种特殊处理,A 和 B 都是同一个,怎么判断都成立。

                  利用这个特点就可以判断出是否是联合类型。

                  其中有两个点比较困惑,我们重点记一下:

                  当 A 是联合类型时:

                  A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。

                  A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。

                  理解了这两点,分布式条件类型就算掌握了。

                  BEM

                  bem 是 css 命名规范,用 block__element--modifier 的形式来描述某个区块下面的某个元素的某个状态的样式。

                  那么我们可以写这样一个高级类型,传入 block、element、modifier,返回构造出的 class 名:

                  这样使用:

                  ts
                  type bemResult = BEM<'guang', ['aaa', 'bbb'], ['warning', 'success']>;

                  它的实现就是三部分的合并,但传入的是数组,要递归遍历取出每一个元素来和其他部分组合,这样太麻烦了。

                  而如果是联合类型就不用递归遍历了,因为联合类型遇到字符串也是会单独每个元素单独传入做处理。

                  数组转联合类型可以这样写:

                  ts
                  type union = ['aaa', 'bbb'][number];\n// type union = 'aaa' | 'bbb'

                  那么 BEM 就可以这样实现:

                  ts
                  type BEM<\n  Block extends string,\n  Element extends string[],\n  Modifiers extends string[],\n> = `${Block}__${Element[number]}--${Modifiers[number]}`;

                  类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

                  构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

                  字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

                  ts
                  type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;\n// type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

                  可以看到,用好了联合类型,确实能简化类型编程逻辑。

                  AllCombinations

                  我们再来实现一个全组合的高级类型,也是联合类型相关的:

                  希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

                  这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

                  比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

                  任何两个类型的组合有四种:A、B、AB、BA

                  ts
                  type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

                  然后构造出来的字符串再和其他字符串组合。

                  所以全组合的高级类型就是这样:

                  ts
                  type AllCombinations<A extends string, B extends string = A> = A extends A\n  ? Combination<A, AllCombinations<Exclude<B, A>>>\n  : never;

                  类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

                  A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

                  A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

                  而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

                  总结

                  联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

                  条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

                  有两点特别要注意:

                  • A extends A 不是没意义,意义是取出联合类型中的单个类型放入 A

                  • A extends A 才是分布式条件类型, [A] extends [A] 就不是了,只有左边是单独的类型参数才可以。

                  我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

                  ',91)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; diff --git a/assets/src_article_typescript_unionType.md.D4NH8xmg.lean.js b/assets/src_article_typescript_unionType.md.BKfC5bWe.lean.js similarity index 99% rename from assets/src_article_typescript_unionType.md.D4NH8xmg.lean.js rename to assets/src_article_typescript_unionType.md.BKfC5bWe.lean.js index 29c9b63d76..6f816118d7 100644 --- a/assets/src_article_typescript_unionType.md.D4NH8xmg.lean.js +++ b/assets/src_article_typescript_unionType.md.BKfC5bWe.lean.js @@ -1 +1 @@ -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"分布式条件类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/unionType.md","filePath":"src/article/typescript/unionType.md","lastUpdated":1728828157000}'),k={name:"src/article/typescript/unionType.md"};function n(p,s,l,e,d,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  分布式条件类型

                  当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。

                  比如这样一个联合类型:

                  ts
                  type Union = 'a' | 'b' | 'c';

                  我们想把其中的 a 大写,就可以这样写:

                  ts
                  type UppercaseA<Item extends string> = Item extends 'a' ? Uppercase<Item> : Item;
                  ts
                  type result = UppercaseA<Union>;\n// type result = 'A' | 'b' | 'c';

                  可以看到,我们类型参数 Item 约束为 string,条件类型的判断中也是判断是否是 a,但传入的是联合类型。

                  这就是 TypeScript 对联合类型在条件类型中使用时的特殊处理:会把联合类型的每一个元素单独传入做类型计算,最后合并。

                  这和联合类型遇到字符串时的处理一样:

                  这样确实是简化了类型编程逻辑的,不需要递归提取每个元素再处理。

                  TypeScript 之所以这样处理联合类型也很容易理解,因为联合类型的每个元素都是互不相关的,不像数组、索引、字符串那样元素之间是有关系的。所以设计成了每一个单独处理,最后合并。

                  知道了 TypeScript 怎么处理的联合类型,趁热打铁来练习一下:

                  CamelcaseUnion

                  Camelcase 我们实现过,就是提取字符串中的字符,首字母大写以后重新构造一个新的。

                  ts
                  type Camelcase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${Camelcase<Rest>}`\n  : Str;

                  提取 _ 左右的字符,把右边字符大写之后构造成新的字符串,余下的字符串递归处理。

                  ts
                  type CamelcaseResult = Camelcase<'aa_aa_aa'>;\n// type CamelcaseResult = 'aaAaAa'

                  如果是对字符串数组做 Camelcase,那就要递归处理每一个元素:

                  ts
                  type CamelcaseArr<Arr extends unknown[]> = Arr extends [infer Item, ...infer RestArr]\n  ? [Camelcase<Item & string>, ...CamelcaseArr<RestArr>]\n  : [];

                  类型参数 Arr 为待处理数组。

                  递归提取每一个元素做 Camelcase,因为 Camelcase 要求传入 string,这里要 & string 来变成 string 类型。

                  那如果是联合类型呢?

                  联合类型不需要递归提取每个元素,TypeScript 内部会把每一个元素传入单独做计算,之后把每个元素的计算结果合并成联合类型。

                  ts
                  type CamelcaseUnion<Item extends string> = Item extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${CamelcaseUnion<Rest>}`\n  : Item;

                  这不和单个字符串的处理没区别么?

                  没错,对联合类型的处理和对单个类型的处理没什么区别,TypeScript 会把每个单独的类型拆开传入。不需要像数组类型那样需要递归提取每个元素做处理。

                  确实简化了很多,好像都是优点?

                  也不全是,其实这样处理也增加了一些认知成本,不信我们再来看个例子:

                  IsUnion

                  判断联合类型我们会这样写:

                  ts
                  type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

                  当传入联合类型时,会返回 true:

                  ts
                  type IsUnionResult = IsUnion<'a' | 'b' 'c'>\n// type IsUnionResult = true

                  当传入其他类型时,会返回 false:

                  ts
                  type IsUnionResult = IsUnion<['a' | 'b' 'c']>\n// type IsUnionResult = false

                  这就是分布式条件类型带来的认知成本。

                  我们先来看这样一个类型:

                  ts
                  type TestUnion<A, B = A> = A extends A ? { a: A; b: B } : never;\n\ntype TestUnionResult = TestUnion<'a' | 'b' | 'c'>;

                  传入联合类型 'a' | 'b' | 'c' 的时候,结果是这样的:

                  A 和 B 都是同一个联合类型,为啥值还不一样呢?

                  因为条件类型中如果左边的类型是联合类型,会把每个元素单独传入做计算,而右边不会。

                  所以 A 是 'a' 的时候,B 是 'a' | 'b' | 'c',A 是 'b' 的时候,B 是 'a' | 'b' | 'c'。。。

                  那么利用这个特点就可以实现 Union 类型的判断:

                  ts
                  type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

                  类型参数 A、B 是待判断的联合类型,B 默认值为 A,也就是同一个类型。

                  A extends A 这段看似没啥意义,主要是为了触发分布式条件类型,让 A 的每个类型单独传入。

                  [B] extends [A] 这样不直接写 B 就可以避免触发分布式条件类型,那么 B 就是整个联合类型。

                  B 是联合类型整体,而 A 是单个类型,自然不成立,而其它类型没有这种特殊处理,A 和 B 都是同一个,怎么判断都成立。

                  利用这个特点就可以判断出是否是联合类型。

                  其中有两个点比较困惑,我们重点记一下:

                  当 A 是联合类型时:

                  A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。

                  A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。

                  理解了这两点,分布式条件类型就算掌握了。

                  BEM

                  bem 是 css 命名规范,用 block__element--modifier 的形式来描述某个区块下面的某个元素的某个状态的样式。

                  那么我们可以写这样一个高级类型,传入 block、element、modifier,返回构造出的 class 名:

                  这样使用:

                  ts
                  type bemResult = BEM<'guang', ['aaa', 'bbb'], ['warning', 'success']>;

                  它的实现就是三部分的合并,但传入的是数组,要递归遍历取出每一个元素来和其他部分组合,这样太麻烦了。

                  而如果是联合类型就不用递归遍历了,因为联合类型遇到字符串也是会单独每个元素单独传入做处理。

                  数组转联合类型可以这样写:

                  ts
                  type union = ['aaa', 'bbb'][number];\n// type union = 'aaa' | 'bbb'

                  那么 BEM 就可以这样实现:

                  ts
                  type BEM<\n  Block extends string,\n  Element extends string[],\n  Modifiers extends string[],\n> = `${Block}__${Element[number]}--${Modifiers[number]}`;

                  类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

                  构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

                  字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

                  ts
                  type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;\n// type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

                  可以看到,用好了联合类型,确实能简化类型编程逻辑。

                  AllCombinations

                  我们再来实现一个全组合的高级类型,也是联合类型相关的:

                  希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

                  这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

                  比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

                  任何两个类型的组合有四种:A、B、AB、BA

                  ts
                  type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

                  然后构造出来的字符串再和其他字符串组合。

                  所以全组合的高级类型就是这样:

                  ts
                  type AllCombinations<A extends string, B extends string = A> = A extends A\n  ? Combination<A, AllCombinations<Exclude<B, A>>>\n  : never;

                  类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

                  A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

                  A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

                  而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

                  总结

                  联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

                  条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

                  有两点特别要注意:

                  • A extends A 不是没意义,意义是取出联合类型中的单个类型放入 A

                  • A extends A 才是分布式条件类型, [A] extends [A] 就不是了,只有左边是单独的类型参数才可以。

                  我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

                  ',91)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"分布式条件类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/article/typescript/unionType.md","filePath":"src/article/typescript/unionType.md","lastUpdated":1728921295000}'),k={name:"src/article/typescript/unionType.md"};function n(p,s,l,e,d,r){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  分布式条件类型

                  当类型参数为联合类型,并且在条件类型左边直接引用该类型参数的时候,TypeScript 会把每一个元素单独传入来做类型运算,最后再合并成联合类型,这种语法叫做分布式条件类型。

                  比如这样一个联合类型:

                  ts
                  type Union = 'a' | 'b' | 'c';

                  我们想把其中的 a 大写,就可以这样写:

                  ts
                  type UppercaseA<Item extends string> = Item extends 'a' ? Uppercase<Item> : Item;
                  ts
                  type result = UppercaseA<Union>;\n// type result = 'A' | 'b' | 'c';

                  可以看到,我们类型参数 Item 约束为 string,条件类型的判断中也是判断是否是 a,但传入的是联合类型。

                  这就是 TypeScript 对联合类型在条件类型中使用时的特殊处理:会把联合类型的每一个元素单独传入做类型计算,最后合并。

                  这和联合类型遇到字符串时的处理一样:

                  这样确实是简化了类型编程逻辑的,不需要递归提取每个元素再处理。

                  TypeScript 之所以这样处理联合类型也很容易理解,因为联合类型的每个元素都是互不相关的,不像数组、索引、字符串那样元素之间是有关系的。所以设计成了每一个单独处理,最后合并。

                  知道了 TypeScript 怎么处理的联合类型,趁热打铁来练习一下:

                  CamelcaseUnion

                  Camelcase 我们实现过,就是提取字符串中的字符,首字母大写以后重新构造一个新的。

                  ts
                  type Camelcase<Str extends string> = Str extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${Camelcase<Rest>}`\n  : Str;

                  提取 _ 左右的字符,把右边字符大写之后构造成新的字符串,余下的字符串递归处理。

                  ts
                  type CamelcaseResult = Camelcase<'aa_aa_aa'>;\n// type CamelcaseResult = 'aaAaAa'

                  如果是对字符串数组做 Camelcase,那就要递归处理每一个元素:

                  ts
                  type CamelcaseArr<Arr extends unknown[]> = Arr extends [infer Item, ...infer RestArr]\n  ? [Camelcase<Item & string>, ...CamelcaseArr<RestArr>]\n  : [];

                  类型参数 Arr 为待处理数组。

                  递归提取每一个元素做 Camelcase,因为 Camelcase 要求传入 string,这里要 & string 来变成 string 类型。

                  那如果是联合类型呢?

                  联合类型不需要递归提取每个元素,TypeScript 内部会把每一个元素传入单独做计算,之后把每个元素的计算结果合并成联合类型。

                  ts
                  type CamelcaseUnion<Item extends string> = Item extends `${infer Left}_${infer Right}${infer Rest}`\n  ? `${Left}${Uppercase<Right>}${CamelcaseUnion<Rest>}`\n  : Item;

                  这不和单个字符串的处理没区别么?

                  没错,对联合类型的处理和对单个类型的处理没什么区别,TypeScript 会把每个单独的类型拆开传入。不需要像数组类型那样需要递归提取每个元素做处理。

                  确实简化了很多,好像都是优点?

                  也不全是,其实这样处理也增加了一些认知成本,不信我们再来看个例子:

                  IsUnion

                  判断联合类型我们会这样写:

                  ts
                  type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

                  当传入联合类型时,会返回 true:

                  ts
                  type IsUnionResult = IsUnion<'a' | 'b' 'c'>\n// type IsUnionResult = true

                  当传入其他类型时,会返回 false:

                  ts
                  type IsUnionResult = IsUnion<['a' | 'b' 'c']>\n// type IsUnionResult = false

                  这就是分布式条件类型带来的认知成本。

                  我们先来看这样一个类型:

                  ts
                  type TestUnion<A, B = A> = A extends A ? { a: A; b: B } : never;\n\ntype TestUnionResult = TestUnion<'a' | 'b' | 'c'>;

                  传入联合类型 'a' | 'b' | 'c' 的时候,结果是这样的:

                  A 和 B 都是同一个联合类型,为啥值还不一样呢?

                  因为条件类型中如果左边的类型是联合类型,会把每个元素单独传入做计算,而右边不会。

                  所以 A 是 'a' 的时候,B 是 'a' | 'b' | 'c',A 是 'b' 的时候,B 是 'a' | 'b' | 'c'。。。

                  那么利用这个特点就可以实现 Union 类型的判断:

                  ts
                  type IsUnion<A, B = A> = A extends A ? ([B] extends [A] ? false : true) : never;

                  类型参数 A、B 是待判断的联合类型,B 默认值为 A,也就是同一个类型。

                  A extends A 这段看似没啥意义,主要是为了触发分布式条件类型,让 A 的每个类型单独传入。

                  [B] extends [A] 这样不直接写 B 就可以避免触发分布式条件类型,那么 B 就是整个联合类型。

                  B 是联合类型整体,而 A 是单个类型,自然不成立,而其它类型没有这种特殊处理,A 和 B 都是同一个,怎么判断都成立。

                  利用这个特点就可以判断出是否是联合类型。

                  其中有两个点比较困惑,我们重点记一下:

                  当 A 是联合类型时:

                  A extends A 这种写法是为了触发分布式条件类型,让每个类型单独传入处理的,没别的意义。

                  A extends A 和 [A] extends [A] 是不同的处理,前者是单个类型和整个类型做判断,后者两边都是整个联合类型,因为只有 extends 左边直接是类型参数才会触发分布式条件类型。

                  理解了这两点,分布式条件类型就算掌握了。

                  BEM

                  bem 是 css 命名规范,用 block__element--modifier 的形式来描述某个区块下面的某个元素的某个状态的样式。

                  那么我们可以写这样一个高级类型,传入 block、element、modifier,返回构造出的 class 名:

                  这样使用:

                  ts
                  type bemResult = BEM<'guang', ['aaa', 'bbb'], ['warning', 'success']>;

                  它的实现就是三部分的合并,但传入的是数组,要递归遍历取出每一个元素来和其他部分组合,这样太麻烦了。

                  而如果是联合类型就不用递归遍历了,因为联合类型遇到字符串也是会单独每个元素单独传入做处理。

                  数组转联合类型可以这样写:

                  ts
                  type union = ['aaa', 'bbb'][number];\n// type union = 'aaa' | 'bbb'

                  那么 BEM 就可以这样实现:

                  ts
                  type BEM<\n  Block extends string,\n  Element extends string[],\n  Modifiers extends string[],\n> = `${Block}__${Element[number]}--${Modifiers[number]}`;

                  类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

                  构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

                  字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

                  ts
                  type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;\n// type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

                  可以看到,用好了联合类型,确实能简化类型编程逻辑。

                  AllCombinations

                  我们再来实现一个全组合的高级类型,也是联合类型相关的:

                  希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

                  这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

                  比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

                  任何两个类型的组合有四种:A、B、AB、BA

                  ts
                  type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

                  然后构造出来的字符串再和其他字符串组合。

                  所以全组合的高级类型就是这样:

                  ts
                  type AllCombinations<A extends string, B extends string = A> = A extends A\n  ? Combination<A, AllCombinations<Exclude<B, A>>>\n  : never;

                  类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

                  A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

                  A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

                  而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

                  总结

                  联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

                  条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

                  有两点特别要注意:

                  • A extends A 不是没意义,意义是取出联合类型中的单个类型放入 A

                  • A extends A 才是分布式条件类型, [A] extends [A] 就不是了,只有左边是单独的类型参数才可以。

                  我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

                  ',91)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; diff --git a/assets/src_ranui_button_index.md.OpGrfpg8.js b/assets/src_ranui_button_index.md.C5LIQdyS.js similarity index 99% rename from assets/src_ranui_button_index.md.OpGrfpg8.js rename to assets/src_ranui_button_index.md.C5LIQdyS.js index e369f58eda..1e6af0df24 100644 --- a/assets/src_ranui_button_index.md.OpGrfpg8.js +++ b/assets/src_ranui_button_index.md.C5LIQdyS.js @@ -1,4 +1,4 @@ -import{_ as a,o as n,c as e,a3 as t,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Button","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/button/index.md","filePath":"src/ranui/button/index.md","lastUpdated":1728828157000}'),l={name:"src/ranui/button/index.md"};function h(p,i,k,r,o,d){return n(),e("div",{"data-pagefind-body":!0},i[0]||(i[0]=[t(`

                  Button

                  The button is used to start an instant action.

                  Code demo

                  Button
                  xml
                   <r-button >Button</r-button>

                  Attribute

                  type

                  There are four types of buttons

                  Primary button
                  Warning button
                  Text button
                  Default button
                  xml
                   <r-button type="primary">Primary button</r-button>
                  +import{_ as a,o as n,c as e,a3 as t,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Button","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/button/index.md","filePath":"src/ranui/button/index.md","lastUpdated":1728921295000}'),l={name:"src/ranui/button/index.md"};function h(p,i,k,r,o,d){return n(),e("div",{"data-pagefind-body":!0},i[0]||(i[0]=[t(`

                  Button

                  The button is used to start an instant action.

                  Code demo

                  Button
                  xml
                   <r-button >Button</r-button>

                  Attribute

                  type

                  There are four types of buttons

                  Primary button
                  Warning button
                  Text button
                  Default button
                  xml
                   <r-button type="primary">Primary button</r-button>
                    <r-button type="warning">Warning button</r-button>
                    <r-button type="text">Text button</r-button>
                    <r-button >Default button</r-button>

                  disabled

                  Adding the disabled attribute makes the button unavailable and changes the button style.

                  Primary button
                  Warning button
                  Text button
                  Default button
                  xml
                   <r-button type="primary" disabled>Primary butto</r-button>
                  diff --git a/assets/src_ranui_button_index.md.OpGrfpg8.lean.js b/assets/src_ranui_button_index.md.C5LIQdyS.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_button_index.md.OpGrfpg8.lean.js
                  rename to assets/src_ranui_button_index.md.C5LIQdyS.lean.js
                  index e369f58eda..1e6af0df24 100644
                  --- a/assets/src_ranui_button_index.md.OpGrfpg8.lean.js
                  +++ b/assets/src_ranui_button_index.md.C5LIQdyS.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,o as n,c as e,a3 as t,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Button","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/button/index.md","filePath":"src/ranui/button/index.md","lastUpdated":1728828157000}'),l={name:"src/ranui/button/index.md"};function h(p,i,k,r,o,d){return n(),e("div",{"data-pagefind-body":!0},i[0]||(i[0]=[t(`

                  Button

                  The button is used to start an instant action.

                  Code demo

                  Button
                  xml
                   <r-button >Button</r-button>

                  Attribute

                  type

                  There are four types of buttons

                  Primary button
                  Warning button
                  Text button
                  Default button
                  xml
                   <r-button type="primary">Primary button</r-button>
                  +import{_ as a,o as n,c as e,a3 as t,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Button","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/button/index.md","filePath":"src/ranui/button/index.md","lastUpdated":1728921295000}'),l={name:"src/ranui/button/index.md"};function h(p,i,k,r,o,d){return n(),e("div",{"data-pagefind-body":!0},i[0]||(i[0]=[t(`

                  Button

                  The button is used to start an instant action.

                  Code demo

                  Button
                  xml
                   <r-button >Button</r-button>

                  Attribute

                  type

                  There are four types of buttons

                  Primary button
                  Warning button
                  Text button
                  Default button
                  xml
                   <r-button type="primary">Primary button</r-button>
                    <r-button type="warning">Warning button</r-button>
                    <r-button type="text">Text button</r-button>
                    <r-button >Default button</r-button>

                  disabled

                  Adding the disabled attribute makes the button unavailable and changes the button style.

                  Primary button
                  Warning button
                  Text button
                  Default button
                  xml
                   <r-button type="primary" disabled>Primary butto</r-button>
                  diff --git a/assets/src_ranui_checkbox_index.md.C6CmsGDw.js b/assets/src_ranui_checkbox_index.md.Dmwi-qhd.js
                  similarity index 99%
                  rename from assets/src_ranui_checkbox_index.md.C6CmsGDw.js
                  rename to assets/src_ranui_checkbox_index.md.Dmwi-qhd.js
                  index 34a754849d..e60627470a 100644
                  --- a/assets/src_ranui_checkbox_index.md.C6CmsGDw.js
                  +++ b/assets/src_ranui_checkbox_index.md.Dmwi-qhd.js
                  @@ -1,2 +1,2 @@
                  -import{_ as e,o as h,c as t,a3 as i,j as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CheckBox","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/checkbox/index.md","filePath":"src/ranui/checkbox/index.md","lastUpdated":1728828157000}'),l={name:"src/ranui/checkbox/index.md"};function k(n,s,c,d,p,o){return h(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[i('

                  CheckBox

                  Code demo

                  xml
                   <r-checkbox ></r-checkbox>

                  Attribute

                  checked

                  xml
                   <r-checkbox checked="true"></r-checkbox>\n <r-checkbox checked="false"></r-checkbox>

                  disabled

                  xml
                   <r-checkbox checked="true" disabled></r-checkbox>\n <r-checkbox checked="false" disabled></r-checkbox>

                  event

                  Common callback events.

                  onchange

                  ',16),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),i(`
                  xml
                   <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
                  +import{_ as e,o as h,c as t,a3 as i,j as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CheckBox","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/checkbox/index.md","filePath":"src/ranui/checkbox/index.md","lastUpdated":1728921295000}'),l={name:"src/ranui/checkbox/index.md"};function k(n,s,c,d,p,o){return h(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[i('

                  CheckBox

                  Code demo

                  xml
                   <r-checkbox ></r-checkbox>

                  Attribute

                  checked

                  xml
                   <r-checkbox checked="true"></r-checkbox>\n <r-checkbox checked="false"></r-checkbox>

                  disabled

                  xml
                   <r-checkbox checked="true" disabled></r-checkbox>\n <r-checkbox checked="false" disabled></r-checkbox>

                  event

                  Common callback events.

                  onchange

                  ',16),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),i(`
                  xml
                   <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
                    <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
                  `,1)]))}const g=e(l,[["render",k]]);export{E as __pageData,g as default}; diff --git a/assets/src_ranui_checkbox_index.md.C6CmsGDw.lean.js b/assets/src_ranui_checkbox_index.md.Dmwi-qhd.lean.js similarity index 99% rename from assets/src_ranui_checkbox_index.md.C6CmsGDw.lean.js rename to assets/src_ranui_checkbox_index.md.Dmwi-qhd.lean.js index 34a754849d..e60627470a 100644 --- a/assets/src_ranui_checkbox_index.md.C6CmsGDw.lean.js +++ b/assets/src_ranui_checkbox_index.md.Dmwi-qhd.lean.js @@ -1,2 +1,2 @@ -import{_ as e,o as h,c as t,a3 as i,j as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CheckBox","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/checkbox/index.md","filePath":"src/ranui/checkbox/index.md","lastUpdated":1728828157000}'),l={name:"src/ranui/checkbox/index.md"};function k(n,s,c,d,p,o){return h(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[i('

                  CheckBox

                  Code demo

                  xml
                   <r-checkbox ></r-checkbox>

                  Attribute

                  checked

                  xml
                   <r-checkbox checked="true"></r-checkbox>\n <r-checkbox checked="false"></r-checkbox>

                  disabled

                  xml
                   <r-checkbox checked="true" disabled></r-checkbox>\n <r-checkbox checked="false" disabled></r-checkbox>

                  event

                  Common callback events.

                  onchange

                  ',16),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),i(`
                  xml
                   <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
                  +import{_ as e,o as h,c as t,a3 as i,j as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"CheckBox","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/checkbox/index.md","filePath":"src/ranui/checkbox/index.md","lastUpdated":1728921295000}'),l={name:"src/ranui/checkbox/index.md"};function k(n,s,c,d,p,o){return h(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[i('

                  CheckBox

                  Code demo

                  xml
                   <r-checkbox ></r-checkbox>

                  Attribute

                  checked

                  xml
                   <r-checkbox checked="true"></r-checkbox>\n <r-checkbox checked="false"></r-checkbox>

                  disabled

                  xml
                   <r-checkbox checked="true" disabled></r-checkbox>\n <r-checkbox checked="false" disabled></r-checkbox>

                  event

                  Common callback events.

                  onchange

                  ',16),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),a("r-checkbox",{onchange:"console.log(this.checked)"},null,-1),i(`
                  xml
                   <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
                    <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
                  `,1)]))}const g=e(l,[["render",k]]);export{E as __pageData,g as default}; diff --git a/assets/src_ranui_icon_index.md.BQTFP8u3.js b/assets/src_ranui_icon_index.md.DHD0uzGs.js similarity index 99% rename from assets/src_ranui_icon_index.md.BQTFP8u3.js rename to assets/src_ranui_icon_index.md.DHD0uzGs.js index 7638c8a55d..94ec3fb18d 100644 --- a/assets/src_ranui_icon_index.md.BQTFP8u3.js +++ b/assets/src_ranui_icon_index.md.DHD0uzGs.js @@ -1,4 +1,4 @@ -import{_ as p,o as r,c as E,a3 as e,j as n}from"./chunks/framework.BYE6xntm.js";const o=()=>{setTimeout(()=>{const l=["add-user","book","check-circle","close-circle","eye-close","eye","info-circle","loading","lock","message","power-off","setting","team","unlock","user"];if(typeof document<"u"){const a=document.getElementById("icon-list"),s=document.createElement("div");s.style.setProperty("display","grid"),s.style.setProperty("grid-template-columns","repeat(3, 200px)"),s.style.setProperty("grid-template-rows","repeat(3, 200px);"),l.forEach(h=>{const i=document.createElement("div");i.style.setProperty("display","flex"),i.style.setProperty("align-items","center"),i.style.setProperty("margin","15px"),i.style.setProperty("justify-content","center"),i.style.setProperty("flex-flow","column nowrap");const t=document.createElement("r-icon");t.setAttribute("name",h),t.setAttribute("size","50"),i.appendChild(t);const k=document.createElement("span");k.innerHTML=h,i.appendChild(k),s==null||s.appendChild(i)}),a==null||a.appendChild(s)}},0)};o();const y=JSON.parse('{"title":"Icon","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/icon/index.md","filePath":"src/ranui/icon/index.md","lastUpdated":1728828157000}'),d={name:"src/ranui/icon/index.md"};function g(l,a,s,h,i,t){return r(),E("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

                  Icon

                  Semantic vector graphics

                  Code demo

                  xml
                   <r-icon name="lock"  ></r-icon>
                  +import{_ as p,o as r,c as E,a3 as e,j as n}from"./chunks/framework.BYE6xntm.js";const o=()=>{setTimeout(()=>{const l=["add-user","book","check-circle","close-circle","eye-close","eye","info-circle","loading","lock","message","power-off","setting","team","unlock","user"];if(typeof document<"u"){const a=document.getElementById("icon-list"),s=document.createElement("div");s.style.setProperty("display","grid"),s.style.setProperty("grid-template-columns","repeat(3, 200px)"),s.style.setProperty("grid-template-rows","repeat(3, 200px);"),l.forEach(h=>{const i=document.createElement("div");i.style.setProperty("display","flex"),i.style.setProperty("align-items","center"),i.style.setProperty("margin","15px"),i.style.setProperty("justify-content","center"),i.style.setProperty("flex-flow","column nowrap");const t=document.createElement("r-icon");t.setAttribute("name",h),t.setAttribute("size","50"),i.appendChild(t);const k=document.createElement("span");k.innerHTML=h,i.appendChild(k),s==null||s.appendChild(i)}),a==null||a.appendChild(s)}},0)};o();const y=JSON.parse('{"title":"Icon","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/icon/index.md","filePath":"src/ranui/icon/index.md","lastUpdated":1728921295000}'),d={name:"src/ranui/icon/index.md"};function g(l,a,s,h,i,t){return r(),E("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

                  Icon

                  Semantic vector graphics

                  Code demo

                  xml
                   <r-icon name="lock"  ></r-icon>
                    <r-icon name="eye"  ></r-icon>
                    <r-icon name="user"  ></r-icon>

                  Attribute

                  name

                  Select a different icon based on the name

                  html
                  <r-icon name="lock"></r-icon>
                   <r-icon name="eye"></r-icon>
                  diff --git a/assets/src_ranui_icon_index.md.BQTFP8u3.lean.js b/assets/src_ranui_icon_index.md.DHD0uzGs.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_icon_index.md.BQTFP8u3.lean.js
                  rename to assets/src_ranui_icon_index.md.DHD0uzGs.lean.js
                  index 7638c8a55d..94ec3fb18d 100644
                  --- a/assets/src_ranui_icon_index.md.BQTFP8u3.lean.js
                  +++ b/assets/src_ranui_icon_index.md.DHD0uzGs.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as p,o as r,c as E,a3 as e,j as n}from"./chunks/framework.BYE6xntm.js";const o=()=>{setTimeout(()=>{const l=["add-user","book","check-circle","close-circle","eye-close","eye","info-circle","loading","lock","message","power-off","setting","team","unlock","user"];if(typeof document<"u"){const a=document.getElementById("icon-list"),s=document.createElement("div");s.style.setProperty("display","grid"),s.style.setProperty("grid-template-columns","repeat(3, 200px)"),s.style.setProperty("grid-template-rows","repeat(3, 200px);"),l.forEach(h=>{const i=document.createElement("div");i.style.setProperty("display","flex"),i.style.setProperty("align-items","center"),i.style.setProperty("margin","15px"),i.style.setProperty("justify-content","center"),i.style.setProperty("flex-flow","column nowrap");const t=document.createElement("r-icon");t.setAttribute("name",h),t.setAttribute("size","50"),i.appendChild(t);const k=document.createElement("span");k.innerHTML=h,i.appendChild(k),s==null||s.appendChild(i)}),a==null||a.appendChild(s)}},0)};o();const y=JSON.parse('{"title":"Icon","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/icon/index.md","filePath":"src/ranui/icon/index.md","lastUpdated":1728828157000}'),d={name:"src/ranui/icon/index.md"};function g(l,a,s,h,i,t){return r(),E("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

                  Icon

                  Semantic vector graphics

                  Code demo

                  xml
                   <r-icon name="lock"  ></r-icon>
                  +import{_ as p,o as r,c as E,a3 as e,j as n}from"./chunks/framework.BYE6xntm.js";const o=()=>{setTimeout(()=>{const l=["add-user","book","check-circle","close-circle","eye-close","eye","info-circle","loading","lock","message","power-off","setting","team","unlock","user"];if(typeof document<"u"){const a=document.getElementById("icon-list"),s=document.createElement("div");s.style.setProperty("display","grid"),s.style.setProperty("grid-template-columns","repeat(3, 200px)"),s.style.setProperty("grid-template-rows","repeat(3, 200px);"),l.forEach(h=>{const i=document.createElement("div");i.style.setProperty("display","flex"),i.style.setProperty("align-items","center"),i.style.setProperty("margin","15px"),i.style.setProperty("justify-content","center"),i.style.setProperty("flex-flow","column nowrap");const t=document.createElement("r-icon");t.setAttribute("name",h),t.setAttribute("size","50"),i.appendChild(t);const k=document.createElement("span");k.innerHTML=h,i.appendChild(k),s==null||s.appendChild(i)}),a==null||a.appendChild(s)}},0)};o();const y=JSON.parse('{"title":"Icon","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/icon/index.md","filePath":"src/ranui/icon/index.md","lastUpdated":1728921295000}'),d={name:"src/ranui/icon/index.md"};function g(l,a,s,h,i,t){return r(),E("div",{"data-pagefind-body":!0},a[0]||(a[0]=[e(`

                  Icon

                  Semantic vector graphics

                  Code demo

                  xml
                   <r-icon name="lock"  ></r-icon>
                    <r-icon name="eye"  ></r-icon>
                    <r-icon name="user"  ></r-icon>

                  Attribute

                  name

                  Select a different icon based on the name

                  html
                  <r-icon name="lock"></r-icon>
                   <r-icon name="eye"></r-icon>
                  diff --git a/assets/src_ranui_image_index.md.ntBTaVra.js b/assets/src_ranui_image_index.md.DuNw7DgW.js
                  similarity index 98%
                  rename from assets/src_ranui_image_index.md.ntBTaVra.js
                  rename to assets/src_ranui_image_index.md.DuNw7DgW.js
                  index b8c2879bb8..e304705a37 100644
                  --- a/assets/src_ranui_image_index.md.ntBTaVra.js
                  +++ b/assets/src_ranui_image_index.md.DuNw7DgW.js
                  @@ -1 +1 @@
                  -import{_ as a,o as i,c as e,a3 as E,j as g}from"./chunks/framework.BYE6xntm.js";const r=JSON.parse('{"title":"Image","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/image/index.md","filePath":"src/ranui/image/index.md","lastUpdated":1728828157000}'),Q={name:"src/ranui/image/index.md"};function s(t,A,o,n,d,h){return i(),e("div",{"data-pagefind-body":!0},A[0]||(A[0]=[E('

                  Image

                  Code demo

                  xml
                   <r-img src="" fallback=""></r-img>

                  Attribute

                  src

                  Image address

                  Image loading failurefallback

                  srcConfiguration of the picture loading failure, the bottom of the picture address, the following is the default loading failure picture

                  ',8),g("r-img",{fallback:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="},null,-1)]))}const B=a(Q,[["render",s]]);export{r as __pageData,B as default}; +import{_ as a,o as i,c as e,a3 as E,j as g}from"./chunks/framework.BYE6xntm.js";const r=JSON.parse('{"title":"Image","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/image/index.md","filePath":"src/ranui/image/index.md","lastUpdated":1728921295000}'),Q={name:"src/ranui/image/index.md"};function s(t,A,o,n,d,h){return i(),e("div",{"data-pagefind-body":!0},A[0]||(A[0]=[E('

                  Image

                  Code demo

                  xml
                   <r-img src="" fallback=""></r-img>

                  Attribute

                  src

                  Image address

                  Image loading failurefallback

                  srcConfiguration of the picture loading failure, the bottom of the picture address, the following is the default loading failure picture

                  ',8),g("r-img",{fallback:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="},null,-1)]))}const B=a(Q,[["render",s]]);export{r as __pageData,B as default}; diff --git a/assets/src_ranui_image_index.md.ntBTaVra.lean.js b/assets/src_ranui_image_index.md.DuNw7DgW.lean.js similarity index 98% rename from assets/src_ranui_image_index.md.ntBTaVra.lean.js rename to assets/src_ranui_image_index.md.DuNw7DgW.lean.js index b8c2879bb8..e304705a37 100644 --- a/assets/src_ranui_image_index.md.ntBTaVra.lean.js +++ b/assets/src_ranui_image_index.md.DuNw7DgW.lean.js @@ -1 +1 @@ -import{_ as a,o as i,c as e,a3 as E,j as g}from"./chunks/framework.BYE6xntm.js";const r=JSON.parse('{"title":"Image","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/image/index.md","filePath":"src/ranui/image/index.md","lastUpdated":1728828157000}'),Q={name:"src/ranui/image/index.md"};function s(t,A,o,n,d,h){return i(),e("div",{"data-pagefind-body":!0},A[0]||(A[0]=[E('

                  Image

                  Code demo

                  xml
                   <r-img src="" fallback=""></r-img>

                  Attribute

                  src

                  Image address

                  Image loading failurefallback

                  srcConfiguration of the picture loading failure, the bottom of the picture address, the following is the default loading failure picture

                  ',8),g("r-img",{fallback:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="},null,-1)]))}const B=a(Q,[["render",s]]);export{r as __pageData,B as default}; +import{_ as a,o as i,c as e,a3 as E,j as g}from"./chunks/framework.BYE6xntm.js";const r=JSON.parse('{"title":"Image","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/image/index.md","filePath":"src/ranui/image/index.md","lastUpdated":1728921295000}'),Q={name:"src/ranui/image/index.md"};function s(t,A,o,n,d,h){return i(),e("div",{"data-pagefind-body":!0},A[0]||(A[0]=[E('

                  Image

                  Code demo

                  xml
                   <r-img src="" fallback=""></r-img>

                  Attribute

                  src

                  Image address

                  Image loading failurefallback

                  srcConfiguration of the picture loading failure, the bottom of the picture address, the following is the default loading failure picture

                  ',8),g("r-img",{fallback:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="},null,-1)]))}const B=a(Q,[["render",s]]);export{r as __pageData,B as default}; diff --git a/assets/src_ranui_index.md.C5qoVF5Z.js b/assets/src_ranui_index.md.DftpvnGE.js similarity index 99% rename from assets/src_ranui_index.md.C5qoVF5Z.js rename to assets/src_ranui_index.md.DftpvnGE.js index 05d8f7ee55..50fe6c93df 100644 --- a/assets/src_ranui_index.md.C5qoVF5Z.js +++ b/assets/src_ranui_index.md.DftpvnGE.js @@ -1,4 +1,4 @@ -import{_ as t}from"./chunks/customElements.qitHOM3M.js";import{_ as n,o as l,c as e,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"ranui","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/index.md","filePath":"src/ranui/index.md","lastUpdated":1728828157000}'),h={name:"src/ranui/index.md"};function p(k,a,r,d,E,o){return l(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  ranui

                  Development scheme based on Web Components

                  Feature

                  1. Cross-Framework Compatibility: Works seamlessly with React, Vue, Preact, SolidJS, Svelte, and more. Integrates with any JavaScript project following W3C standards.
                  2. Pure Native Experience: No need for npm, React/Vue, or build tools. Easy to start, like using native div tags, simplifying structure and reducing learning costs.
                  3. Modular Design: Breaks systems into small, reusable components for enhanced maintainability and scalability.
                  4. Open-Source: Licensed under MIT, providing free access to all source code for personal or commercial use.
                  5. Interactive Documentation: Offers detailed, interactive documentation with live examples for efficient learning.
                  6. Type-Checking: Built on TypeScript with full type support, ensuring robust and maintainable code.
                  7. Stability and Durability: Provides exceptional stability, avoiding disruptive updates and ensuring continuous project operation.

                  Situation

                  Build Statusnpm-vnpm-dbrotlimodule formats: umd, esm

                  Usage

                  In most cases, you can use it just like a native div tag.

                  Here are some examples

                  1. html
                  2. js
                  3. jsx
                  4. vue
                  5. tsx

                  1.html

                  html
                  <script src="./ranui/dist/umd/index.umd.cjs"></script>
                  +import{_ as t}from"./chunks/customElements.qitHOM3M.js";import{_ as n,o as l,c as e,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"ranui","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/index.md","filePath":"src/ranui/index.md","lastUpdated":1728921295000}'),h={name:"src/ranui/index.md"};function p(k,a,r,d,E,o){return l(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  ranui

                  Development scheme based on Web Components

                  Feature

                  1. Cross-Framework Compatibility: Works seamlessly with React, Vue, Preact, SolidJS, Svelte, and more. Integrates with any JavaScript project following W3C standards.
                  2. Pure Native Experience: No need for npm, React/Vue, or build tools. Easy to start, like using native div tags, simplifying structure and reducing learning costs.
                  3. Modular Design: Breaks systems into small, reusable components for enhanced maintainability and scalability.
                  4. Open-Source: Licensed under MIT, providing free access to all source code for personal or commercial use.
                  5. Interactive Documentation: Offers detailed, interactive documentation with live examples for efficient learning.
                  6. Type-Checking: Built on TypeScript with full type support, ensuring robust and maintainable code.
                  7. Stability and Durability: Provides exceptional stability, avoiding disruptive updates and ensuring continuous project operation.

                  Situation

                  Build Statusnpm-vnpm-dbrotlimodule formats: umd, esm

                  Usage

                  In most cases, you can use it just like a native div tag.

                  Here are some examples

                  1. html
                  2. js
                  3. jsx
                  4. vue
                  5. tsx

                  1.html

                  html
                  <script src="./ranui/dist/umd/index.umd.cjs"></script>
                   
                   <body>
                     <r-button>Button</r-button>
                  diff --git a/assets/src_ranui_index.md.C5qoVF5Z.lean.js b/assets/src_ranui_index.md.DftpvnGE.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_index.md.C5qoVF5Z.lean.js
                  rename to assets/src_ranui_index.md.DftpvnGE.lean.js
                  index 05d8f7ee55..50fe6c93df 100644
                  --- a/assets/src_ranui_index.md.C5qoVF5Z.lean.js
                  +++ b/assets/src_ranui_index.md.DftpvnGE.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as t}from"./chunks/customElements.qitHOM3M.js";import{_ as n,o as l,c as e,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"ranui","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/index.md","filePath":"src/ranui/index.md","lastUpdated":1728828157000}'),h={name:"src/ranui/index.md"};function p(k,a,r,d,E,o){return l(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  ranui

                  Development scheme based on Web Components

                  Feature

                  1. Cross-Framework Compatibility: Works seamlessly with React, Vue, Preact, SolidJS, Svelte, and more. Integrates with any JavaScript project following W3C standards.
                  2. Pure Native Experience: No need for npm, React/Vue, or build tools. Easy to start, like using native div tags, simplifying structure and reducing learning costs.
                  3. Modular Design: Breaks systems into small, reusable components for enhanced maintainability and scalability.
                  4. Open-Source: Licensed under MIT, providing free access to all source code for personal or commercial use.
                  5. Interactive Documentation: Offers detailed, interactive documentation with live examples for efficient learning.
                  6. Type-Checking: Built on TypeScript with full type support, ensuring robust and maintainable code.
                  7. Stability and Durability: Provides exceptional stability, avoiding disruptive updates and ensuring continuous project operation.

                  Situation

                  Build Statusnpm-vnpm-dbrotlimodule formats: umd, esm

                  Usage

                  In most cases, you can use it just like a native div tag.

                  Here are some examples

                  1. html
                  2. js
                  3. jsx
                  4. vue
                  5. tsx

                  1.html

                  html
                  <script src="./ranui/dist/umd/index.umd.cjs"></script>
                  +import{_ as t}from"./chunks/customElements.qitHOM3M.js";import{_ as n,o as l,c as e,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"ranui","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/index.md","filePath":"src/ranui/index.md","lastUpdated":1728921295000}'),h={name:"src/ranui/index.md"};function p(k,a,r,d,E,o){return l(),e("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  ranui

                  Development scheme based on Web Components

                  Feature

                  1. Cross-Framework Compatibility: Works seamlessly with React, Vue, Preact, SolidJS, Svelte, and more. Integrates with any JavaScript project following W3C standards.
                  2. Pure Native Experience: No need for npm, React/Vue, or build tools. Easy to start, like using native div tags, simplifying structure and reducing learning costs.
                  3. Modular Design: Breaks systems into small, reusable components for enhanced maintainability and scalability.
                  4. Open-Source: Licensed under MIT, providing free access to all source code for personal or commercial use.
                  5. Interactive Documentation: Offers detailed, interactive documentation with live examples for efficient learning.
                  6. Type-Checking: Built on TypeScript with full type support, ensuring robust and maintainable code.
                  7. Stability and Durability: Provides exceptional stability, avoiding disruptive updates and ensuring continuous project operation.

                  Situation

                  Build Statusnpm-vnpm-dbrotlimodule formats: umd, esm

                  Usage

                  In most cases, you can use it just like a native div tag.

                  Here are some examples

                  1. html
                  2. js
                  3. jsx
                  4. vue
                  5. tsx

                  1.html

                  html
                  <script src="./ranui/dist/umd/index.umd.cjs"></script>
                   
                   <body>
                     <r-button>Button</r-button>
                  diff --git a/assets/src_ranui_input_index.md.D8sbP-uy.js b/assets/src_ranui_input_index.md.DFv44XMF.js
                  similarity index 99%
                  rename from assets/src_ranui_input_index.md.D8sbP-uy.js
                  rename to assets/src_ranui_input_index.md.DFv44XMF.js
                  index 64f0bb2748..aaef85f18b 100644
                  --- a/assets/src_ranui_input_index.md.D8sbP-uy.js
                  +++ b/assets/src_ranui_input_index.md.DFv44XMF.js
                  @@ -1,4 +1,4 @@
                  -import{_ as t}from"./chunks/input-input.MnARRJC6.js";import{_ as n,o as e,c as h,a3 as s,j as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Input","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/input/index.md","filePath":"src/ranui/input/index.md","lastUpdated":1728828157000}'),l={name:"src/ranui/input/index.md"};function p(k,a,r,d,E,o){return e(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s('

                  Input

                  Entering content via mouse or keyboard is the most basic form field packaging.

                  Code demo

                  Input field:
                  xml
                  <r-input></r-input>

                  Attribute

                  label

                  Provide an input experience similar to Metiral Design.

                  html
                  <r-input label="user"></r-input>

                  placeholder

                  Consistent with native 'placeholder'.

                  html
                  <r-input placeholder="user"></r-input>

                  disabled

                  The input box can be disabled by disabled. After disabled, the events on the button become invalid.

                  html
                  <r-input label="user" disabled></r-input>

                  value

                  Sets or returns the value of the 'value' property of the input box.

                  type

                  Currently support 'password', 'number' these types, set will appear additional 'ui' controls.

                  Password entry field

                  The password can be switched between plain text and ciphertext.

                  html
                  <r-input icon="lock" type="password"></r-input>

                  icon

                  You can set an 'icon' to represent the tag identifier.

                  html
                  <r-input icon="user"></r-input>

                  Digital input box

                  Numeric input box, similar to the native 'input[type=number]', support 'min', 'max', 'step' attributes, support keyboard up and down keys to switch numbers.

                  html
                  <r-input type="number" min="-10" max="10" step="0.5"></r-input>

                  name

                  Valid when associated with the form component, the field name collected when the form is submitted

                  status

                  • error

                  Default color value: #ff4d4f

                  ',40),i("div",null,[i("r-input",{status:"error"})],-1),s('
                  xml
                  <r-input status="error"></r-input>
                  • warning

                  Default color value:#ff7875

                  ',3),i("div",null,[i("r-input",{status:"warning"})],-1),s('
                  xml
                  <r-input  status="warning"></r-input>

                  event

                  Common callback events.

                  onchange

                  Triggered when text changes.

                  ',5),i("r-input",{onchange:"console.log(this.value)"},null,-1),s(`
                  html
                  <r-input onchange="func(this.value)"></r-input>
                  js
                  const input = document.createElement('r-input');
                  +import{_ as t}from"./chunks/input-input.MnARRJC6.js";import{_ as n,o as e,c as h,a3 as s,j as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Input","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/input/index.md","filePath":"src/ranui/input/index.md","lastUpdated":1728921295000}'),l={name:"src/ranui/input/index.md"};function p(k,a,r,d,E,o){return e(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s('

                  Input

                  Entering content via mouse or keyboard is the most basic form field packaging.

                  Code demo

                  Input field:
                  xml
                  <r-input></r-input>

                  Attribute

                  label

                  Provide an input experience similar to Metiral Design.

                  html
                  <r-input label="user"></r-input>

                  placeholder

                  Consistent with native 'placeholder'.

                  html
                  <r-input placeholder="user"></r-input>

                  disabled

                  The input box can be disabled by disabled. After disabled, the events on the button become invalid.

                  html
                  <r-input label="user" disabled></r-input>

                  value

                  Sets or returns the value of the 'value' property of the input box.

                  type

                  Currently support 'password', 'number' these types, set will appear additional 'ui' controls.

                  Password entry field

                  The password can be switched between plain text and ciphertext.

                  html
                  <r-input icon="lock" type="password"></r-input>

                  icon

                  You can set an 'icon' to represent the tag identifier.

                  html
                  <r-input icon="user"></r-input>

                  Digital input box

                  Numeric input box, similar to the native 'input[type=number]', support 'min', 'max', 'step' attributes, support keyboard up and down keys to switch numbers.

                  html
                  <r-input type="number" min="-10" max="10" step="0.5"></r-input>

                  name

                  Valid when associated with the form component, the field name collected when the form is submitted

                  status

                  • error

                  Default color value: #ff4d4f

                  ',40),i("div",null,[i("r-input",{status:"error"})],-1),s('
                  xml
                  <r-input status="error"></r-input>
                  • warning

                  Default color value:#ff7875

                  ',3),i("div",null,[i("r-input",{status:"warning"})],-1),s('
                  xml
                  <r-input  status="warning"></r-input>

                  event

                  Common callback events.

                  onchange

                  Triggered when text changes.

                  ',5),i("r-input",{onchange:"console.log(this.value)"},null,-1),s(`
                  html
                  <r-input onchange="func(this.value)"></r-input>
                  js
                  const input = document.createElement('r-input');
                   input.setAttribute('label', 'home');
                   const func = (e) => {
                     console.log(e);
                  diff --git a/assets/src_ranui_input_index.md.D8sbP-uy.lean.js b/assets/src_ranui_input_index.md.DFv44XMF.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_input_index.md.D8sbP-uy.lean.js
                  rename to assets/src_ranui_input_index.md.DFv44XMF.lean.js
                  index 64f0bb2748..aaef85f18b 100644
                  --- a/assets/src_ranui_input_index.md.D8sbP-uy.lean.js
                  +++ b/assets/src_ranui_input_index.md.DFv44XMF.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as t}from"./chunks/input-input.MnARRJC6.js";import{_ as n,o as e,c as h,a3 as s,j as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Input","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/input/index.md","filePath":"src/ranui/input/index.md","lastUpdated":1728828157000}'),l={name:"src/ranui/input/index.md"};function p(k,a,r,d,E,o){return e(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s('

                  Input

                  Entering content via mouse or keyboard is the most basic form field packaging.

                  Code demo

                  Input field:
                  xml
                  <r-input></r-input>

                  Attribute

                  label

                  Provide an input experience similar to Metiral Design.

                  html
                  <r-input label="user"></r-input>

                  placeholder

                  Consistent with native 'placeholder'.

                  html
                  <r-input placeholder="user"></r-input>

                  disabled

                  The input box can be disabled by disabled. After disabled, the events on the button become invalid.

                  html
                  <r-input label="user" disabled></r-input>

                  value

                  Sets or returns the value of the 'value' property of the input box.

                  type

                  Currently support 'password', 'number' these types, set will appear additional 'ui' controls.

                  Password entry field

                  The password can be switched between plain text and ciphertext.

                  html
                  <r-input icon="lock" type="password"></r-input>

                  icon

                  You can set an 'icon' to represent the tag identifier.

                  html
                  <r-input icon="user"></r-input>

                  Digital input box

                  Numeric input box, similar to the native 'input[type=number]', support 'min', 'max', 'step' attributes, support keyboard up and down keys to switch numbers.

                  html
                  <r-input type="number" min="-10" max="10" step="0.5"></r-input>

                  name

                  Valid when associated with the form component, the field name collected when the form is submitted

                  status

                  • error

                  Default color value: #ff4d4f

                  ',40),i("div",null,[i("r-input",{status:"error"})],-1),s('
                  xml
                  <r-input status="error"></r-input>
                  • warning

                  Default color value:#ff7875

                  ',3),i("div",null,[i("r-input",{status:"warning"})],-1),s('
                  xml
                  <r-input  status="warning"></r-input>

                  event

                  Common callback events.

                  onchange

                  Triggered when text changes.

                  ',5),i("r-input",{onchange:"console.log(this.value)"},null,-1),s(`
                  html
                  <r-input onchange="func(this.value)"></r-input>
                  js
                  const input = document.createElement('r-input');
                  +import{_ as t}from"./chunks/input-input.MnARRJC6.js";import{_ as n,o as e,c as h,a3 as s,j as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"Input","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/input/index.md","filePath":"src/ranui/input/index.md","lastUpdated":1728921295000}'),l={name:"src/ranui/input/index.md"};function p(k,a,r,d,E,o){return e(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s('

                  Input

                  Entering content via mouse or keyboard is the most basic form field packaging.

                  Code demo

                  Input field:
                  xml
                  <r-input></r-input>

                  Attribute

                  label

                  Provide an input experience similar to Metiral Design.

                  html
                  <r-input label="user"></r-input>

                  placeholder

                  Consistent with native 'placeholder'.

                  html
                  <r-input placeholder="user"></r-input>

                  disabled

                  The input box can be disabled by disabled. After disabled, the events on the button become invalid.

                  html
                  <r-input label="user" disabled></r-input>

                  value

                  Sets or returns the value of the 'value' property of the input box.

                  type

                  Currently support 'password', 'number' these types, set will appear additional 'ui' controls.

                  Password entry field

                  The password can be switched between plain text and ciphertext.

                  html
                  <r-input icon="lock" type="password"></r-input>

                  icon

                  You can set an 'icon' to represent the tag identifier.

                  html
                  <r-input icon="user"></r-input>

                  Digital input box

                  Numeric input box, similar to the native 'input[type=number]', support 'min', 'max', 'step' attributes, support keyboard up and down keys to switch numbers.

                  html
                  <r-input type="number" min="-10" max="10" step="0.5"></r-input>

                  name

                  Valid when associated with the form component, the field name collected when the form is submitted

                  status

                  • error

                  Default color value: #ff4d4f

                  ',40),i("div",null,[i("r-input",{status:"error"})],-1),s('
                  xml
                  <r-input status="error"></r-input>
                  • warning

                  Default color value:#ff7875

                  ',3),i("div",null,[i("r-input",{status:"warning"})],-1),s('
                  xml
                  <r-input  status="warning"></r-input>

                  event

                  Common callback events.

                  onchange

                  Triggered when text changes.

                  ',5),i("r-input",{onchange:"console.log(this.value)"},null,-1),s(`
                  html
                  <r-input onchange="func(this.value)"></r-input>
                  js
                  const input = document.createElement('r-input');
                   input.setAttribute('label', 'home');
                   const func = (e) => {
                     console.log(e);
                  diff --git a/assets/src_ranui_loading_index.md.iV1VL5bO.js b/assets/src_ranui_loading_index.md.EajM1Fh_.js
                  similarity index 98%
                  rename from assets/src_ranui_loading_index.md.iV1VL5bO.js
                  rename to assets/src_ranui_loading_index.md.EajM1Fh_.js
                  index 4f36115f85..2f2e0e24f2 100644
                  --- a/assets/src_ranui_loading_index.md.iV1VL5bO.js
                  +++ b/assets/src_ranui_loading_index.md.EajM1Fh_.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a}from"./chunks/loading.vue_vue_type_style_index_0_lang.DqjXTuVA.js";import{o as s,c as t,a3 as n,G as l}from"./chunks/framework.BYE6xntm.js";import"./chunks/index.h_46bJa8.js";const o=JSON.parse('{"title":"Loading","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/loading/index.md","filePath":"src/ranui/loading/index.md","lastUpdated":1728828157000}'),e={name:"src/ranui/loading/index.md"},g=Object.assign(e,{setup(h){return(d,i)=>(s(),t("div",{"data-pagefind-body":!0},[i[0]||(i[0]=n(`

                  Loading

                  Some nice looking loading.

                  Code demo

                  xml
                  <r-loading name="circle"></r-loading>

                  Attribute

                  name

                  There's a lot of different loading here

                  xml
                  <r-loading name="double-bounce"></r-loading>
                  +import{_ as a}from"./chunks/loading.vue_vue_type_style_index_0_lang.DqjXTuVA.js";import{o as s,c as t,a3 as n,G as l}from"./chunks/framework.BYE6xntm.js";import"./chunks/index.h_46bJa8.js";const o=JSON.parse('{"title":"Loading","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/loading/index.md","filePath":"src/ranui/loading/index.md","lastUpdated":1728921295000}'),e={name:"src/ranui/loading/index.md"},g=Object.assign(e,{setup(h){return(d,i)=>(s(),t("div",{"data-pagefind-body":!0},[i[0]||(i[0]=n(`

                  Loading

                  Some nice looking loading.

                  Code demo

                  xml
                  <r-loading name="circle"></r-loading>

                  Attribute

                  name

                  There's a lot of different loading here

                  xml
                  <r-loading name="double-bounce"></r-loading>
                   <r-loading name="rotate"></r-loading>
                   <r-loading name="stretch"></r-loading>
                   <r-loading name="cube"></r-loading>

                  Loading list

                  `,14)),l(a)]))}});export{o as __pageData,g as default}; diff --git a/assets/src_ranui_loading_index.md.iV1VL5bO.lean.js b/assets/src_ranui_loading_index.md.EajM1Fh_.lean.js similarity index 98% rename from assets/src_ranui_loading_index.md.iV1VL5bO.lean.js rename to assets/src_ranui_loading_index.md.EajM1Fh_.lean.js index 4f36115f85..2f2e0e24f2 100644 --- a/assets/src_ranui_loading_index.md.iV1VL5bO.lean.js +++ b/assets/src_ranui_loading_index.md.EajM1Fh_.lean.js @@ -1,4 +1,4 @@ -import{_ as a}from"./chunks/loading.vue_vue_type_style_index_0_lang.DqjXTuVA.js";import{o as s,c as t,a3 as n,G as l}from"./chunks/framework.BYE6xntm.js";import"./chunks/index.h_46bJa8.js";const o=JSON.parse('{"title":"Loading","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/loading/index.md","filePath":"src/ranui/loading/index.md","lastUpdated":1728828157000}'),e={name:"src/ranui/loading/index.md"},g=Object.assign(e,{setup(h){return(d,i)=>(s(),t("div",{"data-pagefind-body":!0},[i[0]||(i[0]=n(`

                  Loading

                  Some nice looking loading.

                  Code demo

                  xml
                  <r-loading name="circle"></r-loading>

                  Attribute

                  name

                  There's a lot of different loading here

                  xml
                  <r-loading name="double-bounce"></r-loading>
                  +import{_ as a}from"./chunks/loading.vue_vue_type_style_index_0_lang.DqjXTuVA.js";import{o as s,c as t,a3 as n,G as l}from"./chunks/framework.BYE6xntm.js";import"./chunks/index.h_46bJa8.js";const o=JSON.parse('{"title":"Loading","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/loading/index.md","filePath":"src/ranui/loading/index.md","lastUpdated":1728921295000}'),e={name:"src/ranui/loading/index.md"},g=Object.assign(e,{setup(h){return(d,i)=>(s(),t("div",{"data-pagefind-body":!0},[i[0]||(i[0]=n(`

                  Loading

                  Some nice looking loading.

                  Code demo

                  xml
                  <r-loading name="circle"></r-loading>

                  Attribute

                  name

                  There's a lot of different loading here

                  xml
                  <r-loading name="double-bounce"></r-loading>
                   <r-loading name="rotate"></r-loading>
                   <r-loading name="stretch"></r-loading>
                   <r-loading name="cube"></r-loading>

                  Loading list

                  `,14)),l(a)]))}});export{o as __pageData,g as default}; diff --git a/assets/src_ranui_math_index.md.BJRXy7dX.js b/assets/src_ranui_math_index.md.BX7dsUxQ.js similarity index 97% rename from assets/src_ranui_math_index.md.BJRXy7dX.js rename to assets/src_ranui_math_index.md.BX7dsUxQ.js index f197405bb7..f339f9f769 100644 --- a/assets/src_ranui_math_index.md.BJRXy7dX.js +++ b/assets/src_ranui_math_index.md.BX7dsUxQ.js @@ -1 +1 @@ -import{_ as e,o as l,c as h,j as a,a as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"math","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/math/index.md","filePath":"src/ranui/math/index.md","lastUpdated":1728828157000}'),n={name:"src/ranui/math/index.md"};function r(d,t,p,o,k,c){return l(),h("div",{"data-pagefind-body":!0},t[0]||(t[0]=[a("h1",{id:"math",tabindex:"-1"},[s("math "),a("a",{class:"header-anchor",href:"#math","aria-label":'Permalink to "math"'},"​")],-1),a("p",null,"High-quality display of LaTeX in HTML pages",-1),a("h2",{id:"code-demo",tabindex:"-1"},[s("Code demo "),a("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),a("r-math",{latex:"\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"},null,-1),i('
                  xml
                  <r-math latex="\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"></r-math>

                  Attribute

                  latex string

                  ',3),a("r-math",{latex:"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"},null,-1),i('
                  xml
                    <r-math latex="x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"></r-math>
                  ',1)]))}const E=e(n,[["render",r]]);export{m as __pageData,E as default}; +import{_ as e,o as l,c as h,j as a,a as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"math","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/math/index.md","filePath":"src/ranui/math/index.md","lastUpdated":1728921295000}'),n={name:"src/ranui/math/index.md"};function r(d,t,p,o,k,c){return l(),h("div",{"data-pagefind-body":!0},t[0]||(t[0]=[a("h1",{id:"math",tabindex:"-1"},[s("math "),a("a",{class:"header-anchor",href:"#math","aria-label":'Permalink to "math"'},"​")],-1),a("p",null,"High-quality display of LaTeX in HTML pages",-1),a("h2",{id:"code-demo",tabindex:"-1"},[s("Code demo "),a("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),a("r-math",{latex:"\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"},null,-1),i('
                  xml
                  <r-math latex="\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"></r-math>

                  Attribute

                  latex string

                  ',3),a("r-math",{latex:"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"},null,-1),i('
                  xml
                    <r-math latex="x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"></r-math>
                  ',1)]))}const E=e(n,[["render",r]]);export{m as __pageData,E as default}; diff --git a/assets/src_ranui_math_index.md.BJRXy7dX.lean.js b/assets/src_ranui_math_index.md.BX7dsUxQ.lean.js similarity index 97% rename from assets/src_ranui_math_index.md.BJRXy7dX.lean.js rename to assets/src_ranui_math_index.md.BX7dsUxQ.lean.js index f197405bb7..f339f9f769 100644 --- a/assets/src_ranui_math_index.md.BJRXy7dX.lean.js +++ b/assets/src_ranui_math_index.md.BX7dsUxQ.lean.js @@ -1 +1 @@ -import{_ as e,o as l,c as h,j as a,a as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"math","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/math/index.md","filePath":"src/ranui/math/index.md","lastUpdated":1728828157000}'),n={name:"src/ranui/math/index.md"};function r(d,t,p,o,k,c){return l(),h("div",{"data-pagefind-body":!0},t[0]||(t[0]=[a("h1",{id:"math",tabindex:"-1"},[s("math "),a("a",{class:"header-anchor",href:"#math","aria-label":'Permalink to "math"'},"​")],-1),a("p",null,"High-quality display of LaTeX in HTML pages",-1),a("h2",{id:"code-demo",tabindex:"-1"},[s("Code demo "),a("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),a("r-math",{latex:"\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"},null,-1),i('
                  xml
                  <r-math latex="\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"></r-math>

                  Attribute

                  latex string

                  ',3),a("r-math",{latex:"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"},null,-1),i('
                  xml
                    <r-math latex="x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"></r-math>
                  ',1)]))}const E=e(n,[["render",r]]);export{m as __pageData,E as default}; +import{_ as e,o as l,c as h,j as a,a as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"math","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/math/index.md","filePath":"src/ranui/math/index.md","lastUpdated":1728921295000}'),n={name:"src/ranui/math/index.md"};function r(d,t,p,o,k,c){return l(),h("div",{"data-pagefind-body":!0},t[0]||(t[0]=[a("h1",{id:"math",tabindex:"-1"},[s("math "),a("a",{class:"header-anchor",href:"#math","aria-label":'Permalink to "math"'},"​")],-1),a("p",null,"High-quality display of LaTeX in HTML pages",-1),a("h2",{id:"code-demo",tabindex:"-1"},[s("Code demo "),a("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),a("r-math",{latex:"\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"},null,-1),i('
                  xml
                  <r-math latex="\\frac{x^2}{a^2} + \\frac{y^2}{b^2} = 1 \\quad (a > b > 0)"></r-math>

                  Attribute

                  latex string

                  ',3),a("r-math",{latex:"x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"},null,-1),i('
                  xml
                    <r-math latex="x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}"></r-math>
                  ',1)]))}const E=e(n,[["render",r]]);export{m as __pageData,E as default}; diff --git a/assets/src_ranui_message_index.md.C7vn1gHP.js b/assets/src_ranui_message_index.md.DpTwiP3x.js similarity index 99% rename from assets/src_ranui_message_index.md.C7vn1gHP.js rename to assets/src_ranui_message_index.md.DpTwiP3x.js index e56816b8ca..f28cfbe4a6 100644 --- a/assets/src_ranui_message_index.md.C7vn1gHP.js +++ b/assets/src_ranui_message_index.md.DpTwiP3x.js @@ -1,4 +1,4 @@ -import{_ as e,o as n,c as h,j as s,a as t,a3 as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"message","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/message/index.md","filePath":"src/ranui/message/index.md","lastUpdated":1728828157000}'),l={name:"src/ranui/message/index.md"};function p(o,i,k,r,d,g){return n(),h("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"message",tabindex:"-1"},[t("message "),s("a",{class:"header-anchor",href:"#message","aria-label":'Permalink to "message"'},"​")],-1),s("p",null,"Global display of operation feedback.",-1),s("h2",{id:"code-demo",tabindex:"-1"},[t("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{type:"primary",onclick:"message.info('This is a hint')"},"Click to trigger the global prompt")],-1),a('
                  xml
                  <r-button type="primary" onclick="message.info('This is a hint')">Click to trigger the global prompt</r-button>

                  Attribute

                  type

                  Different prompt types

                  ',4),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.info('This is a hint')"},"Information prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.warning('This is a hint')"},"Warning prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.error('This is a hint')"},"Error prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.success('This is a hint')"},"Success tip")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.toast('This is a hint')"},"toast tip")],-1),a(`
                  html
                  <r-button onclick="message.info('This is a hint')">Information prompt</r-button>
                  +import{_ as e,o as n,c as h,j as s,a as t,a3 as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"message","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/message/index.md","filePath":"src/ranui/message/index.md","lastUpdated":1728921295000}'),l={name:"src/ranui/message/index.md"};function p(o,i,k,r,d,g){return n(),h("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"message",tabindex:"-1"},[t("message "),s("a",{class:"header-anchor",href:"#message","aria-label":'Permalink to "message"'},"​")],-1),s("p",null,"Global display of operation feedback.",-1),s("h2",{id:"code-demo",tabindex:"-1"},[t("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{type:"primary",onclick:"message.info('This is a hint')"},"Click to trigger the global prompt")],-1),a('
                  xml
                  <r-button type="primary" onclick="message.info('This is a hint')">Click to trigger the global prompt</r-button>

                  Attribute

                  type

                  Different prompt types

                  ',4),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.info('This is a hint')"},"Information prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.warning('This is a hint')"},"Warning prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.error('This is a hint')"},"Error prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.success('This is a hint')"},"Success tip")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.toast('This is a hint')"},"toast tip")],-1),a(`
                  html
                  <r-button onclick="message.info('This is a hint')">Information prompt</r-button>
                   <r-button onclick="message.warning('This is a hint')">Warning prompt</r-button>
                   <r-button onclick="message.error('This is a hint')">Error prompt</r-button>
                   <r-button onclick="message.success('This is a hint')">Success tip</r-button>
                  diff --git a/assets/src_ranui_message_index.md.C7vn1gHP.lean.js b/assets/src_ranui_message_index.md.DpTwiP3x.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_message_index.md.C7vn1gHP.lean.js
                  rename to assets/src_ranui_message_index.md.DpTwiP3x.lean.js
                  index e56816b8ca..f28cfbe4a6 100644
                  --- a/assets/src_ranui_message_index.md.C7vn1gHP.lean.js
                  +++ b/assets/src_ranui_message_index.md.DpTwiP3x.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as e,o as n,c as h,j as s,a as t,a3 as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"message","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/message/index.md","filePath":"src/ranui/message/index.md","lastUpdated":1728828157000}'),l={name:"src/ranui/message/index.md"};function p(o,i,k,r,d,g){return n(),h("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"message",tabindex:"-1"},[t("message "),s("a",{class:"header-anchor",href:"#message","aria-label":'Permalink to "message"'},"​")],-1),s("p",null,"Global display of operation feedback.",-1),s("h2",{id:"code-demo",tabindex:"-1"},[t("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{type:"primary",onclick:"message.info('This is a hint')"},"Click to trigger the global prompt")],-1),a('
                  xml
                  <r-button type="primary" onclick="message.info('This is a hint')">Click to trigger the global prompt</r-button>

                  Attribute

                  type

                  Different prompt types

                  ',4),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.info('This is a hint')"},"Information prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.warning('This is a hint')"},"Warning prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.error('This is a hint')"},"Error prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.success('This is a hint')"},"Success tip")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.toast('This is a hint')"},"toast tip")],-1),a(`
                  html
                  <r-button onclick="message.info('This is a hint')">Information prompt</r-button>
                  +import{_ as e,o as n,c as h,j as s,a as t,a3 as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"message","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/message/index.md","filePath":"src/ranui/message/index.md","lastUpdated":1728921295000}'),l={name:"src/ranui/message/index.md"};function p(o,i,k,r,d,g){return n(),h("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"message",tabindex:"-1"},[t("message "),s("a",{class:"header-anchor",href:"#message","aria-label":'Permalink to "message"'},"​")],-1),s("p",null,"Global display of operation feedback.",-1),s("h2",{id:"code-demo",tabindex:"-1"},[t("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{type:"primary",onclick:"message.info('This is a hint')"},"Click to trigger the global prompt")],-1),a('
                  xml
                  <r-button type="primary" onclick="message.info('This is a hint')">Click to trigger the global prompt</r-button>

                  Attribute

                  type

                  Different prompt types

                  ',4),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.info('This is a hint')"},"Information prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.warning('This is a hint')"},"Warning prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.error('This is a hint')"},"Error prompt")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.success('This is a hint')"},"Success tip")],-1),s("div",{style:{display:"inline-block","margin-right":"8px","margin-bottom":"12px"}},[s("r-button",{onclick:"message.toast('This is a hint')"},"toast tip")],-1),a(`
                  html
                  <r-button onclick="message.info('This is a hint')">Information prompt</r-button>
                   <r-button onclick="message.warning('This is a hint')">Warning prompt</r-button>
                   <r-button onclick="message.error('This is a hint')">Error prompt</r-button>
                   <r-button onclick="message.success('This is a hint')">Success tip</r-button>
                  diff --git a/assets/src_ranui_modal_index.md.DEMwPGEr.js b/assets/src_ranui_modal_index.md.BfBNxpQt.js
                  similarity index 84%
                  rename from assets/src_ranui_modal_index.md.DEMwPGEr.js
                  rename to assets/src_ranui_modal_index.md.BfBNxpQt.js
                  index 9901bd42c9..d7b7deca88 100644
                  --- a/assets/src_ranui_modal_index.md.DEMwPGEr.js
                  +++ b/assets/src_ranui_modal_index.md.BfBNxpQt.js
                  @@ -1 +1 @@
                  -import{_ as e,o as a,c as t}from"./chunks/framework.BYE6xntm.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/modal/index.md","filePath":"src/ranui/modal/index.md","lastUpdated":1728828157000}'),r={name:"src/ranui/modal/index.md"};function n(o,s,d,c,i,m){return a(),t("div")}const _=e(r,[["render",n]]);export{l as __pageData,_ as default};
                  +import{_ as e,o as a,c as t}from"./chunks/framework.BYE6xntm.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/modal/index.md","filePath":"src/ranui/modal/index.md","lastUpdated":1728921295000}'),r={name:"src/ranui/modal/index.md"};function n(o,s,d,c,i,m){return a(),t("div")}const _=e(r,[["render",n]]);export{l as __pageData,_ as default};
                  diff --git a/assets/src_ranui_modal_index.md.DEMwPGEr.lean.js b/assets/src_ranui_modal_index.md.BfBNxpQt.lean.js
                  similarity index 84%
                  rename from assets/src_ranui_modal_index.md.DEMwPGEr.lean.js
                  rename to assets/src_ranui_modal_index.md.BfBNxpQt.lean.js
                  index 9901bd42c9..d7b7deca88 100644
                  --- a/assets/src_ranui_modal_index.md.DEMwPGEr.lean.js
                  +++ b/assets/src_ranui_modal_index.md.BfBNxpQt.lean.js
                  @@ -1 +1 @@
                  -import{_ as e,o as a,c as t}from"./chunks/framework.BYE6xntm.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/modal/index.md","filePath":"src/ranui/modal/index.md","lastUpdated":1728828157000}'),r={name:"src/ranui/modal/index.md"};function n(o,s,d,c,i,m){return a(),t("div")}const _=e(r,[["render",n]]);export{l as __pageData,_ as default};
                  +import{_ as e,o as a,c as t}from"./chunks/framework.BYE6xntm.js";const l=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/modal/index.md","filePath":"src/ranui/modal/index.md","lastUpdated":1728921295000}'),r={name:"src/ranui/modal/index.md"};function n(o,s,d,c,i,m){return a(),t("div")}const _=e(r,[["render",n]]);export{l as __pageData,_ as default};
                  diff --git a/assets/src_ranui_player_index.md.DP3RaPdA.js b/assets/src_ranui_player_index.md._41AQgcv.js
                  similarity index 99%
                  rename from assets/src_ranui_player_index.md.DP3RaPdA.js
                  rename to assets/src_ranui_player_index.md._41AQgcv.js
                  index a03d4e873b..cf06aeabfa 100644
                  --- a/assets/src_ranui_player_index.md.DP3RaPdA.js
                  +++ b/assets/src_ranui_player_index.md._41AQgcv.js
                  @@ -1 +1 @@
                  -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"r-player","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/player/index.md","filePath":"src/ranui/player/index.md","lastUpdated":1728828157000}'),i={name:"src/ranui/player/index.md"};function n(o,t,l,s,h,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  r-player

                  Video player

                  Based on 'hlsjs' and' web components', let the native tag 'r-player' have a unified video control. Do not use the 'new Player(options)' way to mount to the specified 'dom', view return view, logic return logic, see and get, more intuitive.

                  1. Drag and drop the progress bar
                  2. Volume control
                  3. The bitrate is automatically switched based on the current bandwidth
                  4. Manual definition switch
                  5. Play at double speed
                  6. Style custom overlay
                  7. 'hls' protocol standard encryption video playback
                  8. Based on native development, it can run in all frameworks and unify the cross-framework situation
                  9. Unified browser controls

                  Code demo

                  xml
                    <r-player src="/ran/hls/example.m3u8"></r-player>

                  Attribute

                  src

                  Resource address of the video

                  volume

                  Set the initial volume. The default is 0.5

                  currentTime

                  Set the initial playback time. By default, the playback starts from the beginning

                  playbackRate

                  Set the double speed. The default is 1.0

                  debug

                  console.log some info

                  event

                  onchange

                  Listen for any player changes, and the value returned is as follows.

                  An 'instance of the player' can be obtained through this method.

                  Live by 'type' to judge different event types, perform different operations

                  propertyexplains thatis of type
                  typeIndicates the type of the changed event'string'
                  dataThe value of the'Object'
                  currentTimeThe current playback time'number'
                  durationTotal duration of videos'number'
                  tagAn example of the player'Element'

                  Where 'type' type has

                  NameDescription
                  canplayYour browser is ready to play the media file, but it probably doesn't have enough data to play it to the end without pausing to buffer the content further.
                  canplaythroughThe browser estimates that it canplay media until the end without stopping content buffering.
                  completeOfflineAudioContext The rendering is complete.
                  durationchangeduration is triggered when the value of the duration property changes.
                  emptiedMedia content emptied; For example, when the media is already loaded (or partially loaded), this event is sent and the load() method is called to reload it.
                  endedThe video stops playing because the media has reached the end point.
                  loadedmetadataThe metadata is loaded.
                  progressis triggered periodically when the browser loads the resource.
                  ratechangeThe play rate changes.
                  seekedThe seek operation is complete.
                  seekingseek begins.
                  stalledThe user agent is trying to obtain media data but it has not appeared unexpectedly.
                  suspendMedia data loading has been suspended.
                  loadeddataThe first frame in media has been added. media has loaded.
                  timeupdateThe time specified by the currentTime property changes. currentTime attribute has changed.
                  volumechangeThe volume changes.
                  waitingPlaying has stopped due to lack of data.
                  playPlayback has started.
                  playingAfter a pause or delay due to lack of data, playback is ready to begin.
                  pausePlay is paused.
                  volumeThe volume changes.
                  fullscreenTriggers a full-screen event
                  ',26)]))}const m=e(i,[["render",n]]);export{u as __pageData,m as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"r-player","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/player/index.md","filePath":"src/ranui/player/index.md","lastUpdated":1728921295000}'),i={name:"src/ranui/player/index.md"};function n(o,t,l,s,h,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  r-player

                  Video player

                  Based on 'hlsjs' and' web components', let the native tag 'r-player' have a unified video control. Do not use the 'new Player(options)' way to mount to the specified 'dom', view return view, logic return logic, see and get, more intuitive.

                  1. Drag and drop the progress bar
                  2. Volume control
                  3. The bitrate is automatically switched based on the current bandwidth
                  4. Manual definition switch
                  5. Play at double speed
                  6. Style custom overlay
                  7. 'hls' protocol standard encryption video playback
                  8. Based on native development, it can run in all frameworks and unify the cross-framework situation
                  9. Unified browser controls

                  Code demo

                  xml
                    <r-player src="/ran/hls/example.m3u8"></r-player>

                  Attribute

                  src

                  Resource address of the video

                  volume

                  Set the initial volume. The default is 0.5

                  currentTime

                  Set the initial playback time. By default, the playback starts from the beginning

                  playbackRate

                  Set the double speed. The default is 1.0

                  debug

                  console.log some info

                  event

                  onchange

                  Listen for any player changes, and the value returned is as follows.

                  An 'instance of the player' can be obtained through this method.

                  Live by 'type' to judge different event types, perform different operations

                  propertyexplains thatis of type
                  typeIndicates the type of the changed event'string'
                  dataThe value of the'Object'
                  currentTimeThe current playback time'number'
                  durationTotal duration of videos'number'
                  tagAn example of the player'Element'

                  Where 'type' type has

                  NameDescription
                  canplayYour browser is ready to play the media file, but it probably doesn't have enough data to play it to the end without pausing to buffer the content further.
                  canplaythroughThe browser estimates that it canplay media until the end without stopping content buffering.
                  completeOfflineAudioContext The rendering is complete.
                  durationchangeduration is triggered when the value of the duration property changes.
                  emptiedMedia content emptied; For example, when the media is already loaded (or partially loaded), this event is sent and the load() method is called to reload it.
                  endedThe video stops playing because the media has reached the end point.
                  loadedmetadataThe metadata is loaded.
                  progressis triggered periodically when the browser loads the resource.
                  ratechangeThe play rate changes.
                  seekedThe seek operation is complete.
                  seekingseek begins.
                  stalledThe user agent is trying to obtain media data but it has not appeared unexpectedly.
                  suspendMedia data loading has been suspended.
                  loadeddataThe first frame in media has been added. media has loaded.
                  timeupdateThe time specified by the currentTime property changes. currentTime attribute has changed.
                  volumechangeThe volume changes.
                  waitingPlaying has stopped due to lack of data.
                  playPlayback has started.
                  playingAfter a pause or delay due to lack of data, playback is ready to begin.
                  pausePlay is paused.
                  volumeThe volume changes.
                  fullscreenTriggers a full-screen event
                  ',26)]))}const m=e(i,[["render",n]]);export{u as __pageData,m as default}; diff --git a/assets/src_ranui_player_index.md.DP3RaPdA.lean.js b/assets/src_ranui_player_index.md._41AQgcv.lean.js similarity index 99% rename from assets/src_ranui_player_index.md.DP3RaPdA.lean.js rename to assets/src_ranui_player_index.md._41AQgcv.lean.js index a03d4e873b..cf06aeabfa 100644 --- a/assets/src_ranui_player_index.md.DP3RaPdA.lean.js +++ b/assets/src_ranui_player_index.md._41AQgcv.lean.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"r-player","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/player/index.md","filePath":"src/ranui/player/index.md","lastUpdated":1728828157000}'),i={name:"src/ranui/player/index.md"};function n(o,t,l,s,h,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  r-player

                  Video player

                  Based on 'hlsjs' and' web components', let the native tag 'r-player' have a unified video control. Do not use the 'new Player(options)' way to mount to the specified 'dom', view return view, logic return logic, see and get, more intuitive.

                  1. Drag and drop the progress bar
                  2. Volume control
                  3. The bitrate is automatically switched based on the current bandwidth
                  4. Manual definition switch
                  5. Play at double speed
                  6. Style custom overlay
                  7. 'hls' protocol standard encryption video playback
                  8. Based on native development, it can run in all frameworks and unify the cross-framework situation
                  9. Unified browser controls

                  Code demo

                  xml
                    <r-player src="/ran/hls/example.m3u8"></r-player>

                  Attribute

                  src

                  Resource address of the video

                  volume

                  Set the initial volume. The default is 0.5

                  currentTime

                  Set the initial playback time. By default, the playback starts from the beginning

                  playbackRate

                  Set the double speed. The default is 1.0

                  debug

                  console.log some info

                  event

                  onchange

                  Listen for any player changes, and the value returned is as follows.

                  An 'instance of the player' can be obtained through this method.

                  Live by 'type' to judge different event types, perform different operations

                  propertyexplains thatis of type
                  typeIndicates the type of the changed event'string'
                  dataThe value of the'Object'
                  currentTimeThe current playback time'number'
                  durationTotal duration of videos'number'
                  tagAn example of the player'Element'

                  Where 'type' type has

                  NameDescription
                  canplayYour browser is ready to play the media file, but it probably doesn't have enough data to play it to the end without pausing to buffer the content further.
                  canplaythroughThe browser estimates that it canplay media until the end without stopping content buffering.
                  completeOfflineAudioContext The rendering is complete.
                  durationchangeduration is triggered when the value of the duration property changes.
                  emptiedMedia content emptied; For example, when the media is already loaded (or partially loaded), this event is sent and the load() method is called to reload it.
                  endedThe video stops playing because the media has reached the end point.
                  loadedmetadataThe metadata is loaded.
                  progressis triggered periodically when the browser loads the resource.
                  ratechangeThe play rate changes.
                  seekedThe seek operation is complete.
                  seekingseek begins.
                  stalledThe user agent is trying to obtain media data but it has not appeared unexpectedly.
                  suspendMedia data loading has been suspended.
                  loadeddataThe first frame in media has been added. media has loaded.
                  timeupdateThe time specified by the currentTime property changes. currentTime attribute has changed.
                  volumechangeThe volume changes.
                  waitingPlaying has stopped due to lack of data.
                  playPlayback has started.
                  playingAfter a pause or delay due to lack of data, playback is ready to begin.
                  pausePlay is paused.
                  volumeThe volume changes.
                  fullscreenTriggers a full-screen event
                  ',26)]))}const m=e(i,[["render",n]]);export{u as __pageData,m as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"r-player","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/player/index.md","filePath":"src/ranui/player/index.md","lastUpdated":1728921295000}'),i={name:"src/ranui/player/index.md"};function n(o,t,l,s,h,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  r-player

                  Video player

                  Based on 'hlsjs' and' web components', let the native tag 'r-player' have a unified video control. Do not use the 'new Player(options)' way to mount to the specified 'dom', view return view, logic return logic, see and get, more intuitive.

                  1. Drag and drop the progress bar
                  2. Volume control
                  3. The bitrate is automatically switched based on the current bandwidth
                  4. Manual definition switch
                  5. Play at double speed
                  6. Style custom overlay
                  7. 'hls' protocol standard encryption video playback
                  8. Based on native development, it can run in all frameworks and unify the cross-framework situation
                  9. Unified browser controls

                  Code demo

                  xml
                    <r-player src="/ran/hls/example.m3u8"></r-player>

                  Attribute

                  src

                  Resource address of the video

                  volume

                  Set the initial volume. The default is 0.5

                  currentTime

                  Set the initial playback time. By default, the playback starts from the beginning

                  playbackRate

                  Set the double speed. The default is 1.0

                  debug

                  console.log some info

                  event

                  onchange

                  Listen for any player changes, and the value returned is as follows.

                  An 'instance of the player' can be obtained through this method.

                  Live by 'type' to judge different event types, perform different operations

                  propertyexplains thatis of type
                  typeIndicates the type of the changed event'string'
                  dataThe value of the'Object'
                  currentTimeThe current playback time'number'
                  durationTotal duration of videos'number'
                  tagAn example of the player'Element'

                  Where 'type' type has

                  NameDescription
                  canplayYour browser is ready to play the media file, but it probably doesn't have enough data to play it to the end without pausing to buffer the content further.
                  canplaythroughThe browser estimates that it canplay media until the end without stopping content buffering.
                  completeOfflineAudioContext The rendering is complete.
                  durationchangeduration is triggered when the value of the duration property changes.
                  emptiedMedia content emptied; For example, when the media is already loaded (or partially loaded), this event is sent and the load() method is called to reload it.
                  endedThe video stops playing because the media has reached the end point.
                  loadedmetadataThe metadata is loaded.
                  progressis triggered periodically when the browser loads the resource.
                  ratechangeThe play rate changes.
                  seekedThe seek operation is complete.
                  seekingseek begins.
                  stalledThe user agent is trying to obtain media data but it has not appeared unexpectedly.
                  suspendMedia data loading has been suspended.
                  loadeddataThe first frame in media has been added. media has loaded.
                  timeupdateThe time specified by the currentTime property changes. currentTime attribute has changed.
                  volumechangeThe volume changes.
                  waitingPlaying has stopped due to lack of data.
                  playPlayback has started.
                  playingAfter a pause or delay due to lack of data, playback is ready to begin.
                  pausePlay is paused.
                  volumeThe volume changes.
                  fullscreenTriggers a full-screen event
                  ',26)]))}const m=e(i,[["render",n]]);export{u as __pageData,m as default}; diff --git a/assets/src_ranui_popover_index.md.CfxjwwU_.js b/assets/src_ranui_popover_index.md.Bq9gtddN.js similarity index 99% rename from assets/src_ranui_popover_index.md.CfxjwwU_.js rename to assets/src_ranui_popover_index.md.Bq9gtddN.js index b0385d7c34..8027bc8565 100644 --- a/assets/src_ranui_popover_index.md.CfxjwwU_.js +++ b/assets/src_ranui_popover_index.md.Bq9gtddN.js @@ -1,4 +1,4 @@ -import{_ as t,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Popover","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/popover/index.md","filePath":"src/ranui/popover/index.md","lastUpdated":1728828157000}'),h={name:"src/ranui/popover/index.md"};function p(k,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Popover

                  Click/mouse to move into the element and pop up a bubbling card layer.

                  Code demo

                  popover
                  this is content
                  xml
                  <r-popover>
                  +import{_ as t,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Popover","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/popover/index.md","filePath":"src/ranui/popover/index.md","lastUpdated":1728921295000}'),h={name:"src/ranui/popover/index.md"};function p(k,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Popover

                  Click/mouse to move into the element and pop up a bubbling card layer.

                  Code demo

                  popover
                  this is content
                  xml
                  <r-popover>
                       <r-button>popover</r-button>
                       <r-content>
                         <div>this is content</div>
                  diff --git a/assets/src_ranui_popover_index.md.CfxjwwU_.lean.js b/assets/src_ranui_popover_index.md.Bq9gtddN.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_popover_index.md.CfxjwwU_.lean.js
                  rename to assets/src_ranui_popover_index.md.Bq9gtddN.lean.js
                  index b0385d7c34..8027bc8565 100644
                  --- a/assets/src_ranui_popover_index.md.CfxjwwU_.lean.js
                  +++ b/assets/src_ranui_popover_index.md.Bq9gtddN.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as t,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Popover","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/popover/index.md","filePath":"src/ranui/popover/index.md","lastUpdated":1728828157000}'),h={name:"src/ranui/popover/index.md"};function p(k,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Popover

                  Click/mouse to move into the element and pop up a bubbling card layer.

                  Code demo

                  popover
                  this is content
                  xml
                  <r-popover>
                  +import{_ as t,o as n,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"Popover","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/popover/index.md","filePath":"src/ranui/popover/index.md","lastUpdated":1728921295000}'),h={name:"src/ranui/popover/index.md"};function p(k,a,e,E,r,d){return n(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Popover

                  Click/mouse to move into the element and pop up a bubbling card layer.

                  Code demo

                  popover
                  this is content
                  xml
                  <r-popover>
                       <r-button>popover</r-button>
                       <r-content>
                         <div>this is content</div>
                  diff --git a/assets/src_ranui_preview_index.md.fG1IQRia.js b/assets/src_ranui_preview_index.md.tg6oXUar.js
                  similarity index 99%
                  rename from assets/src_ranui_preview_index.md.fG1IQRia.js
                  rename to assets/src_ranui_preview_index.md.tg6oXUar.js
                  index 40c15e6151..3e0b275f7c 100644
                  --- a/assets/src_ranui_preview_index.md.fG1IQRia.js
                  +++ b/assets/src_ranui_preview_index.md.tg6oXUar.js
                  @@ -1,4 +1,4 @@
                  -import{_ as t,o as h,c as n,j as s,a,a3 as l}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"preview","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/preview/index.md","filePath":"src/ranui/preview/index.md","lastUpdated":1728828157000}'),e={name:"src/ranui/preview/index.md"};function p(k,i,E,r,d,g){return h(),n("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"preview",tabindex:"-1"},[a("preview "),s("a",{class:"header-anchor",href:"#preview","aria-label":'Permalink to "preview"'},"​")],-1),s("p",null,"Support 'docx', 'pptx', 'pdf', 'xlsx' file preview",-1),s("h2",{id:"code-demo",tabindex:"-1"},[a("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("div",{style:{width:"100px","margin-top":"10px"}},[s("r-preview",{id:"fdsafdsafdsafdsaf"}),s("r-button",{type:"primary",onclick:"uploadFile('fdsafdsafdsafdsaf')"},"choose file to preview")],-1),l(`
                  html
                  <r-preview id="preview"></r-preview>
                  +import{_ as t,o as h,c as n,j as s,a,a3 as l}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"preview","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/preview/index.md","filePath":"src/ranui/preview/index.md","lastUpdated":1728921295000}'),e={name:"src/ranui/preview/index.md"};function p(k,i,E,r,d,g){return h(),n("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"preview",tabindex:"-1"},[a("preview "),s("a",{class:"header-anchor",href:"#preview","aria-label":'Permalink to "preview"'},"​")],-1),s("p",null,"Support 'docx', 'pptx', 'pdf', 'xlsx' file preview",-1),s("h2",{id:"code-demo",tabindex:"-1"},[a("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("div",{style:{width:"100px","margin-top":"10px"}},[s("r-preview",{id:"fdsafdsafdsafdsaf"}),s("r-button",{type:"primary",onclick:"uploadFile('fdsafdsafdsafdsaf')"},"choose file to preview")],-1),l(`
                  html
                  <r-preview id="preview"></r-preview>
                   <r-button type="primary" onclick="uploadFile()">choose file to preview</r-button>
                   
                   <script>
                  diff --git a/assets/src_ranui_preview_index.md.fG1IQRia.lean.js b/assets/src_ranui_preview_index.md.tg6oXUar.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_preview_index.md.fG1IQRia.lean.js
                  rename to assets/src_ranui_preview_index.md.tg6oXUar.lean.js
                  index 40c15e6151..3e0b275f7c 100644
                  --- a/assets/src_ranui_preview_index.md.fG1IQRia.lean.js
                  +++ b/assets/src_ranui_preview_index.md.tg6oXUar.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as t,o as h,c as n,j as s,a,a3 as l}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"preview","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/preview/index.md","filePath":"src/ranui/preview/index.md","lastUpdated":1728828157000}'),e={name:"src/ranui/preview/index.md"};function p(k,i,E,r,d,g){return h(),n("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"preview",tabindex:"-1"},[a("preview "),s("a",{class:"header-anchor",href:"#preview","aria-label":'Permalink to "preview"'},"​")],-1),s("p",null,"Support 'docx', 'pptx', 'pdf', 'xlsx' file preview",-1),s("h2",{id:"code-demo",tabindex:"-1"},[a("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("div",{style:{width:"100px","margin-top":"10px"}},[s("r-preview",{id:"fdsafdsafdsafdsaf"}),s("r-button",{type:"primary",onclick:"uploadFile('fdsafdsafdsafdsaf')"},"choose file to preview")],-1),l(`
                  html
                  <r-preview id="preview"></r-preview>
                  +import{_ as t,o as h,c as n,j as s,a,a3 as l}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"preview","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/preview/index.md","filePath":"src/ranui/preview/index.md","lastUpdated":1728921295000}'),e={name:"src/ranui/preview/index.md"};function p(k,i,E,r,d,g){return h(),n("div",{"data-pagefind-body":!0},i[0]||(i[0]=[s("h1",{id:"preview",tabindex:"-1"},[a("preview "),s("a",{class:"header-anchor",href:"#preview","aria-label":'Permalink to "preview"'},"​")],-1),s("p",null,"Support 'docx', 'pptx', 'pdf', 'xlsx' file preview",-1),s("h2",{id:"code-demo",tabindex:"-1"},[a("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("div",{style:{width:"100px","margin-top":"10px"}},[s("r-preview",{id:"fdsafdsafdsafdsaf"}),s("r-button",{type:"primary",onclick:"uploadFile('fdsafdsafdsafdsaf')"},"choose file to preview")],-1),l(`
                  html
                  <r-preview id="preview"></r-preview>
                   <r-button type="primary" onclick="uploadFile()">choose file to preview</r-button>
                   
                   <script>
                  diff --git a/assets/src_ranui_progress_index.md.cmnI4FIh.js b/assets/src_ranui_progress_index.md.z1F0wQbE.js
                  similarity index 99%
                  rename from assets/src_ranui_progress_index.md.cmnI4FIh.js
                  rename to assets/src_ranui_progress_index.md.z1F0wQbE.js
                  index cf806d91fd..8a842f7826 100644
                  --- a/assets/src_ranui_progress_index.md.cmnI4FIh.js
                  +++ b/assets/src_ranui_progress_index.md.z1F0wQbE.js
                  @@ -1 +1 @@
                  -import{_ as a,o as e,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"progress","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/progress/index.md","filePath":"src/ranui/progress/index.md","lastUpdated":1728828157000}'),p={name:"src/ranui/progress/index.md"};function l(r,t,n,k,d,E){return e(),h("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i('

                  progress

                  Interactive progress bar

                  Code demo

                  xml
                  <r-progress type="drag" ></r-progress>

                  Attribute

                  total

                  Set progress bar Total progress, allowed percentages and numbers.

                  ',8),s("r-progress",{percent:"30",total:"1000"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"70",total:"100"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"10%",total:"100%"},null,-1),i('
                  html
                  <r-progress percent="30" total="1000"></r-progress>\n<r-progress percent="70" total="100"></r-progress>\n<r-progress percent="10%" total="100%"></r-progress>

                  percent

                  Set the current progress of the progress bar, you can set the percentage and number, 'percent' cannot exceed 'total'. If 'total' is not set, the default 'total' is' 100% ', that is, '1'.

                  ',3),s("r-progress",{type:"primary",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"70%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"100%"},null,-1),i('
                  html
                  <r-progress type="primary" percent="30%"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>\n<r-progress type="primary" percent="100%"></r-progress>

                  dot

                  Point of the progress bar, Default display, set to 'false' can be hidden

                  ',3),s("r-progress",{type:"drag",percent:"30%",dot:"false"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%",dot:"true"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
                  html
                  <r-progress type="drag" percent="30%" dot="false"></r-progress>\n<r-progress type="primary" percent="40%" dot="true"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>

                  type

                  • primary: Default progress bar, not setting the 'type' attribute is the default
                  • drag: Draggable, clickable progress bar (dragging requires' dot 'to be' true ')
                  ',3),s("r-progress",{type:"drag",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
                  html
                  <r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

                  Method

                  change

                  The 'change' event is triggered when the 'percent' and 'total' properties change.

                  propertyexplains thattype
                  valueCurrent progress'string or number'
                  percentCurrent progress'string or number'
                  totalTotal progress'string or number'
                  ',5)]))}const y=a(p,[["render",l]]);export{o as __pageData,y as default}; +import{_ as a,o as e,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"progress","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/progress/index.md","filePath":"src/ranui/progress/index.md","lastUpdated":1728921295000}'),p={name:"src/ranui/progress/index.md"};function l(r,t,n,k,d,E){return e(),h("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i('

                  progress

                  Interactive progress bar

                  Code demo

                  xml
                  <r-progress type="drag" ></r-progress>

                  Attribute

                  total

                  Set progress bar Total progress, allowed percentages and numbers.

                  ',8),s("r-progress",{percent:"30",total:"1000"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"70",total:"100"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"10%",total:"100%"},null,-1),i('
                  html
                  <r-progress percent="30" total="1000"></r-progress>\n<r-progress percent="70" total="100"></r-progress>\n<r-progress percent="10%" total="100%"></r-progress>

                  percent

                  Set the current progress of the progress bar, you can set the percentage and number, 'percent' cannot exceed 'total'. If 'total' is not set, the default 'total' is' 100% ', that is, '1'.

                  ',3),s("r-progress",{type:"primary",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"70%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"100%"},null,-1),i('
                  html
                  <r-progress type="primary" percent="30%"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>\n<r-progress type="primary" percent="100%"></r-progress>

                  dot

                  Point of the progress bar, Default display, set to 'false' can be hidden

                  ',3),s("r-progress",{type:"drag",percent:"30%",dot:"false"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%",dot:"true"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
                  html
                  <r-progress type="drag" percent="30%" dot="false"></r-progress>\n<r-progress type="primary" percent="40%" dot="true"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>

                  type

                  • primary: Default progress bar, not setting the 'type' attribute is the default
                  • drag: Draggable, clickable progress bar (dragging requires' dot 'to be' true ')
                  ',3),s("r-progress",{type:"drag",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
                  html
                  <r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

                  Method

                  change

                  The 'change' event is triggered when the 'percent' and 'total' properties change.

                  propertyexplains thattype
                  valueCurrent progress'string or number'
                  percentCurrent progress'string or number'
                  totalTotal progress'string or number'
                  ',5)]))}const y=a(p,[["render",l]]);export{o as __pageData,y as default}; diff --git a/assets/src_ranui_progress_index.md.cmnI4FIh.lean.js b/assets/src_ranui_progress_index.md.z1F0wQbE.lean.js similarity index 99% rename from assets/src_ranui_progress_index.md.cmnI4FIh.lean.js rename to assets/src_ranui_progress_index.md.z1F0wQbE.lean.js index cf806d91fd..8a842f7826 100644 --- a/assets/src_ranui_progress_index.md.cmnI4FIh.lean.js +++ b/assets/src_ranui_progress_index.md.z1F0wQbE.lean.js @@ -1 +1 @@ -import{_ as a,o as e,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"progress","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/progress/index.md","filePath":"src/ranui/progress/index.md","lastUpdated":1728828157000}'),p={name:"src/ranui/progress/index.md"};function l(r,t,n,k,d,E){return e(),h("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i('

                  progress

                  Interactive progress bar

                  Code demo

                  xml
                  <r-progress type="drag" ></r-progress>

                  Attribute

                  total

                  Set progress bar Total progress, allowed percentages and numbers.

                  ',8),s("r-progress",{percent:"30",total:"1000"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"70",total:"100"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"10%",total:"100%"},null,-1),i('
                  html
                  <r-progress percent="30" total="1000"></r-progress>\n<r-progress percent="70" total="100"></r-progress>\n<r-progress percent="10%" total="100%"></r-progress>

                  percent

                  Set the current progress of the progress bar, you can set the percentage and number, 'percent' cannot exceed 'total'. If 'total' is not set, the default 'total' is' 100% ', that is, '1'.

                  ',3),s("r-progress",{type:"primary",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"70%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"100%"},null,-1),i('
                  html
                  <r-progress type="primary" percent="30%"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>\n<r-progress type="primary" percent="100%"></r-progress>

                  dot

                  Point of the progress bar, Default display, set to 'false' can be hidden

                  ',3),s("r-progress",{type:"drag",percent:"30%",dot:"false"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%",dot:"true"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
                  html
                  <r-progress type="drag" percent="30%" dot="false"></r-progress>\n<r-progress type="primary" percent="40%" dot="true"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>

                  type

                  • primary: Default progress bar, not setting the 'type' attribute is the default
                  • drag: Draggable, clickable progress bar (dragging requires' dot 'to be' true ')
                  ',3),s("r-progress",{type:"drag",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
                  html
                  <r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

                  Method

                  change

                  The 'change' event is triggered when the 'percent' and 'total' properties change.

                  propertyexplains thattype
                  valueCurrent progress'string or number'
                  percentCurrent progress'string or number'
                  totalTotal progress'string or number'
                  ',5)]))}const y=a(p,[["render",l]]);export{o as __pageData,y as default}; +import{_ as a,o as e,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const o=JSON.parse('{"title":"progress","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/progress/index.md","filePath":"src/ranui/progress/index.md","lastUpdated":1728921295000}'),p={name:"src/ranui/progress/index.md"};function l(r,t,n,k,d,E){return e(),h("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i('

                  progress

                  Interactive progress bar

                  Code demo

                  xml
                  <r-progress type="drag" ></r-progress>

                  Attribute

                  total

                  Set progress bar Total progress, allowed percentages and numbers.

                  ',8),s("r-progress",{percent:"30",total:"1000"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"70",total:"100"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{percent:"10%",total:"100%"},null,-1),i('
                  html
                  <r-progress percent="30" total="1000"></r-progress>\n<r-progress percent="70" total="100"></r-progress>\n<r-progress percent="10%" total="100%"></r-progress>

                  percent

                  Set the current progress of the progress bar, you can set the percentage and number, 'percent' cannot exceed 'total'. If 'total' is not set, the default 'total' is' 100% ', that is, '1'.

                  ',3),s("r-progress",{type:"primary",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"70%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"100%"},null,-1),i('
                  html
                  <r-progress type="primary" percent="30%"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>\n<r-progress type="primary" percent="100%"></r-progress>

                  dot

                  Point of the progress bar, Default display, set to 'false' can be hidden

                  ',3),s("r-progress",{type:"drag",percent:"30%",dot:"false"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%",dot:"true"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
                  html
                  <r-progress type="drag" percent="30%" dot="false"></r-progress>\n<r-progress type="primary" percent="40%" dot="true"></r-progress>\n<r-progress type="primary" percent="40%"></r-progress>

                  type

                  • primary: Default progress bar, not setting the 'type' attribute is the default
                  • drag: Draggable, clickable progress bar (dragging requires' dot 'to be' true ')
                  ',3),s("r-progress",{type:"drag",percent:"30%"},null,-1),s("div",{style:{height:"20px",width:"10px"}},null,-1),s("r-progress",{type:"primary",percent:"40%"},null,-1),i('
                  html
                  <r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

                  Method

                  change

                  The 'change' event is triggered when the 'percent' and 'total' properties change.

                  propertyexplains thattype
                  valueCurrent progress'string or number'
                  percentCurrent progress'string or number'
                  totalTotal progress'string or number'
                  ',5)]))}const y=a(p,[["render",l]]);export{o as __pageData,y as default}; diff --git a/assets/src_ranui_radar_index.md.DC-fIIc-.js b/assets/src_ranui_radar_index.md.B3Rqerka.js similarity index 99% rename from assets/src_ranui_radar_index.md.DC-fIIc-.js rename to assets/src_ranui_radar_index.md.B3Rqerka.js index 4222827112..39f2a9e526 100644 --- a/assets/src_ranui_radar_index.md.DC-fIIc-.js +++ b/assets/src_ranui_radar_index.md.B3Rqerka.js @@ -1,4 +1,4 @@ -import{_ as e,o as l,c as o,j as t,a as s,a3 as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"Radar","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/radar/index.md","filePath":"src/ranui/radar/index.md","lastUpdated":1728828157000}'),n={name:"src/ranui/radar/index.md"};function h(p,i,r,k,u,d){return l(),o("div",{"data-pagefind-body":!0},i[0]||(i[0]=[t("h1",{id:"radar",tabindex:"-1"},[s("Radar "),t("a",{class:"header-anchor",href:"#radar","aria-label":'Permalink to "Radar"'},"​")],-1),t("p",null,"Comprehensive comparison of differences between multiple sets of data in two-dimensional form, often used to compare 2 or more sets of data",-1),t("h2",{id:"code-demo",tabindex:"-1"},[s("Code demo "),t("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),t("r-radar",{style:{width:"300px",height:"300px",display:"block"},abilitys:'[{"abilityName":"HP","scoreRate":"10"},{"abilityName":"Attack","scoreRate":"90"},{"abilityName":"DEF","scoreRate":"20"},{"abilityName":"Element mastery","scoreRate":"50"},{"abilityName":"Critical Hit Chance","scoreRate":"80"},{"abilityName":"Critical hit damage","scoreRate":"50"}]'},null,-1),a(`
                  xml
                  <r-radar
                  +import{_ as e,o as l,c as o,j as t,a as s,a3 as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"Radar","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/radar/index.md","filePath":"src/ranui/radar/index.md","lastUpdated":1728921295000}'),n={name:"src/ranui/radar/index.md"};function h(p,i,r,k,u,d){return l(),o("div",{"data-pagefind-body":!0},i[0]||(i[0]=[t("h1",{id:"radar",tabindex:"-1"},[s("Radar "),t("a",{class:"header-anchor",href:"#radar","aria-label":'Permalink to "Radar"'},"​")],-1),t("p",null,"Comprehensive comparison of differences between multiple sets of data in two-dimensional form, often used to compare 2 or more sets of data",-1),t("h2",{id:"code-demo",tabindex:"-1"},[s("Code demo "),t("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),t("r-radar",{style:{width:"300px",height:"300px",display:"block"},abilitys:'[{"abilityName":"HP","scoreRate":"10"},{"abilityName":"Attack","scoreRate":"90"},{"abilityName":"DEF","scoreRate":"20"},{"abilityName":"Element mastery","scoreRate":"50"},{"abilityName":"Critical Hit Chance","scoreRate":"80"},{"abilityName":"Critical hit damage","scoreRate":"50"}]'},null,-1),a(`
                  xml
                  <r-radar
                   abilitys='[{"abilityName":"HP","scoreRate":"10"},{"abilityName":"Attack","scoreRate":"90"},{"abilityName":"DEF","scoreRate":"20"},{"abilityName":"Element mastery","scoreRate":"50"},{"abilityName":"Critical Hit Chance","scoreRate":"80"},{"abilityName":"Critical hit damage","scoreRate":"50"}]'
                       style="width:300px;height:300px;display: block;"
                   >
                  diff --git a/assets/src_ranui_radar_index.md.DC-fIIc-.lean.js b/assets/src_ranui_radar_index.md.B3Rqerka.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_radar_index.md.DC-fIIc-.lean.js
                  rename to assets/src_ranui_radar_index.md.B3Rqerka.lean.js
                  index 4222827112..39f2a9e526 100644
                  --- a/assets/src_ranui_radar_index.md.DC-fIIc-.lean.js
                  +++ b/assets/src_ranui_radar_index.md.B3Rqerka.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as e,o as l,c as o,j as t,a as s,a3 as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"Radar","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/radar/index.md","filePath":"src/ranui/radar/index.md","lastUpdated":1728828157000}'),n={name:"src/ranui/radar/index.md"};function h(p,i,r,k,u,d){return l(),o("div",{"data-pagefind-body":!0},i[0]||(i[0]=[t("h1",{id:"radar",tabindex:"-1"},[s("Radar "),t("a",{class:"header-anchor",href:"#radar","aria-label":'Permalink to "Radar"'},"​")],-1),t("p",null,"Comprehensive comparison of differences between multiple sets of data in two-dimensional form, often used to compare 2 or more sets of data",-1),t("h2",{id:"code-demo",tabindex:"-1"},[s("Code demo "),t("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),t("r-radar",{style:{width:"300px",height:"300px",display:"block"},abilitys:'[{"abilityName":"HP","scoreRate":"10"},{"abilityName":"Attack","scoreRate":"90"},{"abilityName":"DEF","scoreRate":"20"},{"abilityName":"Element mastery","scoreRate":"50"},{"abilityName":"Critical Hit Chance","scoreRate":"80"},{"abilityName":"Critical hit damage","scoreRate":"50"}]'},null,-1),a(`
                  xml
                  <r-radar
                  +import{_ as e,o as l,c as o,j as t,a as s,a3 as a}from"./chunks/framework.BYE6xntm.js";const E=JSON.parse('{"title":"Radar","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/radar/index.md","filePath":"src/ranui/radar/index.md","lastUpdated":1728921295000}'),n={name:"src/ranui/radar/index.md"};function h(p,i,r,k,u,d){return l(),o("div",{"data-pagefind-body":!0},i[0]||(i[0]=[t("h1",{id:"radar",tabindex:"-1"},[s("Radar "),t("a",{class:"header-anchor",href:"#radar","aria-label":'Permalink to "Radar"'},"​")],-1),t("p",null,"Comprehensive comparison of differences between multiple sets of data in two-dimensional form, often used to compare 2 or more sets of data",-1),t("h2",{id:"code-demo",tabindex:"-1"},[s("Code demo "),t("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),t("r-radar",{style:{width:"300px",height:"300px",display:"block"},abilitys:'[{"abilityName":"HP","scoreRate":"10"},{"abilityName":"Attack","scoreRate":"90"},{"abilityName":"DEF","scoreRate":"20"},{"abilityName":"Element mastery","scoreRate":"50"},{"abilityName":"Critical Hit Chance","scoreRate":"80"},{"abilityName":"Critical hit damage","scoreRate":"50"}]'},null,-1),a(`
                  xml
                  <r-radar
                   abilitys='[{"abilityName":"HP","scoreRate":"10"},{"abilityName":"Attack","scoreRate":"90"},{"abilityName":"DEF","scoreRate":"20"},{"abilityName":"Element mastery","scoreRate":"50"},{"abilityName":"Critical Hit Chance","scoreRate":"80"},{"abilityName":"Critical hit damage","scoreRate":"50"}]'
                       style="width:300px;height:300px;display: block;"
                   >
                  diff --git a/assets/src_ranui_select_index.md.BtLjKVVg.js b/assets/src_ranui_select_index.md.B8UBMGlm.js
                  similarity index 99%
                  rename from assets/src_ranui_select_index.md.BtLjKVVg.js
                  rename to assets/src_ranui_select_index.md.B8UBMGlm.js
                  index 193692ed16..ccd298c0a4 100644
                  --- a/assets/src_ranui_select_index.md.BtLjKVVg.js
                  +++ b/assets/src_ranui_select_index.md.B8UBMGlm.js
                  @@ -1,4 +1,4 @@
                  -import{_ as h,o as l,c as n,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Select","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/select/index.md","filePath":"src/ranui/select/index.md","lastUpdated":1728828157000}'),p={name:"src/ranui/select/index.md"};function k(e,a,E,r,d,o){return l(),n("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"select",tabindex:"-1"},[t("Select "),s("a",{class:"header-anchor",href:"#select","aria-label":'Permalink to "Select"'},"​")],-1),s("p",null,"A regular pull-down selector.",-1),s("h2",{id:"code-demo",tabindex:"-1"},[t("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("r-select",{style:{width:"120px",height:"40px"},defaultValue:"185"},[s("r-option",{value:"185"},"Mike"),s("r-option",{value:"186"},"Tom"),s("r-option",{value:"187"},"Lucy")],-1),i(`
                  xml
                  <r-select style="width: 120px; height: 40px" defaultValue="185">
                  +import{_ as h,o as l,c as n,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Select","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/select/index.md","filePath":"src/ranui/select/index.md","lastUpdated":1728921295000}'),p={name:"src/ranui/select/index.md"};function k(e,a,E,r,d,o){return l(),n("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"select",tabindex:"-1"},[t("Select "),s("a",{class:"header-anchor",href:"#select","aria-label":'Permalink to "Select"'},"​")],-1),s("p",null,"A regular pull-down selector.",-1),s("h2",{id:"code-demo",tabindex:"-1"},[t("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("r-select",{style:{width:"120px",height:"40px"},defaultValue:"185"},[s("r-option",{value:"185"},"Mike"),s("r-option",{value:"186"},"Tom"),s("r-option",{value:"187"},"Lucy")],-1),i(`
                  xml
                  <r-select style="width: 120px; height: 40px" defaultValue="185">
                         <r-option value="185">Mike</r-option>
                         <r-option value="186">Tom</r-option>
                         <r-option value="187">Lucy</r-option>
                  diff --git a/assets/src_ranui_select_index.md.BtLjKVVg.lean.js b/assets/src_ranui_select_index.md.B8UBMGlm.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_select_index.md.BtLjKVVg.lean.js
                  rename to assets/src_ranui_select_index.md.B8UBMGlm.lean.js
                  index 193692ed16..ccd298c0a4 100644
                  --- a/assets/src_ranui_select_index.md.BtLjKVVg.lean.js
                  +++ b/assets/src_ranui_select_index.md.B8UBMGlm.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as h,o as l,c as n,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Select","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/select/index.md","filePath":"src/ranui/select/index.md","lastUpdated":1728828157000}'),p={name:"src/ranui/select/index.md"};function k(e,a,E,r,d,o){return l(),n("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"select",tabindex:"-1"},[t("Select "),s("a",{class:"header-anchor",href:"#select","aria-label":'Permalink to "Select"'},"​")],-1),s("p",null,"A regular pull-down selector.",-1),s("h2",{id:"code-demo",tabindex:"-1"},[t("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("r-select",{style:{width:"120px",height:"40px"},defaultValue:"185"},[s("r-option",{value:"185"},"Mike"),s("r-option",{value:"186"},"Tom"),s("r-option",{value:"187"},"Lucy")],-1),i(`
                  xml
                  <r-select style="width: 120px; height: 40px" defaultValue="185">
                  +import{_ as h,o as l,c as n,j as s,a as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Select","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/select/index.md","filePath":"src/ranui/select/index.md","lastUpdated":1728921295000}'),p={name:"src/ranui/select/index.md"};function k(e,a,E,r,d,o){return l(),n("div",{"data-pagefind-body":!0},a[0]||(a[0]=[s("h1",{id:"select",tabindex:"-1"},[t("Select "),s("a",{class:"header-anchor",href:"#select","aria-label":'Permalink to "Select"'},"​")],-1),s("p",null,"A regular pull-down selector.",-1),s("h2",{id:"code-demo",tabindex:"-1"},[t("Code demo "),s("a",{class:"header-anchor",href:"#code-demo","aria-label":'Permalink to "Code demo"'},"​")],-1),s("r-select",{style:{width:"120px",height:"40px"},defaultValue:"185"},[s("r-option",{value:"185"},"Mike"),s("r-option",{value:"186"},"Tom"),s("r-option",{value:"187"},"Lucy")],-1),i(`
                  xml
                  <r-select style="width: 120px; height: 40px" defaultValue="185">
                         <r-option value="185">Mike</r-option>
                         <r-option value="186">Tom</r-option>
                         <r-option value="187">Lucy</r-option>
                  diff --git a/assets/src_ranui_skeleton_index.md.J2D8qbZD.js b/assets/src_ranui_skeleton_index.md.8I5i20E1.js
                  similarity index 96%
                  rename from assets/src_ranui_skeleton_index.md.J2D8qbZD.js
                  rename to assets/src_ranui_skeleton_index.md.8I5i20E1.js
                  index 1d8be0bf48..9a825c9800 100644
                  --- a/assets/src_ranui_skeleton_index.md.J2D8qbZD.js
                  +++ b/assets/src_ranui_skeleton_index.md.8I5i20E1.js
                  @@ -1 +1 @@
                  -import{_ as t,o as s,c as a,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"skeleton","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/skeleton/index.md","filePath":"src/ranui/skeleton/index.md","lastUpdated":1728828157000}'),n={name:"src/ranui/skeleton/index.md"};function o(l,e,r,d,p,h){return s(),a("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

                  skeleton

                  Provides a combination of placeholder graphics where you need to wait for content to load.

                  Code demo

                  The skeleton length follows the length of the parent element

                  xml
                  <r-skeleton ></r-skeleton>
                  ',9)]))}const m=t(n,[["render",o]]);export{c as __pageData,m as default}; +import{_ as t,o as s,c as a,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"skeleton","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/skeleton/index.md","filePath":"src/ranui/skeleton/index.md","lastUpdated":1728921295000}'),n={name:"src/ranui/skeleton/index.md"};function o(l,e,r,d,p,h){return s(),a("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

                  skeleton

                  Provides a combination of placeholder graphics where you need to wait for content to load.

                  Code demo

                  The skeleton length follows the length of the parent element

                  xml
                  <r-skeleton ></r-skeleton>
                  ',9)]))}const m=t(n,[["render",o]]);export{c as __pageData,m as default}; diff --git a/assets/src_ranui_skeleton_index.md.J2D8qbZD.lean.js b/assets/src_ranui_skeleton_index.md.8I5i20E1.lean.js similarity index 96% rename from assets/src_ranui_skeleton_index.md.J2D8qbZD.lean.js rename to assets/src_ranui_skeleton_index.md.8I5i20E1.lean.js index 1d8be0bf48..9a825c9800 100644 --- a/assets/src_ranui_skeleton_index.md.J2D8qbZD.lean.js +++ b/assets/src_ranui_skeleton_index.md.8I5i20E1.lean.js @@ -1 +1 @@ -import{_ as t,o as s,c as a,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"skeleton","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/skeleton/index.md","filePath":"src/ranui/skeleton/index.md","lastUpdated":1728828157000}'),n={name:"src/ranui/skeleton/index.md"};function o(l,e,r,d,p,h){return s(),a("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

                  skeleton

                  Provides a combination of placeholder graphics where you need to wait for content to load.

                  Code demo

                  The skeleton length follows the length of the parent element

                  xml
                  <r-skeleton ></r-skeleton>
                  ',9)]))}const m=t(n,[["render",o]]);export{c as __pageData,m as default}; +import{_ as t,o as s,c as a,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"skeleton","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/skeleton/index.md","filePath":"src/ranui/skeleton/index.md","lastUpdated":1728921295000}'),n={name:"src/ranui/skeleton/index.md"};function o(l,e,r,d,p,h){return s(),a("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

                  skeleton

                  Provides a combination of placeholder graphics where you need to wait for content to load.

                  Code demo

                  The skeleton length follows the length of the parent element

                  xml
                  <r-skeleton ></r-skeleton>
                  ',9)]))}const m=t(n,[["render",o]]);export{c as __pageData,m as default}; diff --git a/assets/src_ranui_tab_index.md.CnkY3B_Y.js b/assets/src_ranui_tab_index.md.CeQ2RW9Y.js similarity index 99% rename from assets/src_ranui_tab_index.md.CnkY3B_Y.js rename to assets/src_ranui_tab_index.md.CeQ2RW9Y.js index 3782e80d94..3856456ede 100644 --- a/assets/src_ranui_tab_index.md.CnkY3B_Y.js +++ b/assets/src_ranui_tab_index.md.CeQ2RW9Y.js @@ -1,4 +1,4 @@ -import{_ as t,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/tab/index.md","filePath":"src/ranui/tab/index.md","lastUpdated":1728828157000}'),k={name:"src/ranui/tab/index.md"};function n(p,a,e,E,r,d){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Tab

                  TAB pages, where 'r-tab' needs to be used with 'r-tabs'

                  Code demo

                  111112222233333
                  xml
                  <r-tabs >
                  +import{_ as t,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/tab/index.md","filePath":"src/ranui/tab/index.md","lastUpdated":1728921295000}'),k={name:"src/ranui/tab/index.md"};function n(p,a,e,E,r,d){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Tab

                  TAB pages, where 'r-tab' needs to be used with 'r-tabs'

                  Code demo

                  111112222233333
                  xml
                  <r-tabs >
                         <r-tab label="tab1">11111</r-tab>
                         <r-tab label="tab2">22222</r-tab>
                         <r-tab label="tab3">33333</r-tab>
                  diff --git a/assets/src_ranui_tab_index.md.CnkY3B_Y.lean.js b/assets/src_ranui_tab_index.md.CeQ2RW9Y.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_tab_index.md.CnkY3B_Y.lean.js
                  rename to assets/src_ranui_tab_index.md.CeQ2RW9Y.lean.js
                  index 3782e80d94..3856456ede 100644
                  --- a/assets/src_ranui_tab_index.md.CnkY3B_Y.lean.js
                  +++ b/assets/src_ranui_tab_index.md.CeQ2RW9Y.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as t,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/tab/index.md","filePath":"src/ranui/tab/index.md","lastUpdated":1728828157000}'),k={name:"src/ranui/tab/index.md"};function n(p,a,e,E,r,d){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Tab

                  TAB pages, where 'r-tab' needs to be used with 'r-tabs'

                  Code demo

                  111112222233333
                  xml
                  <r-tabs >
                  +import{_ as t,o as l,c as h,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const y=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/tab/index.md","filePath":"src/ranui/tab/index.md","lastUpdated":1728921295000}'),k={name:"src/ranui/tab/index.md"};function n(p,a,e,E,r,d){return l(),h("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Tab

                  TAB pages, where 'r-tab' needs to be used with 'r-tabs'

                  Code demo

                  111112222233333
                  xml
                  <r-tabs >
                         <r-tab label="tab1">11111</r-tab>
                         <r-tab label="tab2">22222</r-tab>
                         <r-tab label="tab3">33333</r-tab>
                  diff --git a/assets/src_ranui_tabs_index.md.CPGXXUJu.js b/assets/src_ranui_tabs_index.md.CxBjn965.js
                  similarity index 99%
                  rename from assets/src_ranui_tabs_index.md.CPGXXUJu.js
                  rename to assets/src_ranui_tabs_index.md.CxBjn965.js
                  index 3141bbc02c..3ac07ea200 100644
                  --- a/assets/src_ranui_tabs_index.md.CPGXXUJu.js
                  +++ b/assets/src_ranui_tabs_index.md.CxBjn965.js
                  @@ -1,4 +1,4 @@
                  -import{_ as t,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/tabs/index.md","filePath":"src/ranui/tabs/index.md","lastUpdated":1728828157000}'),n={name:"src/ranui/tabs/index.md"};function k(e,a,p,E,r,d){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Tab

                  Code demo

                  tab1tab2tab3
                  xml
                  <r-tabs>
                  +import{_ as t,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/tabs/index.md","filePath":"src/ranui/tabs/index.md","lastUpdated":1728921295000}'),n={name:"src/ranui/tabs/index.md"};function k(e,a,p,E,r,d){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Tab

                  Code demo

                  tab1tab2tab3
                  xml
                  <r-tabs>
                       <r-tab label="tab1">tab1</r-tab>
                       <r-tab label="tab2">tab2</r-tab>
                       <r-tab label="tab3">tab3</r-tab>
                  diff --git a/assets/src_ranui_tabs_index.md.CPGXXUJu.lean.js b/assets/src_ranui_tabs_index.md.CxBjn965.lean.js
                  similarity index 99%
                  rename from assets/src_ranui_tabs_index.md.CPGXXUJu.lean.js
                  rename to assets/src_ranui_tabs_index.md.CxBjn965.lean.js
                  index 3141bbc02c..3ac07ea200 100644
                  --- a/assets/src_ranui_tabs_index.md.CPGXXUJu.lean.js
                  +++ b/assets/src_ranui_tabs_index.md.CxBjn965.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as t,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/tabs/index.md","filePath":"src/ranui/tabs/index.md","lastUpdated":1728828157000}'),n={name:"src/ranui/tabs/index.md"};function k(e,a,p,E,r,d){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Tab

                  Code demo

                  tab1tab2tab3
                  xml
                  <r-tabs>
                  +import{_ as t,o as h,c as l,a3 as i,j as s}from"./chunks/framework.BYE6xntm.js";const b=JSON.parse('{"title":"Tab","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranui/tabs/index.md","filePath":"src/ranui/tabs/index.md","lastUpdated":1728921295000}'),n={name:"src/ranui/tabs/index.md"};function k(e,a,p,E,r,d){return h(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i(`

                  Tab

                  Code demo

                  tab1tab2tab3
                  xml
                  <r-tabs>
                       <r-tab label="tab1">tab1</r-tab>
                       <r-tab label="tab2">tab2</r-tab>
                       <r-tab label="tab3">tab3</r-tab>
                  diff --git a/assets/src_ranuts_binaryTree_index.md.9VY_7CtH.js b/assets/src_ranuts_binaryTree_index.md.BOOvvNkp.js
                  similarity index 99%
                  rename from assets/src_ranuts_binaryTree_index.md.9VY_7CtH.js
                  rename to assets/src_ranuts_binaryTree_index.md.BOOvvNkp.js
                  index 260b190ed7..2e1794b90e 100644
                  --- a/assets/src_ranuts_binaryTree_index.md.9VY_7CtH.js
                  +++ b/assets/src_ranuts_binaryTree_index.md.BOOvvNkp.js
                  @@ -1 +1 @@
                  -import{_ as e}from"./chunks/balanceTree.CCEoBiag.js";import{_ as r,o as i,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"二叉树的定义","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/binaryTree/index.md","filePath":"src/ranuts/binaryTree/index.md","lastUpdated":1728828157000}'),l={name:"src/ranuts/binaryTree/index.md"};function o(n,a,d,s,c,u){return i(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[h('

                  二叉树的定义

                  在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

                  二叉树的性质

                  • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
                  • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
                  • 包含 n 个结点的二叉树的高度至少为(log2n)+1
                  • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
                  • 二叉树的总结点数 n = n1 + n2 + n0
                  • 总连线数等于总节点数减一(B = n - 1)
                  • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

                  二叉树的类型

                  满二叉树

                  一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

                  完全二叉树

                  一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

                  二叉搜索树

                  二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

                  平衡二叉树

                  平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

                  B 树

                  B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

                  B+树

                  B+树是 B 树的变体,也是一种多路搜索树。

                  B*树

                  B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

                  红黑树

                  红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

                  遍历

                  前序遍历

                  后序遍历

                  中序遍历

                  层序遍历

                  常见算法题

                  镜像二叉树

                  重建二叉树

                  二叉树深度

                  二叉树节点总数

                  判断二叉树子结构

                  输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

                  参考文档

                  1. 维基百科二叉树
                  2. 百度百科满二叉树
                  ',36)]))}const m=r(l,[["render",o]]);export{p as __pageData,m as default}; +import{_ as e}from"./chunks/balanceTree.CCEoBiag.js";import{_ as r,o as i,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"二叉树的定义","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/binaryTree/index.md","filePath":"src/ranuts/binaryTree/index.md","lastUpdated":1728921295000}'),l={name:"src/ranuts/binaryTree/index.md"};function o(n,a,d,s,c,u){return i(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[h('

                  二叉树的定义

                  在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

                  二叉树的性质

                  • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
                  • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
                  • 包含 n 个结点的二叉树的高度至少为(log2n)+1
                  • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
                  • 二叉树的总结点数 n = n1 + n2 + n0
                  • 总连线数等于总节点数减一(B = n - 1)
                  • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

                  二叉树的类型

                  满二叉树

                  一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

                  完全二叉树

                  一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

                  二叉搜索树

                  二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

                  平衡二叉树

                  平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

                  B 树

                  B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

                  B+树

                  B+树是 B 树的变体,也是一种多路搜索树。

                  B*树

                  B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

                  红黑树

                  红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

                  遍历

                  前序遍历

                  后序遍历

                  中序遍历

                  层序遍历

                  常见算法题

                  镜像二叉树

                  重建二叉树

                  二叉树深度

                  二叉树节点总数

                  判断二叉树子结构

                  输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

                  参考文档

                  1. 维基百科二叉树
                  2. 百度百科满二叉树
                  ',36)]))}const m=r(l,[["render",o]]);export{p as __pageData,m as default}; diff --git a/assets/src_ranuts_binaryTree_index.md.9VY_7CtH.lean.js b/assets/src_ranuts_binaryTree_index.md.BOOvvNkp.lean.js similarity index 99% rename from assets/src_ranuts_binaryTree_index.md.9VY_7CtH.lean.js rename to assets/src_ranuts_binaryTree_index.md.BOOvvNkp.lean.js index 260b190ed7..2e1794b90e 100644 --- a/assets/src_ranuts_binaryTree_index.md.9VY_7CtH.lean.js +++ b/assets/src_ranuts_binaryTree_index.md.BOOvvNkp.lean.js @@ -1 +1 @@ -import{_ as e}from"./chunks/balanceTree.CCEoBiag.js";import{_ as r,o as i,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"二叉树的定义","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/binaryTree/index.md","filePath":"src/ranuts/binaryTree/index.md","lastUpdated":1728828157000}'),l={name:"src/ranuts/binaryTree/index.md"};function o(n,a,d,s,c,u){return i(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[h('

                  二叉树的定义

                  在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

                  二叉树的性质

                  • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
                  • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
                  • 包含 n 个结点的二叉树的高度至少为(log2n)+1
                  • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
                  • 二叉树的总结点数 n = n1 + n2 + n0
                  • 总连线数等于总节点数减一(B = n - 1)
                  • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

                  二叉树的类型

                  满二叉树

                  一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

                  完全二叉树

                  一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

                  二叉搜索树

                  二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

                  平衡二叉树

                  平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

                  B 树

                  B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

                  B+树

                  B+树是 B 树的变体,也是一种多路搜索树。

                  B*树

                  B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

                  红黑树

                  红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

                  遍历

                  前序遍历

                  后序遍历

                  中序遍历

                  层序遍历

                  常见算法题

                  镜像二叉树

                  重建二叉树

                  二叉树深度

                  二叉树节点总数

                  判断二叉树子结构

                  输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

                  参考文档

                  1. 维基百科二叉树
                  2. 百度百科满二叉树
                  ',36)]))}const m=r(l,[["render",o]]);export{p as __pageData,m as default}; +import{_ as e}from"./chunks/balanceTree.CCEoBiag.js";import{_ as r,o as i,c as t,a3 as h}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"二叉树的定义","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/binaryTree/index.md","filePath":"src/ranuts/binaryTree/index.md","lastUpdated":1728921295000}'),l={name:"src/ranuts/binaryTree/index.md"};function o(n,a,d,s,c,u){return i(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[h('

                  二叉树的定义

                  在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

                  二叉树的性质

                  • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
                  • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
                  • 包含 n 个结点的二叉树的高度至少为(log2n)+1
                  • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
                  • 二叉树的总结点数 n = n1 + n2 + n0
                  • 总连线数等于总节点数减一(B = n - 1)
                  • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

                  二叉树的类型

                  满二叉树

                  一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

                  完全二叉树

                  一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

                  二叉搜索树

                  二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

                  平衡二叉树

                  平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

                  B 树

                  B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

                  B+树

                  B+树是 B 树的变体,也是一种多路搜索树。

                  B*树

                  B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

                  红黑树

                  红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

                  遍历

                  前序遍历

                  后序遍历

                  中序遍历

                  层序遍历

                  常见算法题

                  镜像二叉树

                  重建二叉树

                  二叉树深度

                  二叉树节点总数

                  判断二叉树子结构

                  输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

                  参考文档

                  1. 维基百科二叉树
                  2. 百度百科满二叉树
                  ',36)]))}const m=r(l,[["render",o]]);export{p as __pageData,m as default}; diff --git a/assets/src_ranuts_bundler_index.md.2d_kwA5U.js b/assets/src_ranuts_bundler_index.md.BBvegtDt.js similarity index 96% rename from assets/src_ranuts_bundler_index.md.2d_kwA5U.js rename to assets/src_ranuts_bundler_index.md.BBvegtDt.js index 8c5b351851..34a28a70b3 100644 --- a/assets/src_ranuts_bundler_index.md.2d_kwA5U.js +++ b/assets/src_ranuts_bundler_index.md.BBvegtDt.js @@ -1,4 +1,4 @@ -import{_ as s}from"./chunks/bundle.BxrzsuA1.js";import{_ as a,o as e,c as p,a3 as t}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse('{"title":"Bundler","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/bundler/index.md","filePath":"src/ranuts/bundler/index.md","lastUpdated":1728828157000}'),l={name:"src/ranuts/bundler/index.md"};function r(i,n,d,o,c,u){return e(),p("div",{"data-pagefind-body":!0},n[0]||(n[0]=[t(`

                  Bundler

                  Bundler的使用: 传入 options 参数

                  function build(options: Options):Promise<Build> {
                  +import{_ as s}from"./chunks/bundle.BxrzsuA1.js";import{_ as a,o as e,c as p,a3 as t}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse('{"title":"Bundler","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/bundler/index.md","filePath":"src/ranuts/bundler/index.md","lastUpdated":1728921295000}'),l={name:"src/ranuts/bundler/index.md"};function r(i,n,d,o,c,u){return e(),p("div",{"data-pagefind-body":!0},n[0]||(n[0]=[t(`

                  Bundler

                  Bundler的使用: 传入 options 参数

                  function build(options: Options):Promise<Build> {
                     const bundle = new Bundle({
                       entry: options.input
                     });
                  diff --git a/assets/src_ranuts_bundler_index.md.2d_kwA5U.lean.js b/assets/src_ranuts_bundler_index.md.BBvegtDt.lean.js
                  similarity index 96%
                  rename from assets/src_ranuts_bundler_index.md.2d_kwA5U.lean.js
                  rename to assets/src_ranuts_bundler_index.md.BBvegtDt.lean.js
                  index 8c5b351851..34a28a70b3 100644
                  --- a/assets/src_ranuts_bundler_index.md.2d_kwA5U.lean.js
                  +++ b/assets/src_ranuts_bundler_index.md.BBvegtDt.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as s}from"./chunks/bundle.BxrzsuA1.js";import{_ as a,o as e,c as p,a3 as t}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse('{"title":"Bundler","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/bundler/index.md","filePath":"src/ranuts/bundler/index.md","lastUpdated":1728828157000}'),l={name:"src/ranuts/bundler/index.md"};function r(i,n,d,o,c,u){return e(),p("div",{"data-pagefind-body":!0},n[0]||(n[0]=[t(`

                  Bundler

                  Bundler的使用: 传入 options 参数

                  function build(options: Options):Promise<Build> {
                  +import{_ as s}from"./chunks/bundle.BxrzsuA1.js";import{_ as a,o as e,c as p,a3 as t}from"./chunks/framework.BYE6xntm.js";const h=JSON.parse('{"title":"Bundler","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/bundler/index.md","filePath":"src/ranuts/bundler/index.md","lastUpdated":1728921295000}'),l={name:"src/ranuts/bundler/index.md"};function r(i,n,d,o,c,u){return e(),p("div",{"data-pagefind-body":!0},n[0]||(n[0]=[t(`

                  Bundler

                  Bundler的使用: 传入 options 参数

                  function build(options: Options):Promise<Build> {
                     const bundle = new Bundle({
                       entry: options.input
                     });
                  diff --git a/assets/src_ranuts_file_appendFile.md.CHmuoXqR.js b/assets/src_ranuts_file_appendFile.md.Ba1ZPoPO.js
                  similarity index 96%
                  rename from assets/src_ranuts_file_appendFile.md.CHmuoXqR.js
                  rename to assets/src_ranuts_file_appendFile.md.Ba1ZPoPO.js
                  index e6c98d79fe..91837a37a1 100644
                  --- a/assets/src_ranuts_file_appendFile.md.CHmuoXqR.js
                  +++ b/assets/src_ranuts_file_appendFile.md.Ba1ZPoPO.js
                  @@ -1 +1 @@
                  -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"AppendFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/appendFile.md","filePath":"src/ranuts/file/appendFile.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/file/appendFile.md"};function o(i,t,l,h,s,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  AppendFile

                  追加一些数据到文件内

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否追加成功booleantrue 追加成功 false 追加失败
                  data追加失败的原因,添加成功后的文件内容any

                  Options

                  参数说明类型默认值
                  path文件路径,需要追加的文件stringundefined
                  content需要追加的内容string

                  Example

                  ',9)]))}const b=e(n,[["render",o]]);export{u as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"AppendFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/appendFile.md","filePath":"src/ranuts/file/appendFile.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/file/appendFile.md"};function o(i,t,l,h,s,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  AppendFile

                  追加一些数据到文件内

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否追加成功booleantrue 追加成功 false 追加失败
                  data追加失败的原因,添加成功后的文件内容any

                  Options

                  参数说明类型默认值
                  path文件路径,需要追加的文件stringundefined
                  content需要追加的内容string

                  Example

                  ',9)]))}const b=e(n,[["render",o]]);export{u as __pageData,b as default}; diff --git a/assets/src_ranuts_file_appendFile.md.CHmuoXqR.lean.js b/assets/src_ranuts_file_appendFile.md.Ba1ZPoPO.lean.js similarity index 96% rename from assets/src_ranuts_file_appendFile.md.CHmuoXqR.lean.js rename to assets/src_ranuts_file_appendFile.md.Ba1ZPoPO.lean.js index e6c98d79fe..91837a37a1 100644 --- a/assets/src_ranuts_file_appendFile.md.CHmuoXqR.lean.js +++ b/assets/src_ranuts_file_appendFile.md.Ba1ZPoPO.lean.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"AppendFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/appendFile.md","filePath":"src/ranuts/file/appendFile.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/file/appendFile.md"};function o(i,t,l,h,s,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  AppendFile

                  追加一些数据到文件内

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否追加成功booleantrue 追加成功 false 追加失败
                  data追加失败的原因,添加成功后的文件内容any

                  Options

                  参数说明类型默认值
                  path文件路径,需要追加的文件stringundefined
                  content需要追加的内容string

                  Example

                  ',9)]))}const b=e(n,[["render",o]]);export{u as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"AppendFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/appendFile.md","filePath":"src/ranuts/file/appendFile.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/file/appendFile.md"};function o(i,t,l,h,s,p){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  AppendFile

                  追加一些数据到文件内

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否追加成功booleantrue 追加成功 false 追加失败
                  data追加失败的原因,添加成功后的文件内容any

                  Options

                  参数说明类型默认值
                  path文件路径,需要追加的文件stringundefined
                  content需要追加的内容string

                  Example

                  ',9)]))}const b=e(n,[["render",o]]);export{u as __pageData,b as default}; diff --git a/assets/src_ranuts_file_fileInfo.md.BGMu3rbo.js b/assets/src_ranuts_file_fileInfo.md.C3Zp4I69.js similarity index 96% rename from assets/src_ranuts_file_fileInfo.md.BGMu3rbo.js rename to assets/src_ranuts_file_fileInfo.md.C3Zp4I69.js index 7921d3f1f0..dd959e4351 100644 --- a/assets/src_ranuts_file_fileInfo.md.BGMu3rbo.js +++ b/assets/src_ranuts_file_fileInfo.md.C3Zp4I69.js @@ -1 +1 @@ -import{_ as e,o as a,c as r,a3 as d}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"QueryFileInfo","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/fileInfo.md","filePath":"src/ranuts/file/fileInfo.md","lastUpdated":1728828157000}'),o={name:"src/ranuts/file/fileInfo.md"};function i(n,t,l,h,s,c){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[d('

                  QueryFileInfo

                  查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否检查成功booleantrue 成功 false 失败
                  data文件的信息,或者错误的原因Stats

                  Options

                  参数说明类型默认值
                  path文件路径,需要检查的文件路径stringundefined

                  Example

                  ',9)]))}const p=e(o,[["render",i]]);export{u as __pageData,p as default}; +import{_ as e,o as a,c as r,a3 as d}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"QueryFileInfo","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/fileInfo.md","filePath":"src/ranuts/file/fileInfo.md","lastUpdated":1728921295000}'),o={name:"src/ranuts/file/fileInfo.md"};function i(n,t,l,h,s,c){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[d('

                  QueryFileInfo

                  查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否检查成功booleantrue 成功 false 失败
                  data文件的信息,或者错误的原因Stats

                  Options

                  参数说明类型默认值
                  path文件路径,需要检查的文件路径stringundefined

                  Example

                  ',9)]))}const p=e(o,[["render",i]]);export{u as __pageData,p as default}; diff --git a/assets/src_ranuts_file_fileInfo.md.BGMu3rbo.lean.js b/assets/src_ranuts_file_fileInfo.md.C3Zp4I69.lean.js similarity index 96% rename from assets/src_ranuts_file_fileInfo.md.BGMu3rbo.lean.js rename to assets/src_ranuts_file_fileInfo.md.C3Zp4I69.lean.js index 7921d3f1f0..dd959e4351 100644 --- a/assets/src_ranuts_file_fileInfo.md.BGMu3rbo.lean.js +++ b/assets/src_ranuts_file_fileInfo.md.C3Zp4I69.lean.js @@ -1 +1 @@ -import{_ as e,o as a,c as r,a3 as d}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"QueryFileInfo","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/fileInfo.md","filePath":"src/ranuts/file/fileInfo.md","lastUpdated":1728828157000}'),o={name:"src/ranuts/file/fileInfo.md"};function i(n,t,l,h,s,c){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[d('

                  QueryFileInfo

                  查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否检查成功booleantrue 成功 false 失败
                  data文件的信息,或者错误的原因Stats

                  Options

                  参数说明类型默认值
                  path文件路径,需要检查的文件路径stringundefined

                  Example

                  ',9)]))}const p=e(o,[["render",i]]);export{u as __pageData,p as default}; +import{_ as e,o as a,c as r,a3 as d}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"QueryFileInfo","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/fileInfo.md","filePath":"src/ranuts/file/fileInfo.md","lastUpdated":1728921295000}'),o={name:"src/ranuts/file/fileInfo.md"};function i(n,t,l,h,s,c){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[d('

                  QueryFileInfo

                  查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否检查成功booleantrue 成功 false 失败
                  data文件的信息,或者错误的原因Stats

                  Options

                  参数说明类型默认值
                  path文件路径,需要检查的文件路径stringundefined

                  Example

                  ',9)]))}const p=e(o,[["render",i]]);export{u as __pageData,p as default}; diff --git a/assets/src_ranuts_file_readDir.md.D-wGUvqF.js b/assets/src_ranuts_file_readDir.md.BDf-8MWg.js similarity index 96% rename from assets/src_ranuts_file_readDir.md.D-wGUvqF.js rename to assets/src_ranuts_file_readDir.md.BDf-8MWg.js index 790d768153..a1a709a512 100644 --- a/assets/src_ranuts_file_readDir.md.D-wGUvqF.js +++ b/assets/src_ranuts_file_readDir.md.BDf-8MWg.js @@ -1 +1 @@ -import{_ as e,o as r,c as l,a3 as d,j as t,a as n}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"ReadDir","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/readDir.md","filePath":"src/ranuts/file/readDir.md","lastUpdated":1728828157000}'),i={name:"src/ranuts/file/readDir.md"};function o(s,a,h,u,c,p){return r(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[d('

                  ReadDir

                  读一个目录下的所有文件

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  result目录下所有文件的数组array传入函数的参数

                  Options

                  ',7),t("table",{tabindex:"0"},[t("thead",null,[t("tr",null,[t("th",null,"参数"),t("th",null,"说明"),t("th",null,"类型"),t("th",null,"默认值")])]),t("tbody",null,[t("tr",null,[t("td",null,"options"),t("td",{dirPath:""}),t("td",null,[t("code",null,"object")]),t("td",null,"传入函数的参数")]),t("tr",null,[t("td",null,"dirPath"),t("td",null,"文件的路径"),t("td",null,[t("code",null,"Stats")]),t("td")])])],-1),t("h2",{id:"example",tabindex:"-1"},[n("Example "),t("a",{class:"header-anchor",href:"#example","aria-label":'Permalink to "Example"'},"​")],-1)]))}const f=e(i,[["render",o]]);export{m as __pageData,f as default}; +import{_ as e,o as r,c as l,a3 as d,j as t,a as n}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"ReadDir","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/readDir.md","filePath":"src/ranuts/file/readDir.md","lastUpdated":1728921295000}'),i={name:"src/ranuts/file/readDir.md"};function o(s,a,h,u,c,p){return r(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[d('

                  ReadDir

                  读一个目录下的所有文件

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  result目录下所有文件的数组array传入函数的参数

                  Options

                  ',7),t("table",{tabindex:"0"},[t("thead",null,[t("tr",null,[t("th",null,"参数"),t("th",null,"说明"),t("th",null,"类型"),t("th",null,"默认值")])]),t("tbody",null,[t("tr",null,[t("td",null,"options"),t("td",{dirPath:""}),t("td",null,[t("code",null,"object")]),t("td",null,"传入函数的参数")]),t("tr",null,[t("td",null,"dirPath"),t("td",null,"文件的路径"),t("td",null,[t("code",null,"Stats")]),t("td")])])],-1),t("h2",{id:"example",tabindex:"-1"},[n("Example "),t("a",{class:"header-anchor",href:"#example","aria-label":'Permalink to "Example"'},"​")],-1)]))}const f=e(i,[["render",o]]);export{m as __pageData,f as default}; diff --git a/assets/src_ranuts_file_readDir.md.D-wGUvqF.lean.js b/assets/src_ranuts_file_readDir.md.BDf-8MWg.lean.js similarity index 96% rename from assets/src_ranuts_file_readDir.md.D-wGUvqF.lean.js rename to assets/src_ranuts_file_readDir.md.BDf-8MWg.lean.js index 790d768153..a1a709a512 100644 --- a/assets/src_ranuts_file_readDir.md.D-wGUvqF.lean.js +++ b/assets/src_ranuts_file_readDir.md.BDf-8MWg.lean.js @@ -1 +1 @@ -import{_ as e,o as r,c as l,a3 as d,j as t,a as n}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"ReadDir","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/readDir.md","filePath":"src/ranuts/file/readDir.md","lastUpdated":1728828157000}'),i={name:"src/ranuts/file/readDir.md"};function o(s,a,h,u,c,p){return r(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[d('

                  ReadDir

                  读一个目录下的所有文件

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  result目录下所有文件的数组array传入函数的参数

                  Options

                  ',7),t("table",{tabindex:"0"},[t("thead",null,[t("tr",null,[t("th",null,"参数"),t("th",null,"说明"),t("th",null,"类型"),t("th",null,"默认值")])]),t("tbody",null,[t("tr",null,[t("td",null,"options"),t("td",{dirPath:""}),t("td",null,[t("code",null,"object")]),t("td",null,"传入函数的参数")]),t("tr",null,[t("td",null,"dirPath"),t("td",null,"文件的路径"),t("td",null,[t("code",null,"Stats")]),t("td")])])],-1),t("h2",{id:"example",tabindex:"-1"},[n("Example "),t("a",{class:"header-anchor",href:"#example","aria-label":'Permalink to "Example"'},"​")],-1)]))}const f=e(i,[["render",o]]);export{m as __pageData,f as default}; +import{_ as e,o as r,c as l,a3 as d,j as t,a as n}from"./chunks/framework.BYE6xntm.js";const m=JSON.parse('{"title":"ReadDir","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/readDir.md","filePath":"src/ranuts/file/readDir.md","lastUpdated":1728921295000}'),i={name:"src/ranuts/file/readDir.md"};function o(s,a,h,u,c,p){return r(),l("div",{"data-pagefind-body":!0},a[0]||(a[0]=[d('

                  ReadDir

                  读一个目录下的所有文件

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  result目录下所有文件的数组array传入函数的参数

                  Options

                  ',7),t("table",{tabindex:"0"},[t("thead",null,[t("tr",null,[t("th",null,"参数"),t("th",null,"说明"),t("th",null,"类型"),t("th",null,"默认值")])]),t("tbody",null,[t("tr",null,[t("td",null,"options"),t("td",{dirPath:""}),t("td",null,[t("code",null,"object")]),t("td",null,"传入函数的参数")]),t("tr",null,[t("td",null,"dirPath"),t("td",null,"文件的路径"),t("td",null,[t("code",null,"Stats")]),t("td")])])],-1),t("h2",{id:"example",tabindex:"-1"},[n("Example "),t("a",{class:"header-anchor",href:"#example","aria-label":'Permalink to "Example"'},"​")],-1)]))}const f=e(i,[["render",o]]);export{m as __pageData,f as default}; diff --git a/assets/src_ranuts_file_readFile.md.DzoyHHIO.js b/assets/src_ranuts_file_readFile.md.DZETE7kx.js similarity index 96% rename from assets/src_ranuts_file_readFile.md.DzoyHHIO.js rename to assets/src_ranuts_file_readFile.md.DZETE7kx.js index e3491e00e8..4271061aca 100644 --- a/assets/src_ranuts_file_readFile.md.DzoyHHIO.js +++ b/assets/src_ranuts_file_readFile.md.DZETE7kx.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ReadFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/readFile.md","filePath":"src/ranuts/file/readFile.md","lastUpdated":1728828157000}'),o={name:"src/ranuts/file/readFile.md"};function i(l,t,n,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  ReadFile

                  观察一个文件是否改变

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  data文件是否被改变booleantrue 文件改变 false 文件没变

                  Options

                  参数说明类型默认值
                  path文件路径,需要监听的文件stringundefined
                  interval监听文件改变的时间,单位毫秒。number20

                  Example

                  ',9)]))}const b=e(o,[["render",i]]);export{p as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ReadFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/readFile.md","filePath":"src/ranuts/file/readFile.md","lastUpdated":1728921295000}'),o={name:"src/ranuts/file/readFile.md"};function i(l,t,n,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  ReadFile

                  观察一个文件是否改变

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  data文件是否被改变booleantrue 文件改变 false 文件没变

                  Options

                  参数说明类型默认值
                  path文件路径,需要监听的文件stringundefined
                  interval监听文件改变的时间,单位毫秒。number20

                  Example

                  ',9)]))}const b=e(o,[["render",i]]);export{p as __pageData,b as default}; diff --git a/assets/src_ranuts_file_readFile.md.DzoyHHIO.lean.js b/assets/src_ranuts_file_readFile.md.DZETE7kx.lean.js similarity index 96% rename from assets/src_ranuts_file_readFile.md.DzoyHHIO.lean.js rename to assets/src_ranuts_file_readFile.md.DZETE7kx.lean.js index e3491e00e8..4271061aca 100644 --- a/assets/src_ranuts_file_readFile.md.DzoyHHIO.lean.js +++ b/assets/src_ranuts_file_readFile.md.DZETE7kx.lean.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ReadFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/readFile.md","filePath":"src/ranuts/file/readFile.md","lastUpdated":1728828157000}'),o={name:"src/ranuts/file/readFile.md"};function i(l,t,n,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  ReadFile

                  观察一个文件是否改变

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  data文件是否被改变booleantrue 文件改变 false 文件没变

                  Options

                  参数说明类型默认值
                  path文件路径,需要监听的文件stringundefined
                  interval监听文件改变的时间,单位毫秒。number20

                  Example

                  ',9)]))}const b=e(o,[["render",i]]);export{p as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ReadFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/readFile.md","filePath":"src/ranuts/file/readFile.md","lastUpdated":1728921295000}'),o={name:"src/ranuts/file/readFile.md"};function i(l,t,n,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  ReadFile

                  观察一个文件是否改变

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  data文件是否被改变booleantrue 文件改变 false 文件没变

                  Options

                  参数说明类型默认值
                  path文件路径,需要监听的文件stringundefined
                  interval监听文件改变的时间,单位毫秒。number20

                  Example

                  ',9)]))}const b=e(o,[["render",i]]);export{p as __pageData,b as default}; diff --git a/assets/src_ranuts_file_watchFile.md.6J1Mi6RC.js b/assets/src_ranuts_file_watchFile.md.CRypAqqF.js similarity index 96% rename from assets/src_ranuts_file_watchFile.md.6J1Mi6RC.js rename to assets/src_ranuts_file_watchFile.md.CRypAqqF.js index 53fcace847..2bd8b35865 100644 --- a/assets/src_ranuts_file_watchFile.md.6J1Mi6RC.js +++ b/assets/src_ranuts_file_watchFile.md.CRypAqqF.js @@ -1 +1 @@ -import{_ as a,o as e,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WatchFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/watchFile.md","filePath":"src/ranuts/file/watchFile.md","lastUpdated":1728828157000}'),o={name:"src/ranuts/file/watchFile.md"};function i(h,t,l,n,c,s){return e(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  WatchFile

                  观察一个文件是否改变

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  status文件是否被改变booleantrue 文件改变 false 文件没变

                  Options

                  参数说明类型默认值
                  path文件路径,需要监听的文件stringundefined
                  interval监听文件改变的时间,单位毫秒。number20
                  ',8)]))}const b=a(o,[["render",i]]);export{p as __pageData,b as default}; +import{_ as a,o as e,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WatchFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/watchFile.md","filePath":"src/ranuts/file/watchFile.md","lastUpdated":1728921295000}'),o={name:"src/ranuts/file/watchFile.md"};function i(h,t,l,n,c,s){return e(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  WatchFile

                  观察一个文件是否改变

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  status文件是否被改变booleantrue 文件改变 false 文件没变

                  Options

                  参数说明类型默认值
                  path文件路径,需要监听的文件stringundefined
                  interval监听文件改变的时间,单位毫秒。number20
                  ',8)]))}const b=a(o,[["render",i]]);export{p as __pageData,b as default}; diff --git a/assets/src_ranuts_file_watchFile.md.6J1Mi6RC.lean.js b/assets/src_ranuts_file_watchFile.md.CRypAqqF.lean.js similarity index 96% rename from assets/src_ranuts_file_watchFile.md.6J1Mi6RC.lean.js rename to assets/src_ranuts_file_watchFile.md.CRypAqqF.lean.js index 53fcace847..2bd8b35865 100644 --- a/assets/src_ranuts_file_watchFile.md.6J1Mi6RC.lean.js +++ b/assets/src_ranuts_file_watchFile.md.CRypAqqF.lean.js @@ -1 +1 @@ -import{_ as a,o as e,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WatchFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/watchFile.md","filePath":"src/ranuts/file/watchFile.md","lastUpdated":1728828157000}'),o={name:"src/ranuts/file/watchFile.md"};function i(h,t,l,n,c,s){return e(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  WatchFile

                  观察一个文件是否改变

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  status文件是否被改变booleantrue 文件改变 false 文件没变

                  Options

                  参数说明类型默认值
                  path文件路径,需要监听的文件stringundefined
                  interval监听文件改变的时间,单位毫秒。number20
                  ',8)]))}const b=a(o,[["render",i]]);export{p as __pageData,b as default}; +import{_ as a,o as e,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WatchFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/watchFile.md","filePath":"src/ranuts/file/watchFile.md","lastUpdated":1728921295000}'),o={name:"src/ranuts/file/watchFile.md"};function i(h,t,l,n,c,s){return e(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  WatchFile

                  观察一个文件是否改变

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  status文件是否被改变booleantrue 文件改变 false 文件没变

                  Options

                  参数说明类型默认值
                  path文件路径,需要监听的文件stringundefined
                  interval监听文件改变的时间,单位毫秒。number20
                  ',8)]))}const b=a(o,[["render",i]]);export{p as __pageData,b as default}; diff --git a/assets/src_ranuts_file_writeFile.md.D0A_cl3U.js b/assets/src_ranuts_file_writeFile.md.ouweFqJg.js similarity index 96% rename from assets/src_ranuts_file_writeFile.md.D0A_cl3U.js rename to assets/src_ranuts_file_writeFile.md.ouweFqJg.js index 09b1239b2a..18a3157cbc 100644 --- a/assets/src_ranuts_file_writeFile.md.D0A_cl3U.js +++ b/assets/src_ranuts_file_writeFile.md.ouweFqJg.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WriteFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/writeFile.md","filePath":"src/ranuts/file/writeFile.md","lastUpdated":1728828157000}'),i={name:"src/ranuts/file/writeFile.md"};function o(n,t,l,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  WriteFile

                  将内容写入文件

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否写入成功booleantrue 成功 false 失败
                  data写入失败的原因,添加成功后的文件内容和文件路径any

                  Options

                  参数说明类型默认值
                  path文件路径,需要追加的文件stringundefined
                  content需要追加的内容string
                  ',8)]))}const b=e(i,[["render",o]]);export{p as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WriteFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/writeFile.md","filePath":"src/ranuts/file/writeFile.md","lastUpdated":1728921295000}'),i={name:"src/ranuts/file/writeFile.md"};function o(n,t,l,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  WriteFile

                  将内容写入文件

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否写入成功booleantrue 成功 false 失败
                  data写入失败的原因,添加成功后的文件内容和文件路径any

                  Options

                  参数说明类型默认值
                  path文件路径,需要追加的文件stringundefined
                  content需要追加的内容string
                  ',8)]))}const b=e(i,[["render",o]]);export{p as __pageData,b as default}; diff --git a/assets/src_ranuts_file_writeFile.md.D0A_cl3U.lean.js b/assets/src_ranuts_file_writeFile.md.ouweFqJg.lean.js similarity index 96% rename from assets/src_ranuts_file_writeFile.md.D0A_cl3U.lean.js rename to assets/src_ranuts_file_writeFile.md.ouweFqJg.lean.js index 09b1239b2a..18a3157cbc 100644 --- a/assets/src_ranuts_file_writeFile.md.D0A_cl3U.lean.js +++ b/assets/src_ranuts_file_writeFile.md.ouweFqJg.lean.js @@ -1 +1 @@ -import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WriteFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/writeFile.md","filePath":"src/ranuts/file/writeFile.md","lastUpdated":1728828157000}'),i={name:"src/ranuts/file/writeFile.md"};function o(n,t,l,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  WriteFile

                  将内容写入文件

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否写入成功booleantrue 成功 false 失败
                  data写入失败的原因,添加成功后的文件内容和文件路径any

                  Options

                  参数说明类型默认值
                  path文件路径,需要追加的文件stringundefined
                  content需要追加的内容string
                  ',8)]))}const b=e(i,[["render",o]]);export{p as __pageData,b as default}; +import{_ as e,o as a,c as d,a3 as r}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"WriteFile","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/file/writeFile.md","filePath":"src/ranuts/file/writeFile.md","lastUpdated":1728921295000}'),i={name:"src/ranuts/file/writeFile.md"};function o(n,t,l,h,s,c){return a(),d("div",{"data-pagefind-body":!0},t[0]||(t[0]=[r('

                  WriteFile

                  将内容写入文件

                  API

                  Return

                  • Promise
                  参数说明类型描述
                  success是否写入成功booleantrue 成功 false 失败
                  data写入失败的原因,添加成功后的文件内容和文件路径any

                  Options

                  参数说明类型默认值
                  path文件路径,需要追加的文件stringundefined
                  content需要追加的内容string
                  ',8)]))}const b=e(i,[["render",o]]);export{p as __pageData,b as default}; diff --git a/assets/src_ranuts_index.md.Q_PSqhjV.js b/assets/src_ranuts_index.md.DZGRxbxI.js similarity index 97% rename from assets/src_ranuts_index.md.Q_PSqhjV.js rename to assets/src_ranuts_index.md.DZGRxbxI.js index 8707e3c609..083b82884b 100644 --- a/assets/src_ranuts_index.md.Q_PSqhjV.js +++ b/assets/src_ranuts_index.md.DZGRxbxI.js @@ -1 +1 @@ -import{_ as r,o as d,c as a,a3 as i,G as o,B as l}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ranuts overview","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/index.md","filePath":"src/ranuts/index.md","lastUpdated":1728828157000}'),h={name:"src/ranuts/index.md"};function s(n,t,f,m,c,u){const e=l("TOTP");return d(),a("div",{"data-pagefind-body":!0},[t[0]||(t[0]=i('

                  ranuts overview

                  Method list

                  Methoddescriptiondetail
                  writeFileWrite to filewriteFile
                  readFileRead filereadFile
                  readDirRead the directory and get the names of all the files in the directoryreadDir
                  watchFileCheck whether the contents of the file have changedwatchFile
                  queryFileInfoQuery file informationqueryFileInfo
                  filterObjFilter objectfilterObj
                  EventEmitterPublish-subscribe classEventEmitter
                  str2XmlString is converted to xmlstr2Xml
                  getMimeGets the mime type based on the file format suffixgetMime
                  getCookieGets the value of the specified cookiewriteFile
                  formatJsonFormatted JSONformatJson

                  TOTP

                  ',4)),o(e)])}const v=r(h,[["render",s]]);export{p as __pageData,v as default}; +import{_ as r,o as d,c as a,a3 as i,G as o,B as l}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ranuts overview","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/index.md","filePath":"src/ranuts/index.md","lastUpdated":1728921295000}'),h={name:"src/ranuts/index.md"};function s(n,t,f,m,c,u){const e=l("TOTP");return d(),a("div",{"data-pagefind-body":!0},[t[0]||(t[0]=i('

                  ranuts overview

                  Method list

                  Methoddescriptiondetail
                  writeFileWrite to filewriteFile
                  readFileRead filereadFile
                  readDirRead the directory and get the names of all the files in the directoryreadDir
                  watchFileCheck whether the contents of the file have changedwatchFile
                  queryFileInfoQuery file informationqueryFileInfo
                  filterObjFilter objectfilterObj
                  EventEmitterPublish-subscribe classEventEmitter
                  str2XmlString is converted to xmlstr2Xml
                  getMimeGets the mime type based on the file format suffixgetMime
                  getCookieGets the value of the specified cookiewriteFile
                  formatJsonFormatted JSONformatJson

                  TOTP

                  ',4)),o(e)])}const v=r(h,[["render",s]]);export{p as __pageData,v as default}; diff --git a/assets/src_ranuts_index.md.Q_PSqhjV.lean.js b/assets/src_ranuts_index.md.DZGRxbxI.lean.js similarity index 97% rename from assets/src_ranuts_index.md.Q_PSqhjV.lean.js rename to assets/src_ranuts_index.md.DZGRxbxI.lean.js index 8707e3c609..083b82884b 100644 --- a/assets/src_ranuts_index.md.Q_PSqhjV.lean.js +++ b/assets/src_ranuts_index.md.DZGRxbxI.lean.js @@ -1 +1 @@ -import{_ as r,o as d,c as a,a3 as i,G as o,B as l}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ranuts overview","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/index.md","filePath":"src/ranuts/index.md","lastUpdated":1728828157000}'),h={name:"src/ranuts/index.md"};function s(n,t,f,m,c,u){const e=l("TOTP");return d(),a("div",{"data-pagefind-body":!0},[t[0]||(t[0]=i('

                  ranuts overview

                  Method list

                  Methoddescriptiondetail
                  writeFileWrite to filewriteFile
                  readFileRead filereadFile
                  readDirRead the directory and get the names of all the files in the directoryreadDir
                  watchFileCheck whether the contents of the file have changedwatchFile
                  queryFileInfoQuery file informationqueryFileInfo
                  filterObjFilter objectfilterObj
                  EventEmitterPublish-subscribe classEventEmitter
                  str2XmlString is converted to xmlstr2Xml
                  getMimeGets the mime type based on the file format suffixgetMime
                  getCookieGets the value of the specified cookiewriteFile
                  formatJsonFormatted JSONformatJson

                  TOTP

                  ',4)),o(e)])}const v=r(h,[["render",s]]);export{p as __pageData,v as default}; +import{_ as r,o as d,c as a,a3 as i,G as o,B as l}from"./chunks/framework.BYE6xntm.js";const p=JSON.parse('{"title":"ranuts overview","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/index.md","filePath":"src/ranuts/index.md","lastUpdated":1728921295000}'),h={name:"src/ranuts/index.md"};function s(n,t,f,m,c,u){const e=l("TOTP");return d(),a("div",{"data-pagefind-body":!0},[t[0]||(t[0]=i('

                  ranuts overview

                  Method list

                  Methoddescriptiondetail
                  writeFileWrite to filewriteFile
                  readFileRead filereadFile
                  readDirRead the directory and get the names of all the files in the directoryreadDir
                  watchFileCheck whether the contents of the file have changedwatchFile
                  queryFileInfoQuery file informationqueryFileInfo
                  filterObjFilter objectfilterObj
                  EventEmitterPublish-subscribe classEventEmitter
                  str2XmlString is converted to xmlstr2Xml
                  getMimeGets the mime type based on the file format suffixgetMime
                  getCookieGets the value of the specified cookiewriteFile
                  formatJsonFormatted JSONformatJson

                  TOTP

                  ',4)),o(e)])}const v=r(h,[["render",s]]);export{p as __pageData,v as default}; diff --git a/assets/src_ranuts_mimeType_mimeType.md.CD3nVZEO.js b/assets/src_ranuts_mimeType_mimeType.md.CxFL5631.js similarity index 98% rename from assets/src_ranuts_mimeType_mimeType.md.CD3nVZEO.js rename to assets/src_ranuts_mimeType_mimeType.md.CxFL5631.js index f53be6f3bd..d9e23e51c9 100644 --- a/assets/src_ranuts_mimeType_mimeType.md.CD3nVZEO.js +++ b/assets/src_ranuts_mimeType_mimeType.md.CxFL5631.js @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as t,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getMime","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/mimeType/mimeType.md","filePath":"src/ranuts/mimeType/mimeType.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/mimeType/mimeType.md"};function h(l,s,p,r,d,k){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

                  getMime

                  传入文件格式后缀,返回mime type

                  API

                  Return

                  参数说明类型
                  string返回mime typestring

                  Options

                  参数说明类型默认值
                  ext文件后缀格式string

                  Example

                  js
                  import { getMime } from 'ranuts';
                  +import{_ as i,o as a,c as t,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getMime","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/mimeType/mimeType.md","filePath":"src/ranuts/mimeType/mimeType.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/mimeType/mimeType.md"};function h(l,s,p,r,d,k){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

                  getMime

                  传入文件格式后缀,返回mime type

                  API

                  Return

                  参数说明类型
                  string返回mime typestring

                  Options

                  参数说明类型默认值
                  ext文件后缀格式string

                  Example

                  js
                  import { getMime } from 'ranuts';
                   
                   const result = getMime('.pptx');
                   console.log(result);
                  diff --git a/assets/src_ranuts_mimeType_mimeType.md.CD3nVZEO.lean.js b/assets/src_ranuts_mimeType_mimeType.md.CxFL5631.lean.js
                  similarity index 98%
                  rename from assets/src_ranuts_mimeType_mimeType.md.CD3nVZEO.lean.js
                  rename to assets/src_ranuts_mimeType_mimeType.md.CxFL5631.lean.js
                  index f53be6f3bd..d9e23e51c9 100644
                  --- a/assets/src_ranuts_mimeType_mimeType.md.CD3nVZEO.lean.js
                  +++ b/assets/src_ranuts_mimeType_mimeType.md.CxFL5631.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as t,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getMime","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/mimeType/mimeType.md","filePath":"src/ranuts/mimeType/mimeType.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/mimeType/mimeType.md"};function h(l,s,p,r,d,k){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

                  getMime

                  传入文件格式后缀,返回mime type

                  API

                  Return

                  参数说明类型
                  string返回mime typestring

                  Options

                  参数说明类型默认值
                  ext文件后缀格式string

                  Example

                  js
                  import { getMime } from 'ranuts';
                  +import{_ as i,o as a,c as t,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getMime","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/mimeType/mimeType.md","filePath":"src/ranuts/mimeType/mimeType.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/mimeType/mimeType.md"};function h(l,s,p,r,d,k){return a(),t("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

                  getMime

                  传入文件格式后缀,返回mime type

                  API

                  Return

                  参数说明类型
                  string返回mime typestring

                  Options

                  参数说明类型默认值
                  ext文件后缀格式string

                  Example

                  js
                  import { getMime } from 'ranuts';
                   
                   const result = getMime('.pptx');
                   console.log(result);
                  diff --git a/assets/src_ranuts_mode_subscribe.md.CtPQvPCj.js b/assets/src_ranuts_mode_subscribe.md.Psp8bIgo.js
                  similarity index 99%
                  rename from assets/src_ranuts_mode_subscribe.md.CtPQvPCj.js
                  rename to assets/src_ranuts_mode_subscribe.md.Psp8bIgo.js
                  index d0cb4faf99..e039829a14 100644
                  --- a/assets/src_ranuts_mode_subscribe.md.CtPQvPCj.js
                  +++ b/assets/src_ranuts_mode_subscribe.md.Psp8bIgo.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as n,a3 as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"EventEmitter","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/mode/subscribe.md","filePath":"src/ranuts/mode/subscribe.md","lastUpdated":1728828157000}'),h={name:"src/ranuts/mode/subscribe.md"};function l(k,s,p,e,E,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

                  EventEmitter

                  发布订阅的类

                  Class

                  Methods

                  方法参数说明默认值
                  on订阅事件订阅事件,传入参数事件名,回调函数
                  once订阅一次事件,传入参数事件名,回调函数订阅一次事件,触发一次后不再会触发
                  off取消订阅事件,传入参数事件名,回调函数取消订阅事件
                  emit触发事件,需要事件名触发事件

                  Example

                  js
                  import { Subscribe } from 'ranuts';
                  +import{_ as i,o as a,c as n,a3 as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"EventEmitter","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/mode/subscribe.md","filePath":"src/ranuts/mode/subscribe.md","lastUpdated":1728921295000}'),h={name:"src/ranuts/mode/subscribe.md"};function l(k,s,p,e,E,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

                  EventEmitter

                  发布订阅的类

                  Class

                  Methods

                  方法参数说明默认值
                  on订阅事件订阅事件,传入参数事件名,回调函数
                  once订阅一次事件,传入参数事件名,回调函数订阅一次事件,触发一次后不再会触发
                  off取消订阅事件,传入参数事件名,回调函数取消订阅事件
                  emit触发事件,需要事件名触发事件

                  Example

                  js
                  import { Subscribe } from 'ranuts';
                   
                   const subscribe = new Subscribe();
                   
                  diff --git a/assets/src_ranuts_mode_subscribe.md.CtPQvPCj.lean.js b/assets/src_ranuts_mode_subscribe.md.Psp8bIgo.lean.js
                  similarity index 99%
                  rename from assets/src_ranuts_mode_subscribe.md.CtPQvPCj.lean.js
                  rename to assets/src_ranuts_mode_subscribe.md.Psp8bIgo.lean.js
                  index d0cb4faf99..e039829a14 100644
                  --- a/assets/src_ranuts_mode_subscribe.md.CtPQvPCj.lean.js
                  +++ b/assets/src_ranuts_mode_subscribe.md.Psp8bIgo.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as n,a3 as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"EventEmitter","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/mode/subscribe.md","filePath":"src/ranuts/mode/subscribe.md","lastUpdated":1728828157000}'),h={name:"src/ranuts/mode/subscribe.md"};function l(k,s,p,e,E,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

                  EventEmitter

                  发布订阅的类

                  Class

                  Methods

                  方法参数说明默认值
                  on订阅事件订阅事件,传入参数事件名,回调函数
                  once订阅一次事件,传入参数事件名,回调函数订阅一次事件,触发一次后不再会触发
                  off取消订阅事件,传入参数事件名,回调函数取消订阅事件
                  emit触发事件,需要事件名触发事件

                  Example

                  js
                  import { Subscribe } from 'ranuts';
                  +import{_ as i,o as a,c as n,a3 as t}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"EventEmitter","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/mode/subscribe.md","filePath":"src/ranuts/mode/subscribe.md","lastUpdated":1728921295000}'),h={name:"src/ranuts/mode/subscribe.md"};function l(k,s,p,e,E,r){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t(`

                  EventEmitter

                  发布订阅的类

                  Class

                  Methods

                  方法参数说明默认值
                  on订阅事件订阅事件,传入参数事件名,回调函数
                  once订阅一次事件,传入参数事件名,回调函数订阅一次事件,触发一次后不再会触发
                  off取消订阅事件,传入参数事件名,回调函数取消订阅事件
                  emit触发事件,需要事件名触发事件

                  Example

                  js
                  import { Subscribe } from 'ranuts';
                   
                   const subscribe = new Subscribe();
                   
                  diff --git a/assets/src_ranuts_utils_convertImageToBase64.md.CGjlmYhP.js b/assets/src_ranuts_utils_convertImageToBase64.md.BvH8a7ux.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_convertImageToBase64.md.CGjlmYhP.js
                  rename to assets/src_ranuts_utils_convertImageToBase64.md.BvH8a7ux.js
                  index 8c81cd8299..f2da2e6188 100644
                  --- a/assets/src_ranuts_utils_convertImageToBase64.md.CGjlmYhP.js
                  +++ b/assets/src_ranuts_utils_convertImageToBase64.md.BvH8a7ux.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,o as e,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"convertImageToBase64","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/convertImageToBase64.md","filePath":"src/ranuts/utils/convertImageToBase64.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/utils/convertImageToBase64.md"};function r(o,t,d,h,l,c){return e(),s("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  convertImageToBase64

                  Picture turn 'base64'

                  API

                  Return

                  argumentInstructionstype
                  successWhether the conversion is successfulboolean
                  dataThe value after successful conversionstring,ArrayBuffer , null
                  messageThe reasons why the conversion succeeds or failsstring

                  Options

                  argumentInstructionstypeDefault value
                  fileIncoming fileFilenull

                  Example

                  js
                  import { convertImageToBase64 } from 'ranuts';
                  +import{_ as a,o as e,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"convertImageToBase64","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/convertImageToBase64.md","filePath":"src/ranuts/utils/convertImageToBase64.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/utils/convertImageToBase64.md"};function r(o,t,d,h,l,c){return e(),s("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  convertImageToBase64

                  Picture turn 'base64'

                  API

                  Return

                  argumentInstructionstype
                  successWhether the conversion is successfulboolean
                  dataThe value after successful conversionstring,ArrayBuffer , null
                  messageThe reasons why the conversion succeeds or failsstring

                  Options

                  argumentInstructionstypeDefault value
                  fileIncoming fileFilenull

                  Example

                  js
                  import { convertImageToBase64 } from 'ranuts';
                   
                   convertImageToBase64(file).then((res) => {
                     console.log(result);
                  diff --git a/assets/src_ranuts_utils_convertImageToBase64.md.CGjlmYhP.lean.js b/assets/src_ranuts_utils_convertImageToBase64.md.BvH8a7ux.lean.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_convertImageToBase64.md.CGjlmYhP.lean.js
                  rename to assets/src_ranuts_utils_convertImageToBase64.md.BvH8a7ux.lean.js
                  index 8c81cd8299..f2da2e6188 100644
                  --- a/assets/src_ranuts_utils_convertImageToBase64.md.CGjlmYhP.lean.js
                  +++ b/assets/src_ranuts_utils_convertImageToBase64.md.BvH8a7ux.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,o as e,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"convertImageToBase64","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/convertImageToBase64.md","filePath":"src/ranuts/utils/convertImageToBase64.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/utils/convertImageToBase64.md"};function r(o,t,d,h,l,c){return e(),s("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  convertImageToBase64

                  Picture turn 'base64'

                  API

                  Return

                  argumentInstructionstype
                  successWhether the conversion is successfulboolean
                  dataThe value after successful conversionstring,ArrayBuffer , null
                  messageThe reasons why the conversion succeeds or failsstring

                  Options

                  argumentInstructionstypeDefault value
                  fileIncoming fileFilenull

                  Example

                  js
                  import { convertImageToBase64 } from 'ranuts';
                  +import{_ as a,o as e,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"convertImageToBase64","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/convertImageToBase64.md","filePath":"src/ranuts/utils/convertImageToBase64.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/utils/convertImageToBase64.md"};function r(o,t,d,h,l,c){return e(),s("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  convertImageToBase64

                  Picture turn 'base64'

                  API

                  Return

                  argumentInstructionstype
                  successWhether the conversion is successfulboolean
                  dataThe value after successful conversionstring,ArrayBuffer , null
                  messageThe reasons why the conversion succeeds or failsstring

                  Options

                  argumentInstructionstypeDefault value
                  fileIncoming fileFilenull

                  Example

                  js
                  import { convertImageToBase64 } from 'ranuts';
                   
                   convertImageToBase64(file).then((res) => {
                     console.log(result);
                  diff --git a/assets/src_ranuts_utils_filterObj.md.BsaBmsvk.js b/assets/src_ranuts_utils_filterObj.md.BtAgodt-.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_filterObj.md.BsaBmsvk.js
                  rename to assets/src_ranuts_utils_filterObj.md.BtAgodt-.js
                  index 8b53fa77cd..417d4f2e5c 100644
                  --- a/assets/src_ranuts_utils_filterObj.md.BsaBmsvk.js
                  +++ b/assets/src_ranuts_utils_filterObj.md.BtAgodt-.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,o as t,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"filterObj","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/filterObj.md","filePath":"src/ranuts/utils/filterObj.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/utils/filterObj.md"};function l(h,s,r,p,d,k){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

                  filterObj

                  Filter the properties of the object, remove the properties of the object in the list array, return a new object, usually used to remove null characters and null

                  API

                  Return

                  argumentInstructionstype
                  ObjectReturn an objectObject

                  Options

                  argumentInstructionstypeDefault value
                  objObjects to be filteredobject
                  listFamiliar array to filterarray

                  Example

                  js
                  import { filterObj } from 'ranuts';
                  +import{_ as a,o as t,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"filterObj","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/filterObj.md","filePath":"src/ranuts/utils/filterObj.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/utils/filterObj.md"};function l(h,s,r,p,d,k){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

                  filterObj

                  Filter the properties of the object, remove the properties of the object in the list array, return a new object, usually used to remove null characters and null

                  API

                  Return

                  argumentInstructionstype
                  ObjectReturn an objectObject

                  Options

                  argumentInstructionstypeDefault value
                  objObjects to be filteredobject
                  listFamiliar array to filterarray

                  Example

                  js
                  import { filterObj } from 'ranuts';
                   
                   const obj = {
                     name: 'chaxus',
                  diff --git a/assets/src_ranuts_utils_filterObj.md.BsaBmsvk.lean.js b/assets/src_ranuts_utils_filterObj.md.BtAgodt-.lean.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_filterObj.md.BsaBmsvk.lean.js
                  rename to assets/src_ranuts_utils_filterObj.md.BtAgodt-.lean.js
                  index 8b53fa77cd..417d4f2e5c 100644
                  --- a/assets/src_ranuts_utils_filterObj.md.BsaBmsvk.lean.js
                  +++ b/assets/src_ranuts_utils_filterObj.md.BtAgodt-.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,o as t,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"filterObj","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/filterObj.md","filePath":"src/ranuts/utils/filterObj.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/utils/filterObj.md"};function l(h,s,r,p,d,k){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

                  filterObj

                  Filter the properties of the object, remove the properties of the object in the list array, return a new object, usually used to remove null characters and null

                  API

                  Return

                  argumentInstructionstype
                  ObjectReturn an objectObject

                  Options

                  argumentInstructionstypeDefault value
                  objObjects to be filteredobject
                  listFamiliar array to filterarray

                  Example

                  js
                  import { filterObj } from 'ranuts';
                  +import{_ as a,o as t,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"filterObj","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/filterObj.md","filePath":"src/ranuts/utils/filterObj.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/utils/filterObj.md"};function l(h,s,r,p,d,k){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[e(`

                  filterObj

                  Filter the properties of the object, remove the properties of the object in the list array, return a new object, usually used to remove null characters and null

                  API

                  Return

                  argumentInstructionstype
                  ObjectReturn an objectObject

                  Options

                  argumentInstructionstypeDefault value
                  objObjects to be filteredobject
                  listFamiliar array to filterarray

                  Example

                  js
                  import { filterObj } from 'ranuts';
                   
                   const obj = {
                     name: 'chaxus',
                  diff --git a/assets/src_ranuts_utils_formatJson.md.DNKXhroe.js b/assets/src_ranuts_utils_formatJson.md.CSMLr8Hr.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_formatJson.md.DNKXhroe.js
                  rename to assets/src_ranuts_utils_formatJson.md.CSMLr8Hr.js
                  index 6b9685f572..51fa61d58c 100644
                  --- a/assets/src_ranuts_utils_formatJson.md.DNKXhroe.js
                  +++ b/assets/src_ranuts_utils_formatJson.md.CSMLr8Hr.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,o as t,c as i,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"formatJson","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/formatJson.md","filePath":"src/ranuts/utils/formatJson.md","lastUpdated":1728828157000}'),e={name:"src/ranuts/utils/formatJson.md"};function l(r,s,h,o,d,p){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  formatJson

                  Pass in a JSON or JSON string, add Spaces and newlines to return a formatted JSON string

                  API

                  Return

                  argumentInstructionstype
                  stringReturn an objectObject

                  Options

                  argumentInstructionstypeDefault value
                  jsonJSON objects that need to be formattedobject,stringnull
                  callbackError callback, optionalfunctionnull

                  Example

                  js
                  import { formatJson } from 'ranuts';
                  +import{_ as a,o as t,c as i,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"formatJson","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/formatJson.md","filePath":"src/ranuts/utils/formatJson.md","lastUpdated":1728921295000}'),e={name:"src/ranuts/utils/formatJson.md"};function l(r,s,h,o,d,p){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  formatJson

                  Pass in a JSON or JSON string, add Spaces and newlines to return a formatted JSON string

                  API

                  Return

                  argumentInstructionstype
                  stringReturn an objectObject

                  Options

                  argumentInstructionstypeDefault value
                  jsonJSON objects that need to be formattedobject,stringnull
                  callbackError callback, optionalfunctionnull

                  Example

                  js
                  import { formatJson } from 'ranuts';
                   
                   const json = {
                     name: 'chaxus',
                  diff --git a/assets/src_ranuts_utils_formatJson.md.DNKXhroe.lean.js b/assets/src_ranuts_utils_formatJson.md.CSMLr8Hr.lean.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_formatJson.md.DNKXhroe.lean.js
                  rename to assets/src_ranuts_utils_formatJson.md.CSMLr8Hr.lean.js
                  index 6b9685f572..51fa61d58c 100644
                  --- a/assets/src_ranuts_utils_formatJson.md.DNKXhroe.lean.js
                  +++ b/assets/src_ranuts_utils_formatJson.md.CSMLr8Hr.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,o as t,c as i,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"formatJson","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/formatJson.md","filePath":"src/ranuts/utils/formatJson.md","lastUpdated":1728828157000}'),e={name:"src/ranuts/utils/formatJson.md"};function l(r,s,h,o,d,p){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  formatJson

                  Pass in a JSON or JSON string, add Spaces and newlines to return a formatted JSON string

                  API

                  Return

                  argumentInstructionstype
                  stringReturn an objectObject

                  Options

                  argumentInstructionstypeDefault value
                  jsonJSON objects that need to be formattedobject,stringnull
                  callbackError callback, optionalfunctionnull

                  Example

                  js
                  import { formatJson } from 'ranuts';
                  +import{_ as a,o as t,c as i,a3 as n}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"formatJson","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/formatJson.md","filePath":"src/ranuts/utils/formatJson.md","lastUpdated":1728921295000}'),e={name:"src/ranuts/utils/formatJson.md"};function l(r,s,h,o,d,p){return t(),i("div",{"data-pagefind-body":!0},s[0]||(s[0]=[n(`

                  formatJson

                  Pass in a JSON or JSON string, add Spaces and newlines to return a formatted JSON string

                  API

                  Return

                  argumentInstructionstype
                  stringReturn an objectObject

                  Options

                  argumentInstructionstypeDefault value
                  jsonJSON objects that need to be formattedobject,stringnull
                  callbackError callback, optionalfunctionnull

                  Example

                  js
                  import { formatJson } from 'ranuts';
                   
                   const json = {
                     name: 'chaxus',
                  diff --git a/assets/src_ranuts_utils_getCookie.md.CDeVa4hl.js b/assets/src_ranuts_utils_getCookie.md.C9JVGfW9.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_getCookie.md.CDeVa4hl.js
                  rename to assets/src_ranuts_utils_getCookie.md.C9JVGfW9.js
                  index d41b4fac46..6e7c0b1f98 100644
                  --- a/assets/src_ranuts_utils_getCookie.md.CDeVa4hl.js
                  +++ b/assets/src_ranuts_utils_getCookie.md.C9JVGfW9.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,o as e,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getCookie","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/getCookie.md","filePath":"src/ranuts/utils/getCookie.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/utils/getCookie.md"};function h(o,t,l,r,d,p){return e(),s("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  getCookie

                  Pass in a string to get the value of the cookie with the specified name

                  API

                  Return

                  argumentInstructionstype
                  stingReturns the value of a cookie with the specified namestring

                  Options

                  argumentInstructionstypeDefault value
                  nameSpecifies the value of the name that gets the cookieobject

                  Example

                  js
                  import { getCookie } from 'ranuts';
                  +import{_ as a,o as e,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getCookie","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/getCookie.md","filePath":"src/ranuts/utils/getCookie.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/utils/getCookie.md"};function h(o,t,l,r,d,p){return e(),s("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  getCookie

                  Pass in a string to get the value of the cookie with the specified name

                  API

                  Return

                  argumentInstructionstype
                  stingReturns the value of a cookie with the specified namestring

                  Options

                  argumentInstructionstypeDefault value
                  nameSpecifies the value of the name that gets the cookieobject

                  Example

                  js
                  import { getCookie } from 'ranuts';
                   
                   const result = getCookie('name');
                   
                  diff --git a/assets/src_ranuts_utils_getCookie.md.CDeVa4hl.lean.js b/assets/src_ranuts_utils_getCookie.md.C9JVGfW9.lean.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_getCookie.md.CDeVa4hl.lean.js
                  rename to assets/src_ranuts_utils_getCookie.md.C9JVGfW9.lean.js
                  index d41b4fac46..6e7c0b1f98 100644
                  --- a/assets/src_ranuts_utils_getCookie.md.CDeVa4hl.lean.js
                  +++ b/assets/src_ranuts_utils_getCookie.md.C9JVGfW9.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as a,o as e,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getCookie","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/getCookie.md","filePath":"src/ranuts/utils/getCookie.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/utils/getCookie.md"};function h(o,t,l,r,d,p){return e(),s("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  getCookie

                  Pass in a string to get the value of the cookie with the specified name

                  API

                  Return

                  argumentInstructionstype
                  stingReturns the value of a cookie with the specified namestring

                  Options

                  argumentInstructionstypeDefault value
                  nameSpecifies the value of the name that gets the cookieobject

                  Example

                  js
                  import { getCookie } from 'ranuts';
                  +import{_ as a,o as e,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"getCookie","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/getCookie.md","filePath":"src/ranuts/utils/getCookie.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/utils/getCookie.md"};function h(o,t,l,r,d,p){return e(),s("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  getCookie

                  Pass in a string to get the value of the cookie with the specified name

                  API

                  Return

                  argumentInstructionstype
                  stingReturns the value of a cookie with the specified namestring

                  Options

                  argumentInstructionstypeDefault value
                  nameSpecifies the value of the name that gets the cookieobject

                  Example

                  js
                  import { getCookie } from 'ranuts';
                   
                   const result = getCookie('name');
                   
                  diff --git a/assets/src_ranuts_utils_ocr.md.l96JLeA3.js b/assets/src_ranuts_utils_ocr.md.DzafMtkn.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_ocr.md.l96JLeA3.js
                  rename to assets/src_ranuts_utils_ocr.md.DzafMtkn.js
                  index 91a814d03b..141ed3a794 100644
                  --- a/assets/src_ranuts_utils_ocr.md.l96JLeA3.js
                  +++ b/assets/src_ranuts_utils_ocr.md.DzafMtkn.js
                  @@ -1,4 +1,4 @@
                  -import{_ as d,o as a,c as r,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"OCR","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/ocr.md","filePath":"src/ranuts/utils/ocr.md","lastUpdated":1728828157000}'),s={name:"src/ranuts/utils/ocr.md"};function e(n,t,l,h,o,p){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  OCR

                  Pass in the image and the corresponding language type, and return the text in the image.

                  API

                  Return

                  argumentInstructionstype
                  successWhether the resolution is successfulboolean
                  dataThe object is parsed successfullyobj
                  messageAnalyze the reasons for success or failurestring

                  Options

                  argumentInstructionstypeDefault value
                  imagesAn array of images, supporting 'url' and 'base64'Array<string>null
                  languageSpecify the language in which the text will be generatedlang-codestring
                  langPathWhen using it, you need to be able to access cdn.jsdelivr.net, which will download the corresponding language package, if you cannot access it, you can also put the language package locally, passing the corresponding directory pathstringThis parameter is optional. By default, download from the network

                  Example

                  js
                  import { ocr } from 'ranuts';
                  +import{_ as d,o as a,c as r,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"OCR","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/ocr.md","filePath":"src/ranuts/utils/ocr.md","lastUpdated":1728921295000}'),s={name:"src/ranuts/utils/ocr.md"};function e(n,t,l,h,o,p){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  OCR

                  Pass in the image and the corresponding language type, and return the text in the image.

                  API

                  Return

                  argumentInstructionstype
                  successWhether the resolution is successfulboolean
                  dataThe object is parsed successfullyobj
                  messageAnalyze the reasons for success or failurestring

                  Options

                  argumentInstructionstypeDefault value
                  imagesAn array of images, supporting 'url' and 'base64'Array<string>null
                  languageSpecify the language in which the text will be generatedlang-codestring
                  langPathWhen using it, you need to be able to access cdn.jsdelivr.net, which will download the corresponding language package, if you cannot access it, you can also put the language package locally, passing the corresponding directory pathstringThis parameter is optional. By default, download from the network

                  Example

                  js
                  import { ocr } from 'ranuts';
                   
                   const images = ['https://chaxus.github.io/ran/ocr/eng.png'];
                   const languages = 'eng';
                  diff --git a/assets/src_ranuts_utils_ocr.md.l96JLeA3.lean.js b/assets/src_ranuts_utils_ocr.md.DzafMtkn.lean.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_ocr.md.l96JLeA3.lean.js
                  rename to assets/src_ranuts_utils_ocr.md.DzafMtkn.lean.js
                  index 91a814d03b..141ed3a794 100644
                  --- a/assets/src_ranuts_utils_ocr.md.l96JLeA3.lean.js
                  +++ b/assets/src_ranuts_utils_ocr.md.DzafMtkn.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as d,o as a,c as r,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"OCR","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/ocr.md","filePath":"src/ranuts/utils/ocr.md","lastUpdated":1728828157000}'),s={name:"src/ranuts/utils/ocr.md"};function e(n,t,l,h,o,p){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  OCR

                  Pass in the image and the corresponding language type, and return the text in the image.

                  API

                  Return

                  argumentInstructionstype
                  successWhether the resolution is successfulboolean
                  dataThe object is parsed successfullyobj
                  messageAnalyze the reasons for success or failurestring

                  Options

                  argumentInstructionstypeDefault value
                  imagesAn array of images, supporting 'url' and 'base64'Array<string>null
                  languageSpecify the language in which the text will be generatedlang-codestring
                  langPathWhen using it, you need to be able to access cdn.jsdelivr.net, which will download the corresponding language package, if you cannot access it, you can also put the language package locally, passing the corresponding directory pathstringThis parameter is optional. By default, download from the network

                  Example

                  js
                  import { ocr } from 'ranuts';
                  +import{_ as d,o as a,c as r,a3 as i}from"./chunks/framework.BYE6xntm.js";const c=JSON.parse('{"title":"OCR","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/ocr.md","filePath":"src/ranuts/utils/ocr.md","lastUpdated":1728921295000}'),s={name:"src/ranuts/utils/ocr.md"};function e(n,t,l,h,o,p){return a(),r("div",{"data-pagefind-body":!0},t[0]||(t[0]=[i(`

                  OCR

                  Pass in the image and the corresponding language type, and return the text in the image.

                  API

                  Return

                  argumentInstructionstype
                  successWhether the resolution is successfulboolean
                  dataThe object is parsed successfullyobj
                  messageAnalyze the reasons for success or failurestring

                  Options

                  argumentInstructionstypeDefault value
                  imagesAn array of images, supporting 'url' and 'base64'Array<string>null
                  languageSpecify the language in which the text will be generatedlang-codestring
                  langPathWhen using it, you need to be able to access cdn.jsdelivr.net, which will download the corresponding language package, if you cannot access it, you can also put the language package locally, passing the corresponding directory pathstringThis parameter is optional. By default, download from the network

                  Example

                  js
                  import { ocr } from 'ranuts';
                   
                   const images = ['https://chaxus.github.io/ran/ocr/eng.png'];
                   const languages = 'eng';
                  diff --git a/assets/src_ranuts_utils_str2xml.md.CwgfkeY1.js b/assets/src_ranuts_utils_str2xml.md.DiJE8okl.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_str2xml.md.CwgfkeY1.js
                  rename to assets/src_ranuts_utils_str2xml.md.DiJE8okl.js
                  index 96ac00dab4..502a1b2cf3 100644
                  --- a/assets/src_ranuts_utils_str2xml.md.CwgfkeY1.js
                  +++ b/assets/src_ranuts_utils_str2xml.md.DiJE8okl.js
                  @@ -1,4 +1,4 @@
                  -import{_ as s,o as a,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"str2Xml","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/str2xml.md","filePath":"src/ranuts/utils/str2xml.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/utils/str2xml.md"};function l(r,t,h,d,o,p){return a(),i("div",{"data-pagefind-body":!0},t[0]||(t[0]=[e(`

                  str2Xml

                  Pass in a string and convert it to 'xml'

                  API

                  Return

                  argumentInstructionstype
                  HTMLElement返回一个HTMLElementHTMLElement

                  Options

                  argumentInstructionstypeDefault value
                  xmlStrIncoming parameterstringnull
                  formatSet the format to be converted. The default is' text/xml '' DOMParserSupportedType 'null

                  Example

                  For example, when doing icon library, we need to dynamically import all the 'ICONS' in the directory. In this case, strings are imported, but strings cannot be added to 'xml'. So we need to convert the string to 'xml', and then we can add it to 'xml'.

                  js
                  import { str2Xml } from 'ranuts';
                  +import{_ as s,o as a,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"str2Xml","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/str2xml.md","filePath":"src/ranuts/utils/str2xml.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/utils/str2xml.md"};function l(r,t,h,d,o,p){return a(),i("div",{"data-pagefind-body":!0},t[0]||(t[0]=[e(`

                  str2Xml

                  Pass in a string and convert it to 'xml'

                  API

                  Return

                  argumentInstructionstype
                  HTMLElement返回一个HTMLElementHTMLElement

                  Options

                  argumentInstructionstypeDefault value
                  xmlStrIncoming parameterstringnull
                  formatSet the format to be converted. The default is' text/xml '' DOMParserSupportedType 'null

                  Example

                  For example, when doing icon library, we need to dynamically import all the 'ICONS' in the directory. In this case, strings are imported, but strings cannot be added to 'xml'. So we need to convert the string to 'xml', and then we can add it to 'xml'.

                  js
                  import { str2Xml } from 'ranuts';
                   
                   // import 'assets/*.svg'
                   const svg = \`<svg t="1667483498347" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8544" width="200" height="200"><path d="M858.5 763.6c-18.9-44.8-46.1-85-80.6-119.5-34.5-34.5-74.7-61.6-119.5-80.6-0.4-0.2-0.8-0.3-1.2-0.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-0.4 0.2-0.8 0.3-1.2 0.5-44.8 18.9-85 46-119.5 80.6-34.5 34.5-61.6 74.7-80.6 119.5C146.9 807.5 137 854 136 901.8c-0.1 4.5 3.5 8.2 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c0.1 4.4 3.6 7.8 8 7.8h60c4.5 0 8.1-3.7 8-8.2-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z" p-id="8545"></path></svg>\`;
                  diff --git a/assets/src_ranuts_utils_str2xml.md.CwgfkeY1.lean.js b/assets/src_ranuts_utils_str2xml.md.DiJE8okl.lean.js
                  similarity index 98%
                  rename from assets/src_ranuts_utils_str2xml.md.CwgfkeY1.lean.js
                  rename to assets/src_ranuts_utils_str2xml.md.DiJE8okl.lean.js
                  index 96ac00dab4..502a1b2cf3 100644
                  --- a/assets/src_ranuts_utils_str2xml.md.CwgfkeY1.lean.js
                  +++ b/assets/src_ranuts_utils_str2xml.md.DiJE8okl.lean.js
                  @@ -1,4 +1,4 @@
                  -import{_ as s,o as a,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"str2Xml","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/str2xml.md","filePath":"src/ranuts/utils/str2xml.md","lastUpdated":1728828157000}'),n={name:"src/ranuts/utils/str2xml.md"};function l(r,t,h,d,o,p){return a(),i("div",{"data-pagefind-body":!0},t[0]||(t[0]=[e(`

                  str2Xml

                  Pass in a string and convert it to 'xml'

                  API

                  Return

                  argumentInstructionstype
                  HTMLElement返回一个HTMLElementHTMLElement

                  Options

                  argumentInstructionstypeDefault value
                  xmlStrIncoming parameterstringnull
                  formatSet the format to be converted. The default is' text/xml '' DOMParserSupportedType 'null

                  Example

                  For example, when doing icon library, we need to dynamically import all the 'ICONS' in the directory. In this case, strings are imported, but strings cannot be added to 'xml'. So we need to convert the string to 'xml', and then we can add it to 'xml'.

                  js
                  import { str2Xml } from 'ranuts';
                  +import{_ as s,o as a,c as i,a3 as e}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"str2Xml","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/str2xml.md","filePath":"src/ranuts/utils/str2xml.md","lastUpdated":1728921295000}'),n={name:"src/ranuts/utils/str2xml.md"};function l(r,t,h,d,o,p){return a(),i("div",{"data-pagefind-body":!0},t[0]||(t[0]=[e(`

                  str2Xml

                  Pass in a string and convert it to 'xml'

                  API

                  Return

                  argumentInstructionstype
                  HTMLElement返回一个HTMLElementHTMLElement

                  Options

                  argumentInstructionstypeDefault value
                  xmlStrIncoming parameterstringnull
                  formatSet the format to be converted. The default is' text/xml '' DOMParserSupportedType 'null

                  Example

                  For example, when doing icon library, we need to dynamically import all the 'ICONS' in the directory. In this case, strings are imported, but strings cannot be added to 'xml'. So we need to convert the string to 'xml', and then we can add it to 'xml'.

                  js
                  import { str2Xml } from 'ranuts';
                   
                   // import 'assets/*.svg'
                   const svg = \`<svg t="1667483498347" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8544" width="200" height="200"><path d="M858.5 763.6c-18.9-44.8-46.1-85-80.6-119.5-34.5-34.5-74.7-61.6-119.5-80.6-0.4-0.2-0.8-0.3-1.2-0.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-0.4 0.2-0.8 0.3-1.2 0.5-44.8 18.9-85 46-119.5 80.6-34.5 34.5-61.6 74.7-80.6 119.5C146.9 807.5 137 854 136 901.8c-0.1 4.5 3.5 8.2 8 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c0.1 4.4 3.6 7.8 8 7.8h60c4.5 0 8.1-3.7 8-8.2-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z" p-id="8545"></path></svg>\`;
                  diff --git a/assets/src_ranuts_utils_task.md.CgGq5wbB.js b/assets/src_ranuts_utils_task.md.CapuHzRA.js
                  similarity index 99%
                  rename from assets/src_ranuts_utils_task.md.CgGq5wbB.js
                  rename to assets/src_ranuts_utils_task.md.CapuHzRA.js
                  index d95cd86f15..7c89fd09fc 100644
                  --- a/assets/src_ranuts_utils_task.md.CgGq5wbB.js
                  +++ b/assets/src_ranuts_utils_task.md.CapuHzRA.js
                  @@ -1 +1 @@
                  -import{_ as t,o as a,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"Statistical execution time","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/task.md","filePath":"src/ranuts/utils/task.md","lastUpdated":1728828157000}'),o={name:"src/ranuts/utils/task.md"};function n(d,e,r,c,l,h){return a(),s("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

                  Statistical execution time

                  Sometimes, we need statistics on the execution time of a function to analyze performance. Therefore, the 'startTask' and 'taskEnd' functions are wrapped. Three other statistical methods are also introduced

                  1. new Date().getTime(),
                  2. console.time() , console.timeEnd(),
                  3. performance.now()

                  一.startTask,taskEnd

                  1.startTask

                  Execute before the task begins

                  Return

                  参数说明类型
                  taskId任务标识unique symbol

                  2.taskEnd

                  任务结束的时候执行,需要传入startTask返回的任务标识

                  Options

                  参数说明类型默认值
                  taskId任务标识unique symbol 无默认值,参数必传,否则无法识别是哪个任务

                  Return

                  参数说明类型
                  timetask执行的时间number

                  3.使用例子

                  js
                  const taskId = startTask();\n\n// do something\n\nconst time = taskEnd(taskId);\n\nconsole.log('task 执行花费的时间', time);

                  二.new Date().getTime()

                  new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

                  1. 某些情况下,毫秒级精度可能不够。
                  2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

                    由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

                  三.console.time(), console.timeEnd()

                  启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

                  四.performance.now()

                  performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

                  注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

                  ',24)]))}const m=t(o,[["render",n]]);export{k as __pageData,m as default}; +import{_ as t,o as a,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"Statistical execution time","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/task.md","filePath":"src/ranuts/utils/task.md","lastUpdated":1728921295000}'),o={name:"src/ranuts/utils/task.md"};function n(d,e,r,c,l,h){return a(),s("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

                  Statistical execution time

                  Sometimes, we need statistics on the execution time of a function to analyze performance. Therefore, the 'startTask' and 'taskEnd' functions are wrapped. Three other statistical methods are also introduced

                  1. new Date().getTime(),
                  2. console.time() , console.timeEnd(),
                  3. performance.now()

                  一.startTask,taskEnd

                  1.startTask

                  Execute before the task begins

                  Return

                  参数说明类型
                  taskId任务标识unique symbol

                  2.taskEnd

                  任务结束的时候执行,需要传入startTask返回的任务标识

                  Options

                  参数说明类型默认值
                  taskId任务标识unique symbol 无默认值,参数必传,否则无法识别是哪个任务

                  Return

                  参数说明类型
                  timetask执行的时间number

                  3.使用例子

                  js
                  const taskId = startTask();\n\n// do something\n\nconst time = taskEnd(taskId);\n\nconsole.log('task 执行花费的时间', time);

                  二.new Date().getTime()

                  new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

                  1. 某些情况下,毫秒级精度可能不够。
                  2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

                    由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

                  三.console.time(), console.timeEnd()

                  启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

                  四.performance.now()

                  performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

                  注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

                  ',24)]))}const m=t(o,[["render",n]]);export{k as __pageData,m as default}; diff --git a/assets/src_ranuts_utils_task.md.CgGq5wbB.lean.js b/assets/src_ranuts_utils_task.md.CapuHzRA.lean.js similarity index 99% rename from assets/src_ranuts_utils_task.md.CgGq5wbB.lean.js rename to assets/src_ranuts_utils_task.md.CapuHzRA.lean.js index d95cd86f15..7c89fd09fc 100644 --- a/assets/src_ranuts_utils_task.md.CgGq5wbB.lean.js +++ b/assets/src_ranuts_utils_task.md.CapuHzRA.lean.js @@ -1 +1 @@ -import{_ as t,o as a,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"Statistical execution time","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/task.md","filePath":"src/ranuts/utils/task.md","lastUpdated":1728828157000}'),o={name:"src/ranuts/utils/task.md"};function n(d,e,r,c,l,h){return a(),s("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

                  Statistical execution time

                  Sometimes, we need statistics on the execution time of a function to analyze performance. Therefore, the 'startTask' and 'taskEnd' functions are wrapped. Three other statistical methods are also introduced

                  1. new Date().getTime(),
                  2. console.time() , console.timeEnd(),
                  3. performance.now()

                  一.startTask,taskEnd

                  1.startTask

                  Execute before the task begins

                  Return

                  参数说明类型
                  taskId任务标识unique symbol

                  2.taskEnd

                  任务结束的时候执行,需要传入startTask返回的任务标识

                  Options

                  参数说明类型默认值
                  taskId任务标识unique symbol 无默认值,参数必传,否则无法识别是哪个任务

                  Return

                  参数说明类型
                  timetask执行的时间number

                  3.使用例子

                  js
                  const taskId = startTask();\n\n// do something\n\nconst time = taskEnd(taskId);\n\nconsole.log('task 执行花费的时间', time);

                  二.new Date().getTime()

                  new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

                  1. 某些情况下,毫秒级精度可能不够。
                  2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

                    由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

                  三.console.time(), console.timeEnd()

                  启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

                  四.performance.now()

                  performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

                  注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

                  ',24)]))}const m=t(o,[["render",n]]);export{k as __pageData,m as default}; +import{_ as t,o as a,c as s,a3 as i}from"./chunks/framework.BYE6xntm.js";const k=JSON.parse('{"title":"Statistical execution time","description":"","frontmatter":{},"headers":[],"relativePath":"src/ranuts/utils/task.md","filePath":"src/ranuts/utils/task.md","lastUpdated":1728921295000}'),o={name:"src/ranuts/utils/task.md"};function n(d,e,r,c,l,h){return a(),s("div",{"data-pagefind-body":!0},e[0]||(e[0]=[i('

                  Statistical execution time

                  Sometimes, we need statistics on the execution time of a function to analyze performance. Therefore, the 'startTask' and 'taskEnd' functions are wrapped. Three other statistical methods are also introduced

                  1. new Date().getTime(),
                  2. console.time() , console.timeEnd(),
                  3. performance.now()

                  一.startTask,taskEnd

                  1.startTask

                  Execute before the task begins

                  Return

                  参数说明类型
                  taskId任务标识unique symbol

                  2.taskEnd

                  任务结束的时候执行,需要传入startTask返回的任务标识

                  Options

                  参数说明类型默认值
                  taskId任务标识unique symbol 无默认值,参数必传,否则无法识别是哪个任务

                  Return

                  参数说明类型
                  timetask执行的时间number

                  3.使用例子

                  js
                  const taskId = startTask();\n\n// do something\n\nconst time = taskEnd(taskId);\n\nconsole.log('task 执行花费的时间', time);

                  二.new Date().getTime()

                  new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

                  1. 某些情况下,毫秒级精度可能不够。
                  2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

                    由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

                  三.console.time(), console.timeEnd()

                  启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

                  四.performance.now()

                  performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

                  注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

                  ',24)]))}const m=t(o,[["render",n]]);export{k as __pageData,m as default}; diff --git "a/assets/src_types_TS\347\261\273\345\236\213.md.BkjT3Xys.js" "b/assets/src_types_TS\347\261\273\345\236\213.md.DIHmZPe4.js" similarity index 99% rename from "assets/src_types_TS\347\261\273\345\236\213.md.BkjT3Xys.js" rename to "assets/src_types_TS\347\261\273\345\236\213.md.DIHmZPe4.js" index df2590d173..72784c6a06 100644 --- "a/assets/src_types_TS\347\261\273\345\236\213.md.BkjT3Xys.js" +++ "b/assets/src_types_TS\347\261\273\345\236\213.md.DIHmZPe4.js" @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/TS类型.md","filePath":"src/types/TS类型.md","lastUpdated":1728828157000}'),l={name:"src/types/TS类型.md"};function t(p,s,k,e,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  TypeScript 类型系统中的类型

                  1. 基本类型: number、boolean、string、object、bigint、symbol、undefined、null
                  2. 复合类型: class、Array、元组(Tuple)、接口(Interface)、枚举(Enum)
                  3. 特殊的类型:void、never、any、unknown

                  Tuple

                  元组(Tuple)就是元素个数和类型固定的数组类型:

                  ts
                  type Tuple = [number, string];

                  Interface

                  接口(Interface)可以描述函数、对象、构造器的结构:

                  • 对象
                  ts
                  interface IPerson {
                  +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/TS类型.md","filePath":"src/types/TS类型.md","lastUpdated":1728921295000}'),l={name:"src/types/TS类型.md"};function t(p,s,k,e,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  TypeScript 类型系统中的类型

                  1. 基本类型: number、boolean、string、object、bigint、symbol、undefined、null
                  2. 复合类型: class、Array、元组(Tuple)、接口(Interface)、枚举(Enum)
                  3. 特殊的类型:void、never、any、unknown

                  Tuple

                  元组(Tuple)就是元素个数和类型固定的数组类型:

                  ts
                  type Tuple = [number, string];

                  Interface

                  接口(Interface)可以描述函数、对象、构造器的结构:

                  • 对象
                  ts
                  interface IPerson {
                     name: string;
                     age: number;
                   }
                  diff --git "a/assets/src_types_TS\347\261\273\345\236\213.md.BkjT3Xys.lean.js" "b/assets/src_types_TS\347\261\273\345\236\213.md.DIHmZPe4.lean.js"
                  similarity index 99%
                  rename from "assets/src_types_TS\347\261\273\345\236\213.md.BkjT3Xys.lean.js"
                  rename to "assets/src_types_TS\347\261\273\345\236\213.md.DIHmZPe4.lean.js"
                  index df2590d173..72784c6a06 100644
                  --- "a/assets/src_types_TS\347\261\273\345\236\213.md.BkjT3Xys.lean.js"
                  +++ "b/assets/src_types_TS\347\261\273\345\236\213.md.DIHmZPe4.lean.js"
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/TS类型.md","filePath":"src/types/TS类型.md","lastUpdated":1728828157000}'),l={name:"src/types/TS类型.md"};function t(p,s,k,e,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  TypeScript 类型系统中的类型

                  1. 基本类型: number、boolean、string、object、bigint、symbol、undefined、null
                  2. 复合类型: class、Array、元组(Tuple)、接口(Interface)、枚举(Enum)
                  3. 特殊的类型:void、never、any、unknown

                  Tuple

                  元组(Tuple)就是元素个数和类型固定的数组类型:

                  ts
                  type Tuple = [number, string];

                  Interface

                  接口(Interface)可以描述函数、对象、构造器的结构:

                  • 对象
                  ts
                  interface IPerson {
                  +import{_ as i,o as a,c as n,a3 as h}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/TS类型.md","filePath":"src/types/TS类型.md","lastUpdated":1728921295000}'),l={name:"src/types/TS类型.md"};function t(p,s,k,e,r,d){return a(),n("div",{"data-pagefind-body":!0},s[0]||(s[0]=[h(`

                  TypeScript 类型系统中的类型

                  1. 基本类型: number、boolean、string、object、bigint、symbol、undefined、null
                  2. 复合类型: class、Array、元组(Tuple)、接口(Interface)、枚举(Enum)
                  3. 特殊的类型:void、never、any、unknown

                  Tuple

                  元组(Tuple)就是元素个数和类型固定的数组类型:

                  ts
                  type Tuple = [number, string];

                  Interface

                  接口(Interface)可以描述函数、对象、构造器的结构:

                  • 对象
                  ts
                  interface IPerson {
                     name: string;
                     age: number;
                   }
                  diff --git "a/assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CC8I3wm1.js" "b/assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CjXSWGVq.js"
                  similarity index 99%
                  rename from "assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CC8I3wm1.js"
                  rename to "assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CjXSWGVq.js"
                  index 1022c3856c..fdb5e7675e 100644
                  --- "a/assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CC8I3wm1.js"
                  +++ "b/assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CjXSWGVq.js"
                  @@ -1 +1 @@
                  -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"模式匹配","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/模式匹配.md","filePath":"src/types/模式匹配.md","lastUpdated":1728828157000}'),k={name:"src/types/模式匹配.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  模式匹配

                  Typescript 的类型也同样可以做模式匹配。

                  比如这样一个 Promise 类型:

                  ts
                  type p = Promise<'value'>;

                  我们想提取 value 的类型,可以这样做:

                  ts
                  type GetPromiseValue<T> = T extends Promise<infer value> ? value : never;

                  通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

                  ts
                  type result = GetPromiseValue<Promise<'name'>>; // name

                  数组类型

                  数组类型想提取第一个元素的类型怎么做呢?

                  ts
                  type arr = [1, 2, 3];

                  用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

                  ts
                  type GetArrayFirstItem<T extends unknown[]> = T extends [infer value, ...unknown[]] ? value : never;

                  类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unknown 也就是可以是任何值。

                  any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

                  对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type result = GetArrayFirstItem<[1, 2, 3]>; // 1

                  当类型参数 Arr 为 [] 时:

                  ts
                  type result = GetArrayFirstItem<[]>; // never

                  可以提取第一个元素,当然也可以提取最后一个元素,修改下模式类型就行:

                  ts
                  type GetArrayLastItem<T extends unknown[]> = T extends [...unknown[],inter L] ? L : never

                  我们分别取了首尾元素,当然也可以取剩余的数组,比如取去掉了最后一个元素的数组:

                  ts
                  type Pop<T extends unknown[]> = T extends [] ? [] : T extends [...infer Rest, unknown] ? Rest : never;

                  如果是空数组,就直接返回,否则匹配剩余的元素,放到 infer 声明的局部变量 Rest 里,返回 Rest。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type Result = Pop<[1, 2, 3]>; // [1,2]

                  当类型参数 Arr 为 [] 时:

                  ts
                  type Result = Pop<[]>; // []

                  同理可得 ShiftArr 的实现:

                  ts
                  type Shift<T extends unknown[]> = T extends [] ? [] : T extends [unknown, ...infer Rest] ? Rest : never;

                  字符串类型也同样可以做模式匹配,匹配一个模式字符串,把需要提取的部分放到 infer 声明的局部变量里。

                  判断字符串是否以某个前缀开头,也是通过模式匹配:

                  ts
                  type StartWidth<S extends string, P extends string> = S extends `${P}${string}` ? true : false;

                  需要声明字符串 Str、匹配的前缀 Prefix 两个类型参数,它们都是 string。

                  用 Str 去匹配一个模式类型,模式类型的前缀是 Prefix,后面是任意的 string,如果匹配返回 true,否则返回 false。

                  字符串可以匹配一个模式类型,提取想要的部分,自然也可以用这些再构成一个新的类型。

                  比如实现字符串替换:

                  ts
                  type Replace<S extends string, F extends string, T extends string> = S extends `${infer P}${F}${infer L}`\n  ? `${P}${T}${L}`\n  : S;

                  声明要替换的字符串 Str、待替换的字符串 From、替换成的字符串 3 个类型参数,通过 extends 约束为都是 string 类型。

                  用 Str 去匹配模式串,模式串由 From 和之前之后的字符串构成,把之前之后的字符串放到通过 infer 声明的局部变量 Prefix、Suffix 里。

                  用 Prefix、Suffix 加上替换到的字符串 To 构造成新的字符串类型返回。

                  Trim

                  能够匹配和替换字符串,那也就能实现去掉空白字符的 Trim:

                  不过因为我们不知道有多少个空白字符,所以只能一个个匹配和去掉,需要递归。

                  先实现 TrimRight:

                  ts
                  type TrimRight<S extends string> = S extends `${infer Rest}${' ' | '\\n' | '\\t'}` ? TrimRight<Rest> : S;

                  类型参数 Str 是要 Trim 的字符串。

                  如果 Str 匹配字符串 + 空白字符 (空格、换行、制表符),那就把字符串放到 infer 声明的局部变量 Rest 里。

                  把 Rest 作为类型参数递归 TrimRight,直到不匹配,这时的类型参数 Str 就是处理结果。

                  同理可得 TrimLeft:

                  ts
                  type TrimLeft<S extends string> = S extends `${' ' | '\\n' | '\\t'}${infer Rest}` ? TrimLeft<Rest> : S;

                  TrimRight 和 TrimLeft 结合就是 Trim:

                  ts
                  type Trim<S extends string> = TrimLeft<TrimRight<S>>;

                  函数

                  函数同样也可以做类型匹配,比如提取参数、返回值的类型。

                  GetParameters

                  函数类型可以通过模式匹配来提取参数的类型:

                  ts
                  type GetParameters<T extends Function> = T extends (...args: infer A) => unknown ? A : never;

                  类型参数 Func 是要匹配的函数类型,通过 extends 约束为 Function。

                  Func 和模式类型做匹配,参数类型放到用 infer 声明的局部变量 Args 里,返回值可以是任何类型,用 unknown。

                  返回提取到的参数类型 Args。

                  GetReturnType

                  ts
                  type GetReturnType<T extends Function> = T extends (...args: unknown[]) => infer R ? R : never;

                  Func 和模式类型做匹配,提取返回值到通过 infer 声明的局部变量 ReturnType 里返回。

                  参数类型可以是任意类型,也就是 any[](注意,这里不能用 unknown,这里的解释涉及到参数的逆变性质,具体原因逆变那一节会解释)。

                  GetThisParameterType

                  方法里可以调用 this,用对象.方法名的方式调用的时候,this 就指向那个对象。

                  但是方法也可以用 call 或者 apply 调用,call 调用的时候,this 就变了,但这里却没有被检查出来 this 指向的错误。

                  这里的 this 类型同样也可以通过模式匹配提取出来:

                  ts
                  type GetThisParameterType<T extends Function> = T extends (this: infer H, ...args: unknown[]) => unknown ? H : unknown;

                  构造器

                  构造器和函数的区别是,构造器是用于创建对象的,所以可以被 new。

                  同样,我们也可以通过模式匹配提取构造器的参数和返回值的类型:

                  GetInstanceType

                  构造器类型可以用 interface 声明,使用 new(): xx 的语法。

                  ts
                  interface Person {\n  name: string;\n}\n\ninterface PersonConstructor {\n  new (name: string): Person;\n}

                  这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

                  ts
                  type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T\n  ? T\n  : unknown;
                  ',79)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"模式匹配","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/模式匹配.md","filePath":"src/types/模式匹配.md","lastUpdated":1728921295000}'),k={name:"src/types/模式匹配.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  模式匹配

                  Typescript 的类型也同样可以做模式匹配。

                  比如这样一个 Promise 类型:

                  ts
                  type p = Promise<'value'>;

                  我们想提取 value 的类型,可以这样做:

                  ts
                  type GetPromiseValue<T> = T extends Promise<infer value> ? value : never;

                  通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

                  ts
                  type result = GetPromiseValue<Promise<'name'>>; // name

                  数组类型

                  数组类型想提取第一个元素的类型怎么做呢?

                  ts
                  type arr = [1, 2, 3];

                  用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

                  ts
                  type GetArrayFirstItem<T extends unknown[]> = T extends [infer value, ...unknown[]] ? value : never;

                  类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unknown 也就是可以是任何值。

                  any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

                  对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type result = GetArrayFirstItem<[1, 2, 3]>; // 1

                  当类型参数 Arr 为 [] 时:

                  ts
                  type result = GetArrayFirstItem<[]>; // never

                  可以提取第一个元素,当然也可以提取最后一个元素,修改下模式类型就行:

                  ts
                  type GetArrayLastItem<T extends unknown[]> = T extends [...unknown[],inter L] ? L : never

                  我们分别取了首尾元素,当然也可以取剩余的数组,比如取去掉了最后一个元素的数组:

                  ts
                  type Pop<T extends unknown[]> = T extends [] ? [] : T extends [...infer Rest, unknown] ? Rest : never;

                  如果是空数组,就直接返回,否则匹配剩余的元素,放到 infer 声明的局部变量 Rest 里,返回 Rest。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type Result = Pop<[1, 2, 3]>; // [1,2]

                  当类型参数 Arr 为 [] 时:

                  ts
                  type Result = Pop<[]>; // []

                  同理可得 ShiftArr 的实现:

                  ts
                  type Shift<T extends unknown[]> = T extends [] ? [] : T extends [unknown, ...infer Rest] ? Rest : never;

                  字符串类型也同样可以做模式匹配,匹配一个模式字符串,把需要提取的部分放到 infer 声明的局部变量里。

                  判断字符串是否以某个前缀开头,也是通过模式匹配:

                  ts
                  type StartWidth<S extends string, P extends string> = S extends `${P}${string}` ? true : false;

                  需要声明字符串 Str、匹配的前缀 Prefix 两个类型参数,它们都是 string。

                  用 Str 去匹配一个模式类型,模式类型的前缀是 Prefix,后面是任意的 string,如果匹配返回 true,否则返回 false。

                  字符串可以匹配一个模式类型,提取想要的部分,自然也可以用这些再构成一个新的类型。

                  比如实现字符串替换:

                  ts
                  type Replace<S extends string, F extends string, T extends string> = S extends `${infer P}${F}${infer L}`\n  ? `${P}${T}${L}`\n  : S;

                  声明要替换的字符串 Str、待替换的字符串 From、替换成的字符串 3 个类型参数,通过 extends 约束为都是 string 类型。

                  用 Str 去匹配模式串,模式串由 From 和之前之后的字符串构成,把之前之后的字符串放到通过 infer 声明的局部变量 Prefix、Suffix 里。

                  用 Prefix、Suffix 加上替换到的字符串 To 构造成新的字符串类型返回。

                  Trim

                  能够匹配和替换字符串,那也就能实现去掉空白字符的 Trim:

                  不过因为我们不知道有多少个空白字符,所以只能一个个匹配和去掉,需要递归。

                  先实现 TrimRight:

                  ts
                  type TrimRight<S extends string> = S extends `${infer Rest}${' ' | '\\n' | '\\t'}` ? TrimRight<Rest> : S;

                  类型参数 Str 是要 Trim 的字符串。

                  如果 Str 匹配字符串 + 空白字符 (空格、换行、制表符),那就把字符串放到 infer 声明的局部变量 Rest 里。

                  把 Rest 作为类型参数递归 TrimRight,直到不匹配,这时的类型参数 Str 就是处理结果。

                  同理可得 TrimLeft:

                  ts
                  type TrimLeft<S extends string> = S extends `${' ' | '\\n' | '\\t'}${infer Rest}` ? TrimLeft<Rest> : S;

                  TrimRight 和 TrimLeft 结合就是 Trim:

                  ts
                  type Trim<S extends string> = TrimLeft<TrimRight<S>>;

                  函数

                  函数同样也可以做类型匹配,比如提取参数、返回值的类型。

                  GetParameters

                  函数类型可以通过模式匹配来提取参数的类型:

                  ts
                  type GetParameters<T extends Function> = T extends (...args: infer A) => unknown ? A : never;

                  类型参数 Func 是要匹配的函数类型,通过 extends 约束为 Function。

                  Func 和模式类型做匹配,参数类型放到用 infer 声明的局部变量 Args 里,返回值可以是任何类型,用 unknown。

                  返回提取到的参数类型 Args。

                  GetReturnType

                  ts
                  type GetReturnType<T extends Function> = T extends (...args: unknown[]) => infer R ? R : never;

                  Func 和模式类型做匹配,提取返回值到通过 infer 声明的局部变量 ReturnType 里返回。

                  参数类型可以是任意类型,也就是 any[](注意,这里不能用 unknown,这里的解释涉及到参数的逆变性质,具体原因逆变那一节会解释)。

                  GetThisParameterType

                  方法里可以调用 this,用对象.方法名的方式调用的时候,this 就指向那个对象。

                  但是方法也可以用 call 或者 apply 调用,call 调用的时候,this 就变了,但这里却没有被检查出来 this 指向的错误。

                  这里的 this 类型同样也可以通过模式匹配提取出来:

                  ts
                  type GetThisParameterType<T extends Function> = T extends (this: infer H, ...args: unknown[]) => unknown ? H : unknown;

                  构造器

                  构造器和函数的区别是,构造器是用于创建对象的,所以可以被 new。

                  同样,我们也可以通过模式匹配提取构造器的参数和返回值的类型:

                  GetInstanceType

                  构造器类型可以用 interface 声明,使用 new(): xx 的语法。

                  ts
                  interface Person {\n  name: string;\n}\n\ninterface PersonConstructor {\n  new (name: string): Person;\n}

                  这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

                  ts
                  type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T\n  ? T\n  : unknown;
                  ',79)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; diff --git "a/assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CC8I3wm1.lean.js" "b/assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CjXSWGVq.lean.js" similarity index 99% rename from "assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CC8I3wm1.lean.js" rename to "assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CjXSWGVq.lean.js" index 1022c3856c..fdb5e7675e 100644 --- "a/assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CC8I3wm1.lean.js" +++ "b/assets/src_types_\346\250\241\345\274\217\345\214\271\351\205\215.md.CjXSWGVq.lean.js" @@ -1 +1 @@ -import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"模式匹配","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/模式匹配.md","filePath":"src/types/模式匹配.md","lastUpdated":1728828157000}'),k={name:"src/types/模式匹配.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  模式匹配

                  Typescript 的类型也同样可以做模式匹配。

                  比如这样一个 Promise 类型:

                  ts
                  type p = Promise<'value'>;

                  我们想提取 value 的类型,可以这样做:

                  ts
                  type GetPromiseValue<T> = T extends Promise<infer value> ? value : never;

                  通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

                  ts
                  type result = GetPromiseValue<Promise<'name'>>; // name

                  数组类型

                  数组类型想提取第一个元素的类型怎么做呢?

                  ts
                  type arr = [1, 2, 3];

                  用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

                  ts
                  type GetArrayFirstItem<T extends unknown[]> = T extends [infer value, ...unknown[]] ? value : never;

                  类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unknown 也就是可以是任何值。

                  any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

                  对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type result = GetArrayFirstItem<[1, 2, 3]>; // 1

                  当类型参数 Arr 为 [] 时:

                  ts
                  type result = GetArrayFirstItem<[]>; // never

                  可以提取第一个元素,当然也可以提取最后一个元素,修改下模式类型就行:

                  ts
                  type GetArrayLastItem<T extends unknown[]> = T extends [...unknown[],inter L] ? L : never

                  我们分别取了首尾元素,当然也可以取剩余的数组,比如取去掉了最后一个元素的数组:

                  ts
                  type Pop<T extends unknown[]> = T extends [] ? [] : T extends [...infer Rest, unknown] ? Rest : never;

                  如果是空数组,就直接返回,否则匹配剩余的元素,放到 infer 声明的局部变量 Rest 里,返回 Rest。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type Result = Pop<[1, 2, 3]>; // [1,2]

                  当类型参数 Arr 为 [] 时:

                  ts
                  type Result = Pop<[]>; // []

                  同理可得 ShiftArr 的实现:

                  ts
                  type Shift<T extends unknown[]> = T extends [] ? [] : T extends [unknown, ...infer Rest] ? Rest : never;

                  字符串类型也同样可以做模式匹配,匹配一个模式字符串,把需要提取的部分放到 infer 声明的局部变量里。

                  判断字符串是否以某个前缀开头,也是通过模式匹配:

                  ts
                  type StartWidth<S extends string, P extends string> = S extends `${P}${string}` ? true : false;

                  需要声明字符串 Str、匹配的前缀 Prefix 两个类型参数,它们都是 string。

                  用 Str 去匹配一个模式类型,模式类型的前缀是 Prefix,后面是任意的 string,如果匹配返回 true,否则返回 false。

                  字符串可以匹配一个模式类型,提取想要的部分,自然也可以用这些再构成一个新的类型。

                  比如实现字符串替换:

                  ts
                  type Replace<S extends string, F extends string, T extends string> = S extends `${infer P}${F}${infer L}`\n  ? `${P}${T}${L}`\n  : S;

                  声明要替换的字符串 Str、待替换的字符串 From、替换成的字符串 3 个类型参数,通过 extends 约束为都是 string 类型。

                  用 Str 去匹配模式串,模式串由 From 和之前之后的字符串构成,把之前之后的字符串放到通过 infer 声明的局部变量 Prefix、Suffix 里。

                  用 Prefix、Suffix 加上替换到的字符串 To 构造成新的字符串类型返回。

                  Trim

                  能够匹配和替换字符串,那也就能实现去掉空白字符的 Trim:

                  不过因为我们不知道有多少个空白字符,所以只能一个个匹配和去掉,需要递归。

                  先实现 TrimRight:

                  ts
                  type TrimRight<S extends string> = S extends `${infer Rest}${' ' | '\\n' | '\\t'}` ? TrimRight<Rest> : S;

                  类型参数 Str 是要 Trim 的字符串。

                  如果 Str 匹配字符串 + 空白字符 (空格、换行、制表符),那就把字符串放到 infer 声明的局部变量 Rest 里。

                  把 Rest 作为类型参数递归 TrimRight,直到不匹配,这时的类型参数 Str 就是处理结果。

                  同理可得 TrimLeft:

                  ts
                  type TrimLeft<S extends string> = S extends `${' ' | '\\n' | '\\t'}${infer Rest}` ? TrimLeft<Rest> : S;

                  TrimRight 和 TrimLeft 结合就是 Trim:

                  ts
                  type Trim<S extends string> = TrimLeft<TrimRight<S>>;

                  函数

                  函数同样也可以做类型匹配,比如提取参数、返回值的类型。

                  GetParameters

                  函数类型可以通过模式匹配来提取参数的类型:

                  ts
                  type GetParameters<T extends Function> = T extends (...args: infer A) => unknown ? A : never;

                  类型参数 Func 是要匹配的函数类型,通过 extends 约束为 Function。

                  Func 和模式类型做匹配,参数类型放到用 infer 声明的局部变量 Args 里,返回值可以是任何类型,用 unknown。

                  返回提取到的参数类型 Args。

                  GetReturnType

                  ts
                  type GetReturnType<T extends Function> = T extends (...args: unknown[]) => infer R ? R : never;

                  Func 和模式类型做匹配,提取返回值到通过 infer 声明的局部变量 ReturnType 里返回。

                  参数类型可以是任意类型,也就是 any[](注意,这里不能用 unknown,这里的解释涉及到参数的逆变性质,具体原因逆变那一节会解释)。

                  GetThisParameterType

                  方法里可以调用 this,用对象.方法名的方式调用的时候,this 就指向那个对象。

                  但是方法也可以用 call 或者 apply 调用,call 调用的时候,this 就变了,但这里却没有被检查出来 this 指向的错误。

                  这里的 this 类型同样也可以通过模式匹配提取出来:

                  ts
                  type GetThisParameterType<T extends Function> = T extends (this: infer H, ...args: unknown[]) => unknown ? H : unknown;

                  构造器

                  构造器和函数的区别是,构造器是用于创建对象的,所以可以被 new。

                  同样,我们也可以通过模式匹配提取构造器的参数和返回值的类型:

                  GetInstanceType

                  构造器类型可以用 interface 声明,使用 new(): xx 的语法。

                  ts
                  interface Person {\n  name: string;\n}\n\ninterface PersonConstructor {\n  new (name: string): Person;\n}

                  这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

                  ts
                  type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T\n  ? T\n  : unknown;
                  ',79)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; +import{_ as i,o as a,c as h,a3 as t}from"./chunks/framework.BYE6xntm.js";const F=JSON.parse('{"title":"模式匹配","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/模式匹配.md","filePath":"src/types/模式匹配.md","lastUpdated":1728921295000}'),k={name:"src/types/模式匹配.md"};function n(p,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[t('

                  模式匹配

                  Typescript 的类型也同样可以做模式匹配。

                  比如这样一个 Promise 类型:

                  ts
                  type p = Promise<'value'>;

                  我们想提取 value 的类型,可以这样做:

                  ts
                  type GetPromiseValue<T> = T extends Promise<infer value> ? value : never;

                  通过 extends 对传入的类型参数 P 做模式匹配,其中值的类型是需要提取的,通过 infer 声明一个局部变量 Value 来保存,如果匹配,就返回匹配到的 Value,否则就返回 never 代表没匹配到。

                  ts
                  type result = GetPromiseValue<Promise<'name'>>; // name

                  数组类型

                  数组类型想提取第一个元素的类型怎么做呢?

                  ts
                  type arr = [1, 2, 3];

                  用它来匹配一个模式类型,提取第一个元素的类型到通过 infer 声明的局部变量里返回。

                  ts
                  type GetArrayFirstItem<T extends unknown[]> = T extends [infer value, ...unknown[]] ? value : never;

                  类型参数 Arr 通过 extends 约束为只能是数组类型,数组元素是 unknown 也就是可以是任何值。

                  any 和 unknown 的区别: any 和 unknown 都代表任意类型,但是 unknown 只能接收任意类型的值,而 any 除了可以接收任意类型的值,也可以赋值给任意类型(除了 never)。类型体操中经常用 unknown 接受和匹配任何类型,而很少把任何类型赋值给某个类型变量。

                  对 Arr 做模式匹配,把我们要提取的第一个元素的类型放到通过 infer 声明的 First 局部变量里,后面的元素可以是任何类型,用 unknown 接收,然后把局部变量 First 返回。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type result = GetArrayFirstItem<[1, 2, 3]>; // 1

                  当类型参数 Arr 为 [] 时:

                  ts
                  type result = GetArrayFirstItem<[]>; // never

                  可以提取第一个元素,当然也可以提取最后一个元素,修改下模式类型就行:

                  ts
                  type GetArrayLastItem<T extends unknown[]> = T extends [...unknown[],inter L] ? L : never

                  我们分别取了首尾元素,当然也可以取剩余的数组,比如取去掉了最后一个元素的数组:

                  ts
                  type Pop<T extends unknown[]> = T extends [] ? [] : T extends [...infer Rest, unknown] ? Rest : never;

                  如果是空数组,就直接返回,否则匹配剩余的元素,放到 infer 声明的局部变量 Rest 里,返回 Rest。

                  当类型参数 Arr 为 [1,2,3] 时:

                  ts
                  type Result = Pop<[1, 2, 3]>; // [1,2]

                  当类型参数 Arr 为 [] 时:

                  ts
                  type Result = Pop<[]>; // []

                  同理可得 ShiftArr 的实现:

                  ts
                  type Shift<T extends unknown[]> = T extends [] ? [] : T extends [unknown, ...infer Rest] ? Rest : never;

                  字符串类型也同样可以做模式匹配,匹配一个模式字符串,把需要提取的部分放到 infer 声明的局部变量里。

                  判断字符串是否以某个前缀开头,也是通过模式匹配:

                  ts
                  type StartWidth<S extends string, P extends string> = S extends `${P}${string}` ? true : false;

                  需要声明字符串 Str、匹配的前缀 Prefix 两个类型参数,它们都是 string。

                  用 Str 去匹配一个模式类型,模式类型的前缀是 Prefix,后面是任意的 string,如果匹配返回 true,否则返回 false。

                  字符串可以匹配一个模式类型,提取想要的部分,自然也可以用这些再构成一个新的类型。

                  比如实现字符串替换:

                  ts
                  type Replace<S extends string, F extends string, T extends string> = S extends `${infer P}${F}${infer L}`\n  ? `${P}${T}${L}`\n  : S;

                  声明要替换的字符串 Str、待替换的字符串 From、替换成的字符串 3 个类型参数,通过 extends 约束为都是 string 类型。

                  用 Str 去匹配模式串,模式串由 From 和之前之后的字符串构成,把之前之后的字符串放到通过 infer 声明的局部变量 Prefix、Suffix 里。

                  用 Prefix、Suffix 加上替换到的字符串 To 构造成新的字符串类型返回。

                  Trim

                  能够匹配和替换字符串,那也就能实现去掉空白字符的 Trim:

                  不过因为我们不知道有多少个空白字符,所以只能一个个匹配和去掉,需要递归。

                  先实现 TrimRight:

                  ts
                  type TrimRight<S extends string> = S extends `${infer Rest}${' ' | '\\n' | '\\t'}` ? TrimRight<Rest> : S;

                  类型参数 Str 是要 Trim 的字符串。

                  如果 Str 匹配字符串 + 空白字符 (空格、换行、制表符),那就把字符串放到 infer 声明的局部变量 Rest 里。

                  把 Rest 作为类型参数递归 TrimRight,直到不匹配,这时的类型参数 Str 就是处理结果。

                  同理可得 TrimLeft:

                  ts
                  type TrimLeft<S extends string> = S extends `${' ' | '\\n' | '\\t'}${infer Rest}` ? TrimLeft<Rest> : S;

                  TrimRight 和 TrimLeft 结合就是 Trim:

                  ts
                  type Trim<S extends string> = TrimLeft<TrimRight<S>>;

                  函数

                  函数同样也可以做类型匹配,比如提取参数、返回值的类型。

                  GetParameters

                  函数类型可以通过模式匹配来提取参数的类型:

                  ts
                  type GetParameters<T extends Function> = T extends (...args: infer A) => unknown ? A : never;

                  类型参数 Func 是要匹配的函数类型,通过 extends 约束为 Function。

                  Func 和模式类型做匹配,参数类型放到用 infer 声明的局部变量 Args 里,返回值可以是任何类型,用 unknown。

                  返回提取到的参数类型 Args。

                  GetReturnType

                  ts
                  type GetReturnType<T extends Function> = T extends (...args: unknown[]) => infer R ? R : never;

                  Func 和模式类型做匹配,提取返回值到通过 infer 声明的局部变量 ReturnType 里返回。

                  参数类型可以是任意类型,也就是 any[](注意,这里不能用 unknown,这里的解释涉及到参数的逆变性质,具体原因逆变那一节会解释)。

                  GetThisParameterType

                  方法里可以调用 this,用对象.方法名的方式调用的时候,this 就指向那个对象。

                  但是方法也可以用 call 或者 apply 调用,call 调用的时候,this 就变了,但这里却没有被检查出来 this 指向的错误。

                  这里的 this 类型同样也可以通过模式匹配提取出来:

                  ts
                  type GetThisParameterType<T extends Function> = T extends (this: infer H, ...args: unknown[]) => unknown ? H : unknown;

                  构造器

                  构造器和函数的区别是,构造器是用于创建对象的,所以可以被 new。

                  同样,我们也可以通过模式匹配提取构造器的参数和返回值的类型:

                  GetInstanceType

                  构造器类型可以用 interface 声明,使用 new(): xx 的语法。

                  ts
                  interface Person {\n  name: string;\n}\n\ninterface PersonConstructor {\n  new (name: string): Person;\n}

                  这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

                  ts
                  type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T\n  ? T\n  : unknown;
                  ',79)]))}const y=i(k,[["render",n]]);export{F as __pageData,y as default}; diff --git "a/assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.CYIL5e8N.js" "b/assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Bf4-_Wi-.js" similarity index 99% rename from "assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.CYIL5e8N.js" rename to "assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Bf4-_Wi-.js" index f4bd67d0a0..46bc0dc2fa 100644 --- "a/assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.CYIL5e8N.js" +++ "b/assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Bf4-_Wi-.js" @@ -1,4 +1,4 @@ -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型运算","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/类型运算.md","filePath":"src/types/类型运算.md","lastUpdated":1728828157000}'),n={name:"src/types/类型运算.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

                  TypeScript 类型系统中的类型运算

                  条件:extends ? :

                  TypeScript 里的条件判断是 extends ? :,叫做条件类型(Conditional Type)比如:

                  ts
                  type isTwo<T> = T extends 2 ? true : false;
                  +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型运算","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/类型运算.md","filePath":"src/types/类型运算.md","lastUpdated":1728921295000}'),n={name:"src/types/类型运算.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

                  TypeScript 类型系统中的类型运算

                  条件:extends ? :

                  TypeScript 里的条件判断是 extends ? :,叫做条件类型(Conditional Type)比如:

                  ts
                  type isTwo<T> = T extends 2 ? true : false;
                   
                   type res = isTwo<1>; // true
                   type res2 = isTwo<2>; // false

                  这种类型也叫做高级类型。

                  高级类型的特点是传入类型参数,经过一系列类型运算逻辑后,返回新的类型。

                  推导:infer

                  如何提取类型的一部分呢?答案是 infer。

                  比如提取元组类型的第一个元素:

                  ts
                  type FirstTupleItem<Tuple extends unknown[]> = Tuple extends [infer T, ...inter R] ? T : never;
                  diff --git "a/assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.CYIL5e8N.lean.js" "b/assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Bf4-_Wi-.lean.js"
                  similarity index 99%
                  rename from "assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.CYIL5e8N.lean.js"
                  rename to "assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Bf4-_Wi-.lean.js"
                  index f4bd67d0a0..46bc0dc2fa 100644
                  --- "a/assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.CYIL5e8N.lean.js"
                  +++ "b/assets/src_types_\347\261\273\345\236\213\350\277\220\347\256\227.md.Bf4-_Wi-.lean.js"
                  @@ -1,4 +1,4 @@
                  -import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型运算","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/类型运算.md","filePath":"src/types/类型运算.md","lastUpdated":1728828157000}'),n={name:"src/types/类型运算.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

                  TypeScript 类型系统中的类型运算

                  条件:extends ? :

                  TypeScript 里的条件判断是 extends ? :,叫做条件类型(Conditional Type)比如:

                  ts
                  type isTwo<T> = T extends 2 ? true : false;
                  +import{_ as i,o as a,c as h,a3 as k}from"./chunks/framework.BYE6xntm.js";const g=JSON.parse('{"title":"TypeScript 类型系统中的类型运算","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/类型运算.md","filePath":"src/types/类型运算.md","lastUpdated":1728921295000}'),n={name:"src/types/类型运算.md"};function p(t,s,l,e,r,d){return a(),h("div",{"data-pagefind-body":!0},s[0]||(s[0]=[k(`

                  TypeScript 类型系统中的类型运算

                  条件:extends ? :

                  TypeScript 里的条件判断是 extends ? :,叫做条件类型(Conditional Type)比如:

                  ts
                  type isTwo<T> = T extends 2 ? true : false;
                   
                   type res = isTwo<1>; // true
                   type res2 = isTwo<2>; // false

                  这种类型也叫做高级类型。

                  高级类型的特点是传入类型参数,经过一系列类型运算逻辑后,返回新的类型。

                  推导:infer

                  如何提取类型的一部分呢?答案是 infer。

                  比如提取元组类型的第一个元素:

                  ts
                  type FirstTupleItem<Tuple extends unknown[]> = Tuple extends [infer T, ...inter R] ? T : never;
                  diff --git "a/assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DrTZYnDE.js" "b/assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CufDmqA6.js"
                  similarity index 98%
                  rename from "assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DrTZYnDE.js"
                  rename to "assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CufDmqA6.js"
                  index c24ff9951d..eb87446336 100644
                  --- "a/assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DrTZYnDE.js"
                  +++ "b/assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CufDmqA6.js"
                  @@ -1 +1 @@
                  -import{_ as e,o as r,c as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"TypeScript 内置的高级类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/高级类型.md","filePath":"src/types/高级类型.md","lastUpdated":1728828157000}'),o={name:"src/types/高级类型.md"};function l(n,a,h,c,s,d){return r(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

                  TypeScript 内置的高级类型

                  Parameters

                  Parameters 用于提取函数类型的参数类型。

                  ReturnType

                  ReturnType 用于提取函数类型的返回值类型。

                  ConstructorParameters

                  构造器类型和函数类型的区别就是可以被 new。

                  Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

                  InstanceType

                  提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

                  ThisParameterType

                  OmitThisParameter

                  Partial

                  Required

                  Readonly

                  Pick

                  Record

                  Exclude

                  Extract

                  Omit

                  Awaited

                  NonNullable

                  Uppercase

                  Lowercase

                  Capitalize

                  Uncapitalize

                  总结

                  比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

                  用模式匹配 + 重新构造可以实现:OmitThisParameter

                  用重新构造可以实现:Partial、Required、Readonly、Pick、Record

                  用模式匹配 + 递归可以实现: Awaited

                  用联合类型在分布式条件类型的特性可以实现: Exclude

                  此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

                  ',33)]))}const m=e(o,[["render",l]]);export{u as __pageData,m as default}; +import{_ as e,o as r,c as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"TypeScript 内置的高级类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/高级类型.md","filePath":"src/types/高级类型.md","lastUpdated":1728921295000}'),o={name:"src/types/高级类型.md"};function l(n,a,h,c,s,d){return r(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

                  TypeScript 内置的高级类型

                  Parameters

                  Parameters 用于提取函数类型的参数类型。

                  ReturnType

                  ReturnType 用于提取函数类型的返回值类型。

                  ConstructorParameters

                  构造器类型和函数类型的区别就是可以被 new。

                  Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

                  InstanceType

                  提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

                  ThisParameterType

                  OmitThisParameter

                  Partial

                  Required

                  Readonly

                  Pick

                  Record

                  Exclude

                  Extract

                  Omit

                  Awaited

                  NonNullable

                  Uppercase

                  Lowercase

                  Capitalize

                  Uncapitalize

                  总结

                  比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

                  用模式匹配 + 重新构造可以实现:OmitThisParameter

                  用重新构造可以实现:Partial、Required、Readonly、Pick、Record

                  用模式匹配 + 递归可以实现: Awaited

                  用联合类型在分布式条件类型的特性可以实现: Exclude

                  此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

                  ',33)]))}const m=e(o,[["render",l]]);export{u as __pageData,m as default}; diff --git "a/assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DrTZYnDE.lean.js" "b/assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CufDmqA6.lean.js" similarity index 98% rename from "assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DrTZYnDE.lean.js" rename to "assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CufDmqA6.lean.js" index c24ff9951d..eb87446336 100644 --- "a/assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.DrTZYnDE.lean.js" +++ "b/assets/src_types_\351\253\230\347\272\247\347\261\273\345\236\213.md.CufDmqA6.lean.js" @@ -1 +1 @@ -import{_ as e,o as r,c as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"TypeScript 内置的高级类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/高级类型.md","filePath":"src/types/高级类型.md","lastUpdated":1728828157000}'),o={name:"src/types/高级类型.md"};function l(n,a,h,c,s,d){return r(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

                  TypeScript 内置的高级类型

                  Parameters

                  Parameters 用于提取函数类型的参数类型。

                  ReturnType

                  ReturnType 用于提取函数类型的返回值类型。

                  ConstructorParameters

                  构造器类型和函数类型的区别就是可以被 new。

                  Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

                  InstanceType

                  提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

                  ThisParameterType

                  OmitThisParameter

                  Partial

                  Required

                  Readonly

                  Pick

                  Record

                  Exclude

                  Extract

                  Omit

                  Awaited

                  NonNullable

                  Uppercase

                  Lowercase

                  Capitalize

                  Uncapitalize

                  总结

                  比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

                  用模式匹配 + 重新构造可以实现:OmitThisParameter

                  用重新构造可以实现:Partial、Required、Readonly、Pick、Record

                  用模式匹配 + 递归可以实现: Awaited

                  用联合类型在分布式条件类型的特性可以实现: Exclude

                  此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

                  ',33)]))}const m=e(o,[["render",l]]);export{u as __pageData,m as default}; +import{_ as e,o as r,c as t,a3 as i}from"./chunks/framework.BYE6xntm.js";const u=JSON.parse('{"title":"TypeScript 内置的高级类型","description":"","frontmatter":{},"headers":[],"relativePath":"src/types/高级类型.md","filePath":"src/types/高级类型.md","lastUpdated":1728921295000}'),o={name:"src/types/高级类型.md"};function l(n,a,h,c,s,d){return r(),t("div",{"data-pagefind-body":!0},a[0]||(a[0]=[i('

                  TypeScript 内置的高级类型

                  Parameters

                  Parameters 用于提取函数类型的参数类型。

                  ReturnType

                  ReturnType 用于提取函数类型的返回值类型。

                  ConstructorParameters

                  构造器类型和函数类型的区别就是可以被 new。

                  Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

                  InstanceType

                  提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

                  ThisParameterType

                  OmitThisParameter

                  Partial

                  Required

                  Readonly

                  Pick

                  Record

                  Exclude

                  Extract

                  Omit

                  Awaited

                  NonNullable

                  Uppercase

                  Lowercase

                  Capitalize

                  Uncapitalize

                  总结

                  比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

                  用模式匹配 + 重新构造可以实现:OmitThisParameter

                  用重新构造可以实现:Partial、Required、Readonly、Pick、Record

                  用模式匹配 + 递归可以实现: Awaited

                  用联合类型在分布式条件类型的特性可以实现: Exclude

                  此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

                  ',33)]))}const m=e(o,[["render",l]]);export{u as __pageData,m as default}; diff --git a/cn/index.html b/cn/index.html index 03cfc77015..82fc7812a7 100644 --- a/cn/index.html +++ b/cn/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - +
                  Skip to content

                  ran

                  风起于青萍之末

                  A ship in harbor is safe, but that is not what ships are built for.

                  logo

                  Released under the MIT License.

                  - + \ No newline at end of file diff --git a/cn/src/article/astParse/tokenizer.html b/cn/src/article/astParse/tokenizer.html index a011b5a0e5..4bd79518bf 100644 --- a/cn/src/article/astParse/tokenizer.html +++ b/cn/src/article/astParse/tokenizer.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -226,8 +226,8 @@ { type: 'RightParen', value: ')', start: 17, end: 18 }, { type: 'LeftCurly', value: '{', start: 19, end: 20 }, { type: 'RightCurly', value: '}', start: 20, end: 21 }, -];

                  一个简易版本的分词器已经被我们开发出来了,不过目前的分词器还比较简陋,仅仅支持有限的语法,不过在明确了核心的开发步骤之后,后面继续完善的过程就比较简单了。

                  四。编写语法分析器(Parser)

                  在解析出词法 token 之后,我们就可以进入语法分析阶段了。在这个阶段,我们会依次遍历 token ,对代码进行语法结构层面的分析,最后的目标是生成 AST 数据结构。至于代码的 AST 结构到底是什么样子,你可以去 AST Explorer 网站进行在线预览:

                  接下来,我们要做的就是将 token 数组转换为上图所示的 AST 数据。

                  开发步骤主要分为:

                  • 初始化类型声明

                  Released under the MIT License.

                  - +];

                  一个简易版本的分词器已经被我们开发出来了,不过目前的分词器还比较简陋,仅仅支持有限的语法,不过在明确了核心的开发步骤之后,后面继续完善的过程就比较简单了。

                  四。编写语法分析器(Parser)

                  在解析出词法 token 之后,我们就可以进入语法分析阶段了。在这个阶段,我们会依次遍历 token ,对代码进行语法结构层面的分析,最后的目标是生成 AST 数据结构。至于代码的 AST 结构到底是什么样子,你可以去 AST Explorer 网站进行在线预览:

                  接下来,我们要做的就是将 token 数组转换为上图所示的 AST 数据。

                  开发步骤主要分为:

                  • 初始化类型声明

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/babel.html b/cn/src/article/babel.html index 5fed7080f0..f3f9b3468b 100644 --- a/cn/src/article/babel.html +++ b/cn/src/article/babel.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
                  Skip to content

                  Babel

                  babel 核心库主要是:

                  • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
                  • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
                  • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
                  • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
                  • @babel/code-frame 可以创建友好的报错信息
                  • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
                  • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。

                  Released under the MIT License.

                  - +
                  Skip to content

                  Babel

                  babel 核心库主要是:

                  • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
                  • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
                  • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
                  • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
                  • @babel/code-frame 可以创建友好的报错信息
                  • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
                  • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/bundle.html b/cn/src/article/bundle.html index 99b84eebfc..9846274393 100644 --- a/cn/src/article/bundle.html +++ b/cn/src/article/bundle.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
                  Skip to content

                  Bundle

                  Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:

                  • 编译能力
                  • 插件机制
                  • HMR
                  • cli 和命令行能力

                  Released under the MIT License.

                  - +
                  Skip to content

                  Bundle

                  Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:

                  • 编译能力
                  • 插件机制
                  • HMR
                  • cli 和命令行能力

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/designMode.html b/cn/src/article/designMode.html index 7c99380731..f09f958928 100644 --- a/cn/src/article/designMode.html +++ b/cn/src/article/designMode.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -794,8 +794,8 @@ Visitor.push(a,1,2,3,4); Visitor.push(a,4,5,6); Visitor.pop(a); -Visitor.splice(a,2);

                  访问者模式解决了数据与数据的操作方法之间的耦合,让数据的操作方法独立于数据,使其可以自由演变。因此,访问者模式更适合于那些数据稳定、但数据的操作方法易变的环境下。

                  优点:

                  • 增加新的访问操作很方便。使用访问者模式,增加新的访问操作就意味着增加一个新的具体访问者类,实现简单,无须修改源代码,符合“开闭原则”。
                  • 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问。
                  • 让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作。

                  缺点:

                  • 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”的要求。
                  • 破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问。

                  总结

                  系统地学习设计模式后,你可以在过往的开发经历中发现,设计模式是无处不在的。在学习设计模式之前的很多时候我们是凭借过往经验和智慧来完善系统的设计,而这些经验很多和某个设计模式的思想不谋而合。

                  还有一些地方没有完全理解,文中有误之处还望不吝指出。

                  参考资料

                  Released under the MIT License.

                  - +Visitor.splice(a,2);

                  访问者模式解决了数据与数据的操作方法之间的耦合,让数据的操作方法独立于数据,使其可以自由演变。因此,访问者模式更适合于那些数据稳定、但数据的操作方法易变的环境下。

                  优点:

                  • 增加新的访问操作很方便。使用访问者模式,增加新的访问操作就意味着增加一个新的具体访问者类,实现简单,无须修改源代码,符合“开闭原则”。
                  • 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中。类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问。
                  • 让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作。

                  缺点:

                  • 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”的要求。
                  • 破坏封装。访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问。

                  总结

                  系统地学习设计模式后,你可以在过往的开发经历中发现,设计模式是无处不在的。在学习设计模式之前的很多时候我们是凭借过往经验和智慧来完善系统的设计,而这些经验很多和某个设计模式的思想不谋而合。

                  还有一些地方没有完全理解,文中有误之处还望不吝指出。

                  参考资料

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/docPreview.html b/cn/src/article/docPreview.html index 826adf36e3..039ad88e56 100644 --- a/cn/src/article/docPreview.html +++ b/cn/src/article/docPreview.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -304,8 +304,8 @@ public static void main(String[] args) { convertToPDF("/Users/koolearn/Desktop/asdf.docx", "/Users/koolearn/Desktop/adsf.pdf"); } -}

                  2.kkFileView

                  github地址:https://github.com/kekingcn/kkFileView

                  支持的文件预览格式非常丰富 image.png

                  接下来是 从零到一 的启动步骤,按着步骤来,任何人都能搞定

                  1. 安装java:
                  sh
                  brew install java
                  1. 安装maven,java的包管理工具:
                  sh
                  brew install mvn
                  1. 检查是否安装成功

                  执行java --versionmvn -v。我这里遇到mvn找不到java home的报错。解决方式如下:

                  我用的是zsh,所以需要去.zshrc添加路径:

                  export JAVA_HOME=$(/usr/libexec/java_home)

                  添加完后,执行

                  source .zshrc
                  1. 安装下libreoffice :

                  kkFileView明确要求的额外依赖,否则无法启动

                  brew install libreoffice
                  1. mvn安装依赖

                  进入项目,在根目录执行依赖安装,同时清理缓存,跳过单测 (遇到了单测报错的问题)

                  mvn clean install -DskipTests
                  1. 启动项目

                  找到主文件,主函数mian,点击vscode上面的Run即可执行,路径如下图

                  image.png

                  1. 访问页面

                  启动完成后,点击终端输出的地址

                  image.png

                  1. 最终结果

                  最终展示如下,可以添加链接进行预览,也可以选择本地文件进行预览

                  image.png

                  预览效果非常好

                  3.onlyOffice

                  官网地址:https://www.onlyoffice.com/zh

                  github地址:https://github.com/ONLYOFFICE

                  开发者版本和社区版免费,企业版付费:https://www.onlyoffice.com/zh/docs-enterprise-prices.aspx

                  预览的文件种类没有kkFileView多,但对office三件套有很好的支持,甚至支持多人编辑。

                  四:总结

                  1. 外部服务,推荐微软的view.officeapps.live.com/op/view.aspx,但只建议预览一些互联网公开的文件,不建议使用在要求保密性和稳定性的文件。
                  2. 对保密性和稳定性有要求,且不差钱的,可以试试大厂服务,阿里云解决方案。
                  3. 服务端技术比较给力的,使用服务端预览方案。目前最好最全的效果是服务端预览方案。
                  4. 不想花钱,没有服务器的,使用前端预览方案,客户端渲染零成本。

                  五:参考文档:

                  1. 在 java 中如何使用 openOffice 进行格式转换
                  2. MAC 搭建 OpenOffice 完整教程 - 保姆级
                  3. 纯 js 实现 docx、xlsx、pdf 文件预览库,使用超简单
                  4. 前端实现 word、excel、pdf、ppt、mp4、图片、文本等文件的预览

                  Released under the MIT License.

                  - +}

                  2.kkFileView

                  github地址:https://github.com/kekingcn/kkFileView

                  支持的文件预览格式非常丰富 image.png

                  接下来是 从零到一 的启动步骤,按着步骤来,任何人都能搞定

                  1. 安装java:
                  sh
                  brew install java
                  1. 安装maven,java的包管理工具:
                  sh
                  brew install mvn
                  1. 检查是否安装成功

                  执行java --versionmvn -v。我这里遇到mvn找不到java home的报错。解决方式如下:

                  我用的是zsh,所以需要去.zshrc添加路径:

                  export JAVA_HOME=$(/usr/libexec/java_home)

                  添加完后,执行

                  source .zshrc
                  1. 安装下libreoffice :

                  kkFileView明确要求的额外依赖,否则无法启动

                  brew install libreoffice
                  1. mvn安装依赖

                  进入项目,在根目录执行依赖安装,同时清理缓存,跳过单测 (遇到了单测报错的问题)

                  mvn clean install -DskipTests
                  1. 启动项目

                  找到主文件,主函数mian,点击vscode上面的Run即可执行,路径如下图

                  image.png

                  1. 访问页面

                  启动完成后,点击终端输出的地址

                  image.png

                  1. 最终结果

                  最终展示如下,可以添加链接进行预览,也可以选择本地文件进行预览

                  image.png

                  预览效果非常好

                  3.onlyOffice

                  官网地址:https://www.onlyoffice.com/zh

                  github地址:https://github.com/ONLYOFFICE

                  开发者版本和社区版免费,企业版付费:https://www.onlyoffice.com/zh/docs-enterprise-prices.aspx

                  预览的文件种类没有kkFileView多,但对office三件套有很好的支持,甚至支持多人编辑。

                  四:总结

                  1. 外部服务,推荐微软的view.officeapps.live.com/op/view.aspx,但只建议预览一些互联网公开的文件,不建议使用在要求保密性和稳定性的文件。
                  2. 对保密性和稳定性有要求,且不差钱的,可以试试大厂服务,阿里云解决方案。
                  3. 服务端技术比较给力的,使用服务端预览方案。目前最好最全的效果是服务端预览方案。
                  4. 不想花钱,没有服务器的,使用前端预览方案,客户端渲染零成本。

                  五:参考文档:

                  1. 在 java 中如何使用 openOffice 进行格式转换
                  2. MAC 搭建 OpenOffice 完整教程 - 保姆级
                  3. 纯 js 实现 docx、xlsx、pdf 文件预览库,使用超简单
                  4. 前端实现 word、excel、pdf、ppt、mp4、图片、文本等文件的预览

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/functionalProgramming.html b/cn/src/article/functionalProgramming.html index 94bb41eee7..e8d2e2ad32 100644 --- a/cn/src/article/functionalProgramming.html +++ b/cn/src/article/functionalProgramming.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -379,8 +379,8 @@ }; let r = readFile('package.json') //这里可以用 map 去处理内容 .flatMap(print) - .join();

                  参考资料

                  Released under the MIT License.

                  - + .join();

                  参考资料

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/imagemin.html b/cn/src/article/imagemin.html index bbb3fbd1a0..d100630593 100644 --- a/cn/src/article/imagemin.html +++ b/cn/src/article/imagemin.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + - - + + \ No newline at end of file diff --git a/cn/src/article/javascript/domLoad.html b/cn/src/article/javascript/domLoad.html index 62d19d7ae6..ed0e645ca9 100644 --- a/cn/src/article/javascript/domLoad.html +++ b/cn/src/article/javascript/domLoad.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -44,8 +44,8 @@
                  Skip to content

                  页面加载完成后事件

                  window.onload

                  DOMContentLoaded

                  js
                  document.addEventListener('DOMContentLoaded', fun);

                  <body onload="fun()">

                  readyState

                  js
                  document.readyState;
                   
                  -document.onreadystatechange;

                  一个文档的 readyState 可以是以下之一:

                  • loading / 加载。document 仍在加载。
                  • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
                  • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。

                  Released under the MIT License.

                  - +document.onreadystatechange;

                  一个文档的 readyState 可以是以下之一:

                  • loading / 加载。document 仍在加载。
                  • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
                  • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/sort/bubble/index.html b/cn/src/article/sort/bubble/index.html index e77b0ce640..a3c6a95038 100644 --- a/cn/src/article/sort/bubble/index.html +++ b/cn/src/article/sort/bubble/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -55,8 +55,8 @@ } } return list; -};

                  Released under the MIT License.

                  - +};

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/sort/bucket/index.html b/cn/src/article/sort/bucket/index.html index 30f2a91f0a..e5c25aa668 100644 --- a/cn/src/article/sort/bucket/index.html +++ b/cn/src/article/sort/bucket/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -98,8 +98,8 @@ list = list.concat(count(buckets[i])); } return list; -};

                  算法分析

                  桶排序最好情况下使用线性时间 O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为 O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。

                  Released under the MIT License.

                  - +};

                  算法分析

                  桶排序最好情况下使用线性时间 O(n),桶排序的时间复杂度,取决与对各个桶之间数据进行排序的时间复杂度,因为其它部分的时间复杂度都为 O(n)。很显然,桶划分的越小,各个桶之间的数据越少,排序所用的时间也会越少。但相应的空间消耗就会增大。

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/sort/count/index.html b/cn/src/article/sort/count/index.html index 8fd7301c68..5e82f2d996 100644 --- a/cn/src/article/sort/count/index.html +++ b/cn/src/article/sort/count/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -76,8 +76,8 @@ } } return result; -};

                  算法分析

                  计数排序是一个稳定的排序算法。当输入的元素是 n 个 0 到 k 之间的整数时,时间复杂度是 O(n+k),空间复杂度也是 O(n+k),其排序速度快于任何比较排序算法。当 k 不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。

                  Released under the MIT License.

                  - +};

                  算法分析

                  计数排序是一个稳定的排序算法。当输入的元素是 n 个 0 到 k 之间的整数时,时间复杂度是 O(n+k),空间复杂度也是 O(n+k),其排序速度快于任何比较排序算法。当 k 不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。

                  Released under the MIT License.

                  + \ No newline at end of file diff --git a/cn/src/article/sort/heap/index.html b/cn/src/article/sort/heap/index.html index cdd9d25f22..63bb39983f 100644 --- a/cn/src/article/sort/heap/index.html +++ b/cn/src/article/sort/heap/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -92,8 +92,8 @@ const heap = (list: Array<number>): Array<number> => { const { value } = new Heap(list); return value; -};

                Released under the MIT License.

            - +};

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/sort/index.html b/cn/src/article/sort/index.html index dfc19f6769..d96aea14e8 100644 --- a/cn/src/article/sort/index.html +++ b/cn/src/article/sort/index.html @@ -13,7 +13,7 @@ - + @@ -37,14 +37,14 @@ - + -
          Skip to content

          十大经典排序

          十种常见排序算法可以分为两大类:

          • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O(nlogn),因此也称为非线性时间比较类排序。
          • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

          排序分类

          算法复杂度

          算法复杂度

          相关概念

          • 稳定:如果 a 原本在 b 前面,而 a=b,排序之后 a 仍然在 b 的前面。
          • 不稳定:如果 a 原本在 b 的前面,而 a=b,排序之后 a 可能会出现在 b 的后面。
          • 时间复杂度:对排序数据的总的操作次数。反映当 n 变化时,操作次数呈现什么规律。
          • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模 n 的函数。

          Released under the MIT License.

          - +
          Skip to content

          十大经典排序

          十种常见排序算法可以分为两大类:

          • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破 O(nlogn),因此也称为非线性时间比较类排序。
          • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

          排序分类

          算法复杂度

          算法复杂度

          相关概念

          • 稳定:如果 a 原本在 b 前面,而 a=b,排序之后 a 仍然在 b 的前面。
          • 不稳定:如果 a 原本在 b 的前面,而 a=b,排序之后 a 可能会出现在 b 的后面。
          • 时间复杂度:对排序数据的总的操作次数。反映当 n 变化时,操作次数呈现什么规律。
          • 空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模 n 的函数。

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/sort/insert/index.html b/cn/src/article/sort/insert/index.html index 47116c6e18..75e4cae102 100644 --- a/cn/src/article/sort/insert/index.html +++ b/cn/src/article/sort/insert/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -55,8 +55,8 @@ list[preIndex + 1] = current; } return list; -};

          算法分析

          插入排序在实现上,通常采用 in-place 排序(即只需用到 O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

          Released under the MIT License.

          - +};

          算法分析

          插入排序在实现上,通常采用 in-place 排序(即只需用到 O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/sort/merge/index.html b/cn/src/article/sort/merge/index.html index 584bbc4254..e21c2bf769 100644 --- a/cn/src/article/sort/merge/index.html +++ b/cn/src/article/sort/merge/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -75,8 +75,8 @@ const left = list.slice(0, middle); const right = list.slice(middle); return combine(merge(left), merge(right)); -};

          算法分析

          归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O(nlogn)的时间复杂度。代价是需要额外的内存空间。

          Released under the MIT License.

          - +};

          算法分析

          归并排序是一种稳定的排序方法。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O(nlogn)的时间复杂度。代价是需要额外的内存空间。

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/sort/quick/index.html b/cn/src/article/sort/quick/index.html index 4c59dafe07..70ada51388 100644 --- a/cn/src/article/sort/quick/index.html +++ b/cn/src/article/sort/quick/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -93,8 +93,8 @@ const quick = (list: number[] = []): number[] => { const size = list.length; return combine(list, 0, size - 1); -};

          Released under the MIT License.

          - +};

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/sort/radix/index.html b/cn/src/article/sort/radix/index.html index 51a7884eb2..eca9ae05b0 100644 --- a/cn/src/article/sort/radix/index.html +++ b/cn/src/article/sort/radix/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -78,8 +78,8 @@ list = list.concat(count(buckets[i])); } return list; -};

          算法分析

          基数排序基于分配排序,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要 O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要 O(n)的时间复杂度。假如待排数据可以分为 d 个关键字,则基数排序的时间复杂度将是 O(d*2n) ,当然 d 要远远小于 n,因此基本上还是线性级别的。

          基数排序的空间复杂度为 O(n+k),其中 k 为桶的数量。一般来说 n>>k,因此额外空间需要大概 n 个左右。

          Released under the MIT License.

          - +};

          算法分析

          基数排序基于分配排序,所以是稳定的。但基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要 O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要 O(n)的时间复杂度。假如待排数据可以分为 d 个关键字,则基数排序的时间复杂度将是 O(d*2n) ,当然 d 要远远小于 n,因此基本上还是线性级别的。

          基数排序的空间复杂度为 O(n+k),其中 k 为桶的数量。一般来说 n>>k,因此额外空间需要大概 n 个左右。

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/sort/select/index.html b/cn/src/article/sort/select/index.html index 1c0fa0f790..3a6b90abce 100644 --- a/cn/src/article/sort/select/index.html +++ b/cn/src/article/sort/select/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -59,8 +59,8 @@ } } return list; -};

          算法分析

          表现最稳定的排序算法之一,因为无论什么数据进去都是 O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法了吧。

          Released under the MIT License.

          - +};

          算法分析

          表现最稳定的排序算法之一,因为无论什么数据进去都是 O(n2)的时间复杂度,所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。理论上讲,选择排序可能也是平时排序一般人想到的最多的排序方法了吧。

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/sort/shell/index.html b/cn/src/article/sort/shell/index.html index 4c7a23dd05..a95e057043 100644 --- a/cn/src/article/sort/shell/index.html +++ b/cn/src/article/sort/shell/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -62,8 +62,8 @@ } } return list; -};

          算法分析

          希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第 4 版)》的合著者 Robert Sedgewick 提出的。

          Released under the MIT License.

          - +};

          算法分析

          希尔排序的核心在于间隔序列的设定。既可以提前设定好间隔序列,也可以动态的定义间隔序列。动态定义间隔序列的算法是《算法(第 4 版)》的合著者 Robert Sedgewick 提出的。

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/systemDesign.html b/cn/src/article/systemDesign.html index 9a77327161..1d2c8a549a 100644 --- a/cn/src/article/systemDesign.html +++ b/cn/src/article/systemDesign.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
          Skip to content

          如何处理一个系统设计

          系统设计是一个开放式的对话。他们期望你去主导这个对话。

          你可以使用下面的步骤来指引讨论。为了巩固这个过程,请使用下面的步骤完成系统设计的面试题和解答这个章节。

          第一步:描述使用场景,约束和假设

          把所有需要的东西聚集在一起,审视问题。不停的提问,以至于我们可以明确使用场景和约束。讨论假设。

          谁会使用它? 他们会怎样使用它? 有多少用户? 系统的作用是什么? 系统的输入输出分别是什么? 我们希望处理多少数据? 我们希望每秒钟处理多少请求? 我们希望的读写比率?

          第二步:创造一个高层级的设计

          使用所有重要的组件来描绘出一个高层级的设计。

          画出主要的组件和连接 证明你的想法

          第三步:设计核心组件

          对每一个核心组件进行详细深入的分析。举例来说,如果你被问到设计一个 url 缩写服务,开始讨论:

          生成并储存一个完整 url 的 hash MD5 和 Base62 Hash 碰撞 SQL 还是 NoSQL 数据库模型 将一个 hashed url 翻译成完整的 url 数据库查找 API 和面向对象设计

          第四步:扩展设计

          确认和处理瓶颈以及一些限制。举例来说就是你需要下面的这些来完成扩展性的议题吗?

          负载均衡 水平扩展 缓存 数据库分片 论述可能的解决办法和代价。每件事情需要取舍。可以使用可扩展系统的设计原则来处理瓶颈。

          Released under the MIT License.

          - +
          Skip to content

          如何处理一个系统设计

          系统设计是一个开放式的对话。他们期望你去主导这个对话。

          你可以使用下面的步骤来指引讨论。为了巩固这个过程,请使用下面的步骤完成系统设计的面试题和解答这个章节。

          第一步:描述使用场景,约束和假设

          把所有需要的东西聚集在一起,审视问题。不停的提问,以至于我们可以明确使用场景和约束。讨论假设。

          谁会使用它? 他们会怎样使用它? 有多少用户? 系统的作用是什么? 系统的输入输出分别是什么? 我们希望处理多少数据? 我们希望每秒钟处理多少请求? 我们希望的读写比率?

          第二步:创造一个高层级的设计

          使用所有重要的组件来描绘出一个高层级的设计。

          画出主要的组件和连接 证明你的想法

          第三步:设计核心组件

          对每一个核心组件进行详细深入的分析。举例来说,如果你被问到设计一个 url 缩写服务,开始讨论:

          生成并储存一个完整 url 的 hash MD5 和 Base62 Hash 碰撞 SQL 还是 NoSQL 数据库模型 将一个 hashed url 翻译成完整的 url 数据库查找 API 和面向对象设计

          第四步:扩展设计

          确认和处理瓶颈以及一些限制。举例来说就是你需要下面的这些来完成扩展性的议题吗?

          负载均衡 水平扩展 缓存 数据库分片 论述可能的解决办法和代价。每件事情需要取舍。可以使用可扩展系统的设计原则来处理瓶颈。

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/typescript/calculate.html b/cn/src/article/typescript/calculate.html index 10f7f763c1..da365ae7e9 100644 --- a/cn/src/article/typescript/calculate.html +++ b/cn/src/article/typescript/calculate.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -72,8 +72,8 @@ ? CurrentArr['length'] : FibonacciLoop<CurrentArr, [...PrevArr, ...CurrentArr], [...IndexArr, unknown], Num>; -type Fibonacci<Num extends number> = FibonacciLoop<[1], [], [], Num>;

          类型参数 PrevArr 是代表之前的累加值的数组。类型参数 CurrentArr 是代表当前数值的数组。

          类型参数 IndexArr 用于记录 index,每次递归加一,默认值是 [],代表从 0 开始。

          类型参数 Num 代表求数列的第几个数。

          判断当前 index 也就是 IndexArr['length'] 是否到了 Num,到了就返回当前的数值 CurrentArr['length']。

          否则求出当前 index 对应的数值,用之前的数加上当前的数 [...PrevArr, ... CurrentArr]。

          然后继续递归,index + 1,也就是 [...IndexArr, unknown]。

          这就是递归计算 Fibinacci 数列的数的过程。

          可以正确的算出第 8 个数是 21:

          Released under the MIT License.

          - +type Fibonacci<Num extends number> = FibonacciLoop<[1], [], [], Num>;

          类型参数 PrevArr 是代表之前的累加值的数组。类型参数 CurrentArr 是代表当前数值的数组。

          类型参数 IndexArr 用于记录 index,每次递归加一,默认值是 [],代表从 0 开始。

          类型参数 Num 代表求数列的第几个数。

          判断当前 index 也就是 IndexArr['length'] 是否到了 Num,到了就返回当前的数值 CurrentArr['length']。

          否则求出当前 index 对应的数值,用之前的数加上当前的数 [...PrevArr, ... CurrentArr]。

          然后继续递归,index + 1,也就是 [...IndexArr, unknown]。

          这就是递归计算 Fibinacci 数列的数的过程。

          可以正确的算出第 8 个数是 21:

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/typescript/index.html b/cn/src/article/typescript/index.html index d68d4e56b0..ffff6db605 100644 --- a/cn/src/article/typescript/index.html +++ b/cn/src/article/typescript/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -197,8 +197,8 @@ type TestAnyResult = TestAny<any>; // type TestAnyResult = 1 | 2

          联合类型、never、any 在作为条件类型的类型参数时的这些特殊情况,也会在后面的原理篇来解释原因。

          IsTuple

          元组类型怎么判断呢?它和数组有什么区别呢?

          元组类型的 length 是数字字面量,而数组的 length 是 number。

          ts
          type len

          UnionToIntersection

          类型之间是有父子关系的,更具体的那个是子类型,比如 A 和 B 的交叉类型 A & B 就是联合类型 A | B 的子类型,因为更具体。

          如果允许父类型赋值给子类型,就叫做逆变

          如果允许子类型赋值给父类型,就叫做协变

          (关于逆变、协变等概念的详细解释可以看原理篇)

          在 TypeScript 中有函数参数是有逆变的性质的,也就是如果参数可能是多个类型,参数类型会变成它们的交叉类型。

          所以联合转交叉可以这样实现 :

          ts
          type UnionToIntersection<U> = (U extends U ? (x: U) => unknown : never) extends (x: infer R) => unknown ? R : never;

          类型参数 U 是要转换的联合类型。

          U extends U 是为了触发联合类型的 distributive 的性质,让每个类型单独传入做计算,最后合并。

          利用 U 做为参数构造个函数,通过模式匹配取参数的类型。

          结果就是交叉类型

          函数参数的逆变性质一般就联合类型转交叉类型会用,记住就行。

          GetOptional

          如何提取索引类型中的可选索引呢?

          这也要利用可选索引的特性:可选索引的值为 undefined 和值类型的联合类型。

          过滤可选索引,就要构造一个新的索引类型,过程中做过滤:

          ts
          type GetOptional<Obj extends Record<string, any>> = {
             [Key in keyof Obj as {} extends Pick<Obj, Key> ? Key : never]: Obj[Key];
          -};

          类型参数 Obj 为待处理的索引类型,类型约束为索引为 string、值为任意类型的索引类型 Record<string, any>。

          用映射类型的语法重新构造索引类型,索引是之前的索引也就是 Key in keyof Obj,但要做一些过滤,也就是 as 之后的部分。

          过滤的方式就是单独取出该索引之后,判断空对象是否是其子类型。

          这里的 Pick 是 ts 提供的内置高级类型,就是取出某个 Key 构造新的索引类型:

          ts
          type Pick<T, K extends keyof T> = { [P in K]: T[P] };

          比如单独取出 age 构造的新的索引类型是这样的:

          可选的意思是这个索引可能没有,没有的时候,那 Pick<Obj, Key> 就是空的,所以 {} extends Pick<Obj, Key> 就能过滤出可选索引。

          值的类型依然是之前的,也就是 Obj[Key]。

          这样,就能过滤出所有可选索引,构造成新的索引类型:

          总结

          • any 类型与任何类型的交叉都是 any,也就是 1 & any 结果是 any,可以用这个特性判断 any 类型。
          • 联合类型作为类型参数出现在条件类型左侧时,会分散成单个类型传入,最后合并。
          • never 作为类型参数出现在条件类型左侧时,会直接返回 never。
          • any 作为类型参数出现在条件类型左侧时,会直接返回 trueType 和 falseType 的联合类型。
          • 元组类型也是数组类型,但 length 是数字字面量,而数组的 length 是 number。可以用来判断元组类型。
          • 函数参数处会发生逆变,可以用来实现联合类型转交叉类型。
          • 可选索引的索引可能没有,那 Pick 出来的就可能是 {},可以用来过滤可选索引,反过来也可以过滤非可选索引。
          • 索引类型的索引为字符串字面量类型,而可索引签名不是,可以用这个特性过滤掉可索引签名。
          • keyof 只能拿到 class 的 public 的索引,可以用来过滤出 public 的属性。
          • 默认推导出来的不是字面量类型,加上 as const 可以推导出字面量类型,但带有 readonly 修饰,这样模式匹配的时候也得加上 readonly 才行。

          Released under the MIT License.

          - +};

          类型参数 Obj 为待处理的索引类型,类型约束为索引为 string、值为任意类型的索引类型 Record<string, any>。

          用映射类型的语法重新构造索引类型,索引是之前的索引也就是 Key in keyof Obj,但要做一些过滤,也就是 as 之后的部分。

          过滤的方式就是单独取出该索引之后,判断空对象是否是其子类型。

          这里的 Pick 是 ts 提供的内置高级类型,就是取出某个 Key 构造新的索引类型:

          ts
          type Pick<T, K extends keyof T> = { [P in K]: T[P] };

          比如单独取出 age 构造的新的索引类型是这样的:

          可选的意思是这个索引可能没有,没有的时候,那 Pick<Obj, Key> 就是空的,所以 {} extends Pick<Obj, Key> 就能过滤出可选索引。

          值的类型依然是之前的,也就是 Obj[Key]。

          这样,就能过滤出所有可选索引,构造成新的索引类型:

          总结

          • any 类型与任何类型的交叉都是 any,也就是 1 & any 结果是 any,可以用这个特性判断 any 类型。
          • 联合类型作为类型参数出现在条件类型左侧时,会分散成单个类型传入,最后合并。
          • never 作为类型参数出现在条件类型左侧时,会直接返回 never。
          • any 作为类型参数出现在条件类型左侧时,会直接返回 trueType 和 falseType 的联合类型。
          • 元组类型也是数组类型,但 length 是数字字面量,而数组的 length 是 number。可以用来判断元组类型。
          • 函数参数处会发生逆变,可以用来实现联合类型转交叉类型。
          • 可选索引的索引可能没有,那 Pick 出来的就可能是 {},可以用来过滤可选索引,反过来也可以过滤非可选索引。
          • 索引类型的索引为字符串字面量类型,而可索引签名不是,可以用这个特性过滤掉可索引签名。
          • keyof 只能拿到 class 的 public 的索引,可以用来过滤出 public 的属性。
          • 默认推导出来的不是字面量类型,加上 as const 可以推导出字面量类型,但带有 readonly 修饰,这样模式匹配的时候也得加上 readonly 才行。

          Released under the MIT License.

          + \ No newline at end of file diff --git a/cn/src/article/typescript/pattern.html b/cn/src/article/typescript/pattern.html index af7836804a..cbff70d862 100644 --- a/cn/src/article/typescript/pattern.html +++ b/cn/src/article/typescript/pattern.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -134,8 +134,8 @@ : never : never;

          类型参数 Props 为待处理的类型。

          通过 keyof Props 取出 Props 的所有索引构成的联合类型,判断下 ref 是否在其中,也就是 'ref' extends keyof Props。

          为什么要做这个判断,上面注释里写了:

          在 ts3.0 里面如果没有对应的索引,Obj[Key] 返回的是 {} 而不是 never,所以这样做下兼容处理。

          如果有 ref 这个索引的话,就通过 infer 提取 Value 的类型返回,否则返回 never。

          ts
          type GetPropsRefResult = GetPropsRef<{ ref: 1; name: 'str' }>;
           // type GetPropsRefResult = 1

          当 ref 为 undefined 时:

          ts
          type GetPropsRefResult = GetPropsRef<{ ref: undefined; name: 'str' }>;
          -// type GetPropsRefResult = undefined

          Released under the MIT License.

          - +// type GetPropsRefResult = undefined

        Released under the MIT License.

    + \ No newline at end of file diff --git a/cn/src/article/typescript/reconstruction.html b/cn/src/article/typescript/reconstruction.html index 2c18e120ac..3e26bc1597 100644 --- a/cn/src/article/typescript/reconstruction.html +++ b/cn/src/article/typescript/reconstruction.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -89,8 +89,8 @@ [Key in keyof T]-?: T[Key]; };

给索引类型 T 的索引去掉 ? 的修饰 ,其余保持不变。

FilterByValueType

可以在构造新索引类型的时候根据值的类型做下过滤:

ts
type FilterByValueType<Obj extends Record<string, any>, ValueType> = {
   [Key in keyof Obj as Obj[Key] extends ValueType ? Key : never]: Obj[Key];
-};

类型参数 Obj 为要处理的索引类型,通过 extends 约束为索引为 string,值为任意类型的索引类型 Record<string, any>。

类型参数 ValueType 为要过滤出的值的类型。

构造新的索引类型,索引为 Obj 的索引,也就是 Key in keyof Obj,但要做一些变换,也就是 as 之后的部分。

如果原来索引的值 Obj[Key] 是 ValueType 类型,索引依然为之前的索引 Key,否则索引设置为 never,never 的索引会在生成新的索引类型时被去掉。

值保持不变,依然为原来索引的值,也就是 Obj[Key]。

这样就达到了过滤索引类型的索引,产生新的索引类型的目的:

- +};

类型参数 Obj 为要处理的索引类型,通过 extends 约束为索引为 string,值为任意类型的索引类型 Record<string, any>。

类型参数 ValueType 为要过滤出的值的类型。

构造新的索引类型,索引为 Obj 的索引,也就是 Key in keyof Obj,但要做一些变换,也就是 as 之后的部分。

如果原来索引的值 Obj[Key] 是 ValueType 类型,索引依然为之前的索引 Key,否则索引设置为 never,never 的索引会在生成新的索引类型时被去掉。

值保持不变,依然为原来索引的值,也就是 Obj[Key]。

这样就达到了过滤索引类型的索引,产生新的索引类型的目的:

+ \ No newline at end of file diff --git a/cn/src/article/typescript/recursion.html b/cn/src/article/typescript/recursion.html index ebef32f616..e488966611 100644 --- a/cn/src/article/typescript/recursion.html +++ b/cn/src/article/typescript/recursion.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -106,8 +106,8 @@ : DeepReadonly<Obj[Key]> : Obj[Key]; } - : never; - + : never; + \ No newline at end of file diff --git a/cn/src/article/typescript/unionType.html b/cn/src/article/typescript/unionType.html index 38c7c44c95..ba52e410cb 100644 --- a/cn/src/article/typescript/unionType.html +++ b/cn/src/article/typescript/unionType.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -62,8 +62,8 @@ > = `${Block}__${Element[number]}--${Modifiers[number]}`;

类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

ts
type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;
 // type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

可以看到,用好了联合类型,确实能简化类型编程逻辑。

AllCombinations

我们再来实现一个全组合的高级类型,也是联合类型相关的:

希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

任何两个类型的组合有四种:A、B、AB、BA

ts
type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

然后构造出来的字符串再和其他字符串组合。

所以全组合的高级类型就是这样:

ts
type AllCombinations<A extends string, B extends string = A> = A extends A
   ? Combination<A, AllCombinations<Exclude<B, A>>>
-  : never;

类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

总结

联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

有两点特别要注意:

我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

- + : never;

类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

总结

联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

有两点特别要注意:

我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

+ \ No newline at end of file diff --git a/cn/src/article/video.html b/cn/src/article/video.html index 4206da31bd..8e1c6e94de 100644 --- a/cn/src/article/video.html +++ b/cn/src/article/video.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -326,8 +326,8 @@ display: none; }

由于播放器本身就是一个元素,那么可以任意的在里面添加元素,添加逻辑。

jsx
<r-player onChange={change} src="hls/example.m3u8">
   <div>111111</div>
-</r-player>

所以,这就解决配置项,长达好几页的问题,同时看到也就知道怎么配置,怎么开发了。

八:总结

目前已经从前后端的角度,实现了

  1. 视频的标准加密
  2. 视频的动态码率播放
  3. 视频的分片加载
  4. 可拖拽进度条
  5. 音量控制
  6. 手动清晰度切换
  7. 倍速播放
  8. 样式自定义覆盖
  9. 基于原生开发,可在所有框架运行,统一跨框架情况,各浏览器控件统一

这是demo和源码地址:

demo和文档地址:https://chaxus.github.io/ran/src/ranui/player/

源码地址:https://github.com/chaxus/ran

demo文档做了国际化,可切换到中文

- +</r-player>

所以,这就解决配置项,长达好几页的问题,同时看到也就知道怎么配置,怎么开发了。

八:总结

目前已经从前后端的角度,实现了

  1. 视频的标准加密
  2. 视频的动态码率播放
  3. 视频的分片加载
  4. 可拖拽进度条
  5. 音量控制
  6. 手动清晰度切换
  7. 倍速播放
  8. 样式自定义覆盖
  9. 基于原生开发,可在所有框架运行,统一跨框架情况,各浏览器控件统一

这是demo和源码地址:

demo和文档地址:https://chaxus.github.io/ran/src/ranui/player/

源码地址:https://github.com/chaxus/ran

demo文档做了国际化,可切换到中文

+ \ No newline at end of file diff --git a/cn/src/article/visual.html b/cn/src/article/visual.html index 7cb7ae5c02..6b8905d5e4 100644 --- a/cn/src/article/visual.html +++ b/cn/src/article/visual.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -184,8 +184,8 @@ if (lineStyle.visible) { ctx.globalAlpha = lineStyle.alpha * this.worldAlpha; ctx.stroke(); -}

三 层级管理

在 canvas 绘图环境中,先绘制的图形会被后绘制的图形所覆盖,因此,层级的管理就自然地通过绘制顺序来实现。在这种情况下,最先被绘制的图形将位于最底层,而随后绘制的图形则逐层叠加,直至最上层。

我们已经实现了各种基础图形的绘制,接下来继续分离绘制时的数据和绘制操作。

我们需要一个容器类,在容器类中统一绘制所有的图形。

用一个 children 属性来添加所有的图形,在 render 方法中统一绘制。

同时,我们会根据 zIndex 属性来排序子元素,zIndex 越大的元素会被排在 children 数组的越后面,但是注意,排序的时候,要保证相同 zIndex 的相对顺序不变。

四 图形组的管理

我们会实现一个节点类 Vertex 这个类代表了最原始的‘节点’的概念,所有可以被展示到 canvas 画布上的、各种类型的节点都会继承于这个类,这是一个抽象类,我们并不会直接实例化这个类。

这个类上面挂载了‘节点’的各种属性,比如:父元素、透明度、旋转角度、缩放、平移、节点是否可见等。

为了进行图形组的管理,会继续实现一个容器类 Container,这个类代表了‘组’的概念,它提供了添加子元素,移除子元素等的方法;后续的要被渲染的一些类 (如 Graphics,Text,Sprite 等) 会继承于这个类;这个类本身不会被渲染 (因为它只是一个‘组’,它本身没有内容可以渲染)。

这个类继承于 Vertex 类,‘组’也算作‘节点’。

Graphics 这个类会用来构建一些几何图形元素;它会继承 Container 类。

在渲染引擎中,一切变换 (平移、旋转、缩放等) 都会转化成变换矩阵 (matrix),因为 canvas 只接受矩阵变换,虽然 canvas 为了开发的便捷,也提供了 ctx.rotate,ctx.scale 等操作,但是 canvas 中的这些操作会直接转换成变换矩阵,而不像 DOM 那样,有锚点的概念,所以 canvas 提供的 rotate,scale 等操作,和 DOM 提供的 rotate,scale 的表现是不一样的。

Matrix 类将会提供各种各样的与矩阵操作相关的函数 (矩阵相乘,矩阵求逆等),任何变换的叠加都将会转换成 matrix,方便我们调用 canvas 的指令。

Transform 类就类似 CSS 的 transform,它提供了一些更清晰、更符合人类直觉的变换,而不用直接使用矩阵变换,当然,这些变换最终会转换成矩阵变换。

参考资料:

  1. 如何通俗地讲解「仿射变换」?
  2. 仿射变换及其变换矩阵的理解
  3. 深入理解贝塞尔曲线
  4. 如何理解并应用贝塞尔曲线
- +}

三 层级管理

在 canvas 绘图环境中,先绘制的图形会被后绘制的图形所覆盖,因此,层级的管理就自然地通过绘制顺序来实现。在这种情况下,最先被绘制的图形将位于最底层,而随后绘制的图形则逐层叠加,直至最上层。

我们已经实现了各种基础图形的绘制,接下来继续分离绘制时的数据和绘制操作。

我们需要一个容器类,在容器类中统一绘制所有的图形。

用一个 children 属性来添加所有的图形,在 render 方法中统一绘制。

同时,我们会根据 zIndex 属性来排序子元素,zIndex 越大的元素会被排在 children 数组的越后面,但是注意,排序的时候,要保证相同 zIndex 的相对顺序不变。

四 图形组的管理

我们会实现一个节点类 Vertex 这个类代表了最原始的‘节点’的概念,所有可以被展示到 canvas 画布上的、各种类型的节点都会继承于这个类,这是一个抽象类,我们并不会直接实例化这个类。

这个类上面挂载了‘节点’的各种属性,比如:父元素、透明度、旋转角度、缩放、平移、节点是否可见等。

为了进行图形组的管理,会继续实现一个容器类 Container,这个类代表了‘组’的概念,它提供了添加子元素,移除子元素等的方法;后续的要被渲染的一些类 (如 Graphics,Text,Sprite 等) 会继承于这个类;这个类本身不会被渲染 (因为它只是一个‘组’,它本身没有内容可以渲染)。

这个类继承于 Vertex 类,‘组’也算作‘节点’。

Graphics 这个类会用来构建一些几何图形元素;它会继承 Container 类。

在渲染引擎中,一切变换 (平移、旋转、缩放等) 都会转化成变换矩阵 (matrix),因为 canvas 只接受矩阵变换,虽然 canvas 为了开发的便捷,也提供了 ctx.rotate,ctx.scale 等操作,但是 canvas 中的这些操作会直接转换成变换矩阵,而不像 DOM 那样,有锚点的概念,所以 canvas 提供的 rotate,scale 等操作,和 DOM 提供的 rotate,scale 的表现是不一样的。

Matrix 类将会提供各种各样的与矩阵操作相关的函数 (矩阵相乘,矩阵求逆等),任何变换的叠加都将会转换成 matrix,方便我们调用 canvas 的指令。

Transform 类就类似 CSS 的 transform,它提供了一些更清晰、更符合人类直觉的变换,而不用直接使用矩阵变换,当然,这些变换最终会转换成矩阵变换。

参考资料:

  1. 如何通俗地讲解「仿射变换」?
  2. 仿射变换及其变换矩阵的理解
  3. 深入理解贝塞尔曲线
  4. 如何理解并应用贝塞尔曲线
+ \ No newline at end of file diff --git a/cn/src/note/centos.html b/cn/src/note/centos.html index d392e2d361..f443364ea3 100644 --- a/cn/src/note/centos.html +++ b/cn/src/note/centos.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -63,8 +63,8 @@ baseurl=http://vault.centos.org/8.5.2111/extras/$basearch/os/ gpgcheck=1 enabled=1 -gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

更新缓存并重试

  1. 清理缓存:yum clean all
  2. 生成新的缓存:yum makecache
  3. 更新系统:yum update
- +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial

更新缓存并重试

  1. 清理缓存:yum clean all
  2. 生成新的缓存:yum makecache
  3. 更新系统:yum update
+ \ No newline at end of file diff --git a/cn/src/note/docker.html b/cn/src/note/docker.html index bbd5fbfd07..fb3217f7ea 100644 --- a/cn/src/note/docker.html +++ b/cn/src/note/docker.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -108,8 +108,8 @@ EXPOSR 3000 # 表示容器启动后自动执行 CMD node demos/01.js
shell
$ docker container run --rm - p 8000:3000 -it koa-demo:0.0.1

问题:

  1. 如果遇到 docker desktop 登录不上,可以尝试 docker login进行登录,命令行登录会输出错误的信息,如果发现是网络问题,换一个代理即可。
  2. Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
shell
# docker服务没有启动
-$ service docker start

参考资料

- +$ service docker start

参考资料

+ \ No newline at end of file diff --git a/cn/src/note/libreoffice2wasm.html b/cn/src/note/libreoffice2wasm.html index 6a1a8734b1..10b140864a 100644 --- a/cn/src/note/libreoffice2wasm.html +++ b/cn/src/note/libreoffice2wasm.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -110,8 +110,8 @@ --disable-odk --disable-pch --disable-skia ---disable-scripting

通过这些步骤,你应该能够显著减小生成的 WebAssembly 文件的体积,同时保留将文件转换为 PDF 的功能。如果遇到具体问题,请提供详细的错误信息,以便更好地帮助你解决问题。

wasm-opt 是 Binaryen 项目的一部分,它是一个用于优化和处理 WebAssembly 二进制文件的工具。你可以在 Ubuntu 上通过以下步骤安装和使用 wasm-opt:

  1. 安装依赖项 首先,确保你的系统上已经安装了必要的依赖项:

sudo apt update sudo apt install cmake build-essential git 2. 下载和编译 Binaryen 接下来,从源码编译 Binaryen:

克隆 Binaryen 仓库

git clone https://github.com/WebAssembly/binaryen.git cd binaryen

创建并进入构建目录

mkdir build cd build

使用 CMake 配置构建

cmake ..

编译 Binaryen

make

安装 Binaryen

sudo make install 3. 使用 wasm-opt 安装完成后,你可以使用 wasm-opt 命令来优化 WebAssembly 文件。例如:

假设你有一个名为 original.wasm 的 WebAssembly 文件

wasm-opt -Oz -o optimized.wasm original.wasm 在这个命令中:

-Oz 表示进行最大化的尺寸优化。 -o optimized.wasm 指定输出文件名为 optimized.wasm。 original.wasm 是输入的 WebAssembly 文件。4. 验证安装 你可以通过运行以下命令来验证 wasm-opt 是否正确安装:

wasm-opt --version 这将输出 wasm-opt 的版本信息,确认它已成功安装并可以使用。

示例 假设你有一个名为 example.wasm 的 WebAssembly 文件,你可以通过以下命令优化它:

wasm-opt -Oz -o example_optimized.wasm example.wasm 这将生成一个优化后的 WebAssembly 文件 example_optimized.wasm,其体积通常会显著减小。

通过这些步骤,你应该能够在 Ubuntu 上成功安装和使用 wasm-opt 来优化你的 WebAssembly 文件。如果在安装或使用过程中遇到任何问题,请提供详细的错误信息,以便进一步帮助你解决问题。

--disable-debug --enable-sal-log --disable-crashdump --host=wasm32-local-emscripten --disable-gui --with-main-module=writer --with-package-format=emscripten --disable-dbus --disable-odk --disable-postgresql-sdbc --disable-firebird-sdbc --disable-coinmp --disable-cve-tests --disable-gtk3 --disable-gstreamer-1-0 --disable-kf5 --disable-scripting-beanshell --disable-scripting-javascript --disable-extensions --disable-epm --disable-online-update --disable-python --disable-pdfimport --disable-lpsolve --disable-sdremote --disable-scripting --disable-avmedia --disable-coinmp --disable-report-builder --disable-odk --disable-pch --disable-skia --disable-scripting

步骤 1:下载最新的 OpenSSL 源代码 首先,确保你在一个干净的目录中,然后下载最新版本的 OpenSSL 源代码。你可以访问 OpenSSL 官方网站 查看最新版本。假设最新版本是 openssl-3.0.9:

wget https://www.openssl.org/source/openssl-3.0.9.tar.gz tar -xzvf openssl-3.0.9.tar.gz cd openssl-3.0.9 步骤 2:编译和安装 OpenSSL 接下来,编译并安装 OpenSSL:

./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl shared zlib make make test make install 步骤 3:确认 OpenSSL 安装路径 确保 OpenSSL 的头文件和库文件已正确安装:

ls /usr/local/ssl/include ls /usr/local/ssl/lib 步骤 4:设置环境变量 设置正确的环境变量,以便编译时能找到 OpenSSL:

export PKG_CONFIG_PATH="/usr/local/ssl/lib/pkgconfig" export CFLAGS="-I/usr/local/ssl/include" export LDFLAGS="-L/usr/local/ssl/lib -lssl -lcrypto" 步骤 5:清理之前的配置 在重新运行 configure 脚本之前,清理之前的配置:

make clean 步骤 6:重新运行 configure 脚本 重新运行 configure 脚本,以确保它能找到新的 OpenSSL 版本:

emconfigure ./configure --disable-debug --enable-sal-log --disable-crashdump --host=wasm32-local-emscripten --disable-gui --with-main-module=writer --with-package-format=emscripten --disable-dbus --disable-odk --disable-postgresql-sdbc --disable-firebird-sdbc --disable-coinmp --disable-cve-tests --disable-gtk3 --disable-gstreamer-1-0 --disable-kf5 --disable-scripting-beanshell --disable-scripting-javascript --disable-extensions --disable-epm --disable-online-update --disable-python --disable-pdfimport --disable-lpsolve --disable-sdremote --disable-scripting --disable-avmedia --disable-coinmp --disable-report-builder --disable-odk --disable-pch --disable-skia --disable-scripting --srcdir=/home/core --enable-option-checking=fatal --disable-pthreads 步骤 7:检查 config.log 如果配置仍然失败,请检查 config.log 文件以获取更多详细信息:

cat config.log | grep openssl 通过确保 OpenSSL 已正确安装并设置正确的环境变量,我们应该能够解决配置过程中遇到的问题。如果问题仍然存在,请提供 config.log 文件中与 OpenSSL 相关的更多详细信息,以便进一步诊断和解决问题。

emconfigure ./configure --disable-debug --enable-sal-log --disable-crashdump --host=wasm32-local-emscripten --disable-gui --with-main-module=writer --with-package-format=emscripten --disable-dbus --disable-odk --disable-postgresql-sdbc --disable-firebird-sdbc --disable-coinmp --disable-cve-tests --disable-gtk3 --disable-gstreamer-1-0 --disable-kf5 --disable-scripting-beanshell --disable-scripting-javascript --disable-extensions --disable-epm --disable-online-update --disable-python --disable-pdfimport --disable-lpsolve --disable-sdremote --disable-scripting --disable-avmedia --disable-coinmp --disable-report-builder --disable-odk --disable-pch --disable-skia --disable-scripting --srcdir=/home/core --enable-option-checking=fatal

emmake make CXXFLAGS="-I/usr/local/ssl/include -O3 -g0 -msimd128" LDFLAGS="-L/usr/local/ssl/lib -lssl -lcrypto -O3 -g0"

emconfigure ./configure --disable-cups --disable-dbus --without-system-fontconfig --with-system-zlib --disable-dynamic-loading --disable-gui CXXFLAGS=-std=c++20 --host=wasm32-unknown-emscripten

root@8cb3480a4441:/home/core/instsetoo_native# vim CustomTarget_emscripten-install.mk

使用 file_packager.py 工具将文件预加载到虚拟文件系统中。确保 Emscripten 的环境变量已经正确设置,然后运行以下命令:

python3 /home/emsdk/upstream/emscripten/tools/file_packager.py preload.data --preload /home/core/instdir/share@/instdir/share --js-output=preload.js

- +--disable-scripting

通过这些步骤,你应该能够显著减小生成的 WebAssembly 文件的体积,同时保留将文件转换为 PDF 的功能。如果遇到具体问题,请提供详细的错误信息,以便更好地帮助你解决问题。

wasm-opt 是 Binaryen 项目的一部分,它是一个用于优化和处理 WebAssembly 二进制文件的工具。你可以在 Ubuntu 上通过以下步骤安装和使用 wasm-opt:

  1. 安装依赖项 首先,确保你的系统上已经安装了必要的依赖项:

sudo apt update sudo apt install cmake build-essential git 2. 下载和编译 Binaryen 接下来,从源码编译 Binaryen:

克隆 Binaryen 仓库

git clone https://github.com/WebAssembly/binaryen.git cd binaryen

创建并进入构建目录

mkdir build cd build

使用 CMake 配置构建

cmake ..

编译 Binaryen

make

安装 Binaryen

sudo make install 3. 使用 wasm-opt 安装完成后,你可以使用 wasm-opt 命令来优化 WebAssembly 文件。例如:

假设你有一个名为 original.wasm 的 WebAssembly 文件

wasm-opt -Oz -o optimized.wasm original.wasm 在这个命令中:

-Oz 表示进行最大化的尺寸优化。 -o optimized.wasm 指定输出文件名为 optimized.wasm。 original.wasm 是输入的 WebAssembly 文件。4. 验证安装 你可以通过运行以下命令来验证 wasm-opt 是否正确安装:

wasm-opt --version 这将输出 wasm-opt 的版本信息,确认它已成功安装并可以使用。

示例 假设你有一个名为 example.wasm 的 WebAssembly 文件,你可以通过以下命令优化它:

wasm-opt -Oz -o example_optimized.wasm example.wasm 这将生成一个优化后的 WebAssembly 文件 example_optimized.wasm,其体积通常会显著减小。

通过这些步骤,你应该能够在 Ubuntu 上成功安装和使用 wasm-opt 来优化你的 WebAssembly 文件。如果在安装或使用过程中遇到任何问题,请提供详细的错误信息,以便进一步帮助你解决问题。

--disable-debug --enable-sal-log --disable-crashdump --host=wasm32-local-emscripten --disable-gui --with-main-module=writer --with-package-format=emscripten --disable-dbus --disable-odk --disable-postgresql-sdbc --disable-firebird-sdbc --disable-coinmp --disable-cve-tests --disable-gtk3 --disable-gstreamer-1-0 --disable-kf5 --disable-scripting-beanshell --disable-scripting-javascript --disable-extensions --disable-epm --disable-online-update --disable-python --disable-pdfimport --disable-lpsolve --disable-sdremote --disable-scripting --disable-avmedia --disable-coinmp --disable-report-builder --disable-odk --disable-pch --disable-skia --disable-scripting

步骤 1:下载最新的 OpenSSL 源代码 首先,确保你在一个干净的目录中,然后下载最新版本的 OpenSSL 源代码。你可以访问 OpenSSL 官方网站 查看最新版本。假设最新版本是 openssl-3.0.9:

wget https://www.openssl.org/source/openssl-3.0.9.tar.gz tar -xzvf openssl-3.0.9.tar.gz cd openssl-3.0.9 步骤 2:编译和安装 OpenSSL 接下来,编译并安装 OpenSSL:

./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl shared zlib make make test make install 步骤 3:确认 OpenSSL 安装路径 确保 OpenSSL 的头文件和库文件已正确安装:

ls /usr/local/ssl/include ls /usr/local/ssl/lib 步骤 4:设置环境变量 设置正确的环境变量,以便编译时能找到 OpenSSL:

export PKG_CONFIG_PATH="/usr/local/ssl/lib/pkgconfig" export CFLAGS="-I/usr/local/ssl/include" export LDFLAGS="-L/usr/local/ssl/lib -lssl -lcrypto" 步骤 5:清理之前的配置 在重新运行 configure 脚本之前,清理之前的配置:

make clean 步骤 6:重新运行 configure 脚本 重新运行 configure 脚本,以确保它能找到新的 OpenSSL 版本:

emconfigure ./configure --disable-debug --enable-sal-log --disable-crashdump --host=wasm32-local-emscripten --disable-gui --with-main-module=writer --with-package-format=emscripten --disable-dbus --disable-odk --disable-postgresql-sdbc --disable-firebird-sdbc --disable-coinmp --disable-cve-tests --disable-gtk3 --disable-gstreamer-1-0 --disable-kf5 --disable-scripting-beanshell --disable-scripting-javascript --disable-extensions --disable-epm --disable-online-update --disable-python --disable-pdfimport --disable-lpsolve --disable-sdremote --disable-scripting --disable-avmedia --disable-coinmp --disable-report-builder --disable-odk --disable-pch --disable-skia --disable-scripting --srcdir=/home/core --enable-option-checking=fatal --disable-pthreads 步骤 7:检查 config.log 如果配置仍然失败,请检查 config.log 文件以获取更多详细信息:

cat config.log | grep openssl 通过确保 OpenSSL 已正确安装并设置正确的环境变量,我们应该能够解决配置过程中遇到的问题。如果问题仍然存在,请提供 config.log 文件中与 OpenSSL 相关的更多详细信息,以便进一步诊断和解决问题。

emconfigure ./configure --disable-debug --enable-sal-log --disable-crashdump --host=wasm32-local-emscripten --disable-gui --with-main-module=writer --with-package-format=emscripten --disable-dbus --disable-odk --disable-postgresql-sdbc --disable-firebird-sdbc --disable-coinmp --disable-cve-tests --disable-gtk3 --disable-gstreamer-1-0 --disable-kf5 --disable-scripting-beanshell --disable-scripting-javascript --disable-extensions --disable-epm --disable-online-update --disable-python --disable-pdfimport --disable-lpsolve --disable-sdremote --disable-scripting --disable-avmedia --disable-coinmp --disable-report-builder --disable-odk --disable-pch --disable-skia --disable-scripting --srcdir=/home/core --enable-option-checking=fatal

emmake make CXXFLAGS="-I/usr/local/ssl/include -O3 -g0 -msimd128" LDFLAGS="-L/usr/local/ssl/lib -lssl -lcrypto -O3 -g0"

emconfigure ./configure --disable-cups --disable-dbus --without-system-fontconfig --with-system-zlib --disable-dynamic-loading --disable-gui CXXFLAGS=-std=c++20 --host=wasm32-unknown-emscripten

root@8cb3480a4441:/home/core/instsetoo_native# vim CustomTarget_emscripten-install.mk

使用 file_packager.py 工具将文件预加载到虚拟文件系统中。确保 Emscripten 的环境变量已经正确设置,然后运行以下命令:

python3 /home/emsdk/upstream/emscripten/tools/file_packager.py preload.data --preload /home/core/instdir/share@/instdir/share --js-output=preload.js

+ \ No newline at end of file diff --git a/cn/src/note/ubuntu.html b/cn/src/note/ubuntu.html index 267e4b2cb1..8a70c4822b 100644 --- a/cn/src/note/ubuntu.html +++ b/cn/src/note/ubuntu.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -44,8 +44,8 @@
Skip to content

ubuntu

sh
apt update
 
-apt install openjdk-11-jdk  wget curl junit4 ant libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev libgtk-3-dev libglib2.0-dev libatk1.0-dev libcairo2-dev zip flex uuid-runtime bison libxrandr-dev libxrender-dev libxext-dev libnss3-dev libnspr4-dev libkrb5-dev python3 python3-pip libxml2-utils xsltproc libxslt1-dev gperf libfontconfig1-dev libcups2-dev gcc make autoconf pkg-config automake

Last updated:

Released under the MIT License.

- +apt install openjdk-11-jdk wget curl junit4 ant libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgstreamer-plugins-good1.0-dev libgtk-3-dev libglib2.0-dev libatk1.0-dev libcairo2-dev zip flex uuid-runtime bison libxrandr-dev libxrender-dev libxext-dev libnss3-dev libnspr4-dev libkrb5-dev python3 python3-pip libxml2-utils xsltproc libxslt1-dev gperf libfontconfig1-dev libcups2-dev gcc make autoconf pkg-config automake + \ No newline at end of file diff --git a/cn/src/ranui/button/index.html b/cn/src/ranui/button/index.html index 6f6d5810ac..ef66fd1fc0 100644 --- a/cn/src/ranui/button/index.html +++ b/cn/src/ranui/button/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -50,8 +50,8 @@ <r-button type="text" disabled>文本按钮</r-button> <r-button disabled>默认按钮</r-button>

图标icon

当需要在 Button 内嵌入 Icon 时,可以设置 icon 属性,或者直接在 Button 内使用 Icon 组件。

如果想控制 Icon 具体的位置,只能直接使用 Icon 组件,而非 icon 属性。

默认按钮
主要按钮
xml
<r-button type="default" icon="user">默认按钮</r-button>
 <r-button type="primary" icon="home">主要按钮</r-button>

特效 effect

如果需要纯净的 Button,可以加上 effect = false,屏蔽点击时候的水波纹特效

默认按钮主要按钮
xml
<r-button type="default" icon="user">默认按钮</r-button>
-<r-button type="primary" icon="home">主要按钮</r-button>
- +<r-button type="primary" icon="home">主要按钮</r-button> + \ No newline at end of file diff --git a/cn/src/ranui/checkbox/index.html b/cn/src/ranui/checkbox/index.html index c487a98508..9fd592f247 100644 --- a/cn/src/ranui/checkbox/index.html +++ b/cn/src/ranui/checkbox/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -45,8 +45,8 @@
Skip to content

CheckBox 多选框

代码演示

xml
 <r-checkbox ></r-checkbox>

属性

checked

xml
 <r-checkbox checked="true"></r-checkbox>
  <r-checkbox checked="false"></r-checkbox>

disabled

xml
 <r-checkbox checked="true" disabled></r-checkbox>
  <r-checkbox checked="false" disabled></r-checkbox>

事件event

改变的时候触发。

onchange

xml
 <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
- <r-checkbox onchange="console.log(this.checked)"></r-checkbox>

Released under the MIT License.

- + <r-checkbox onchange="console.log(this.checked)"></r-checkbox> + \ No newline at end of file diff --git a/cn/src/ranui/icon/index.html b/cn/src/ranui/icon/index.html index ad86145fb9..e9b40b6fb7 100644 --- a/cn/src/ranui/icon/index.html +++ b/cn/src/ranui/icon/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -53,8 +53,8 @@ <r-icon name="lock" size="50" color="#F44336"></r-icon> <r-icon name="lock" size="50" color="#3F51B5"></r-icon>

旋转spin

设置 spin 开启旋转,传入数字控制旋转的速度,数字越小旋转越快

html
<r-icon name="loading" size="50" color="#1E90FF" spin="0.7"></r-icon>
 <r-icon name="loading" size="50" color="#1E90FF" spin></r-icon>
-<r-icon name="loading" size="50" color="#1E90FF" spin="5"></r-icon>

图标列表

- +<r-icon name="loading" size="50" color="#1E90FF" spin="5"></r-icon>

图标列表

+ \ No newline at end of file diff --git a/cn/src/ranui/image/index.html b/cn/src/ranui/image/index.html index f0bc8480c2..a5b0374f21 100644 --- a/cn/src/ranui/image/index.html +++ b/cn/src/ranui/image/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

Image 图片

代码演示

xml
 <r-img src="" fallback=""></r-img>

属性

图片加载地址src

图片的地址

图片加载失败fallback

src配置的图片加载失败,兜底的图片地址,下面是默认加载失败图片

Released under the MIT License.

- +
Skip to content

Image 图片

代码演示

xml
 <r-img src="" fallback=""></r-img>

属性

图片加载地址src

图片的地址

图片加载失败fallback

src配置的图片加载失败,兜底的图片地址,下面是默认加载失败图片

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranui/index.html b/cn/src/ranui/index.html index f96674188f..77a23cae94 100644 --- a/cn/src/ranui/index.html +++ b/cn/src/ranui/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -128,8 +128,8 @@ percent="0.70" type="drag" style="--ran-progress-wrap-background:linear-gradient(to right, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);" -></r-progress>

具体css3变量名称可以参考每个组件的介绍和说明

Compatibility 兼容性

Contributors 贡献者

Other 相关资源

  1. 优秀的组件设计
  2. 在线生成 CSS 渐变色
  3. 优秀设计作品,有 psd 和 sketch
  4. 3D UI 设计,类似于 3D 版的 figma
  5. 设计规范
  6. 优秀设计作品
  7. element UI 中文网
  8. Ant design 中文网
  9. 在线绘制 CSS 动画
  10. tailwindcss 组件库
  11. animate css 非常优秀的 css 动画
  12. can i use 检测兼容性 API 网站
  13. figma

协议和标准

  1. RFCs
  2. ECMA
  3. w3c
- +></r-progress>

具体css3变量名称可以参考每个组件的介绍和说明

Compatibility 兼容性

Contributors 贡献者

Other 相关资源

  1. 优秀的组件设计
  2. 在线生成 CSS 渐变色
  3. 优秀设计作品,有 psd 和 sketch
  4. 3D UI 设计,类似于 3D 版的 figma
  5. 设计规范
  6. 优秀设计作品
  7. element UI 中文网
  8. Ant design 中文网
  9. 在线绘制 CSS 动画
  10. tailwindcss 组件库
  11. animate css 非常优秀的 css 动画
  12. can i use 检测兼容性 API 网站
  13. figma

协议和标准

  1. RFCs
  2. ECMA
  3. w3c
+ \ No newline at end of file diff --git a/cn/src/ranui/input/index.html b/cn/src/ranui/input/index.html index 8d1321a5a3..de2ce79763 100644 --- a/cn/src/ranui/input/index.html +++ b/cn/src/ranui/input/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -53,8 +53,8 @@ const func = (e) => { console.log(e); }; -input.addEventListener('input', func);

事件的e参数结构 input方法

- +input.addEventListener('input', func);

事件的e参数结构 input方法

+ \ No newline at end of file diff --git a/cn/src/ranui/loading/index.html b/cn/src/ranui/loading/index.html index 907b7dc38b..56e39c9767 100644 --- a/cn/src/ranui/loading/index.html +++ b/cn/src/ranui/loading/index.html @@ -14,7 +14,7 @@ - + @@ -38,7 +38,7 @@ - + @@ -47,8 +47,8 @@
Skip to content

Loading

一些好看的 loading

Code demo

xml
<r-loading name="circle"></r-loading>

属性

name

这里有很多好看的 loading,可供选择

xml
<r-loading name="double-bounce"></r-loading>
 <r-loading name="rotate"></r-loading>
 <r-loading name="stretch"></r-loading>
-<r-loading name="cube"></r-loading>

Loading list

Move the mouse over the icon to see the loading animation

stretch
rotate
double-bounce
cube
dot
triple-bounce
scale-out
circle
circle-line
square
pulse
solar
cube-fold
circle-fold
cube-grid
circle-turn
circle-rotate
circle-spin
dot-bar
dot-circle
line
dot-pulse
line-scale
text
cube-dim
dot-line
arc
drop
pacman

Released under the MIT License.

- +<r-loading name="cube"></r-loading>

Loading list

Move the mouse over the icon to see the loading animation

stretch
rotate
double-bounce
cube
dot
triple-bounce
scale-out
circle
circle-line
square
pulse
solar
cube-fold
circle-fold
cube-grid
circle-turn
circle-rotate
circle-spin
dot-bar
dot-circle
line
dot-pulse
line-scale
text
cube-dim
dot-line
arc
drop
pacman
+ \ No newline at end of file diff --git a/cn/src/ranui/math/index.html b/cn/src/ranui/math/index.html index 82d0bb1f9b..8783c73309 100644 --- a/cn/src/ranui/math/index.html +++ b/cn/src/ranui/math/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

math 数学公式

HTML 页面中高质量展示 LaTeX 数学公式

代码演示

xml
<r-math latex="\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1 \quad (a > b > 0)"></r-math>

属性

latex string

xml
  <r-math latex="x = {-b \pm \sqrt{b^2-4ac} \over 2a}"></r-math>

Released under the MIT License.

- +
Skip to content

math 数学公式

HTML 页面中高质量展示 LaTeX 数学公式

代码演示

xml
<r-math latex="\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1 \quad (a > b > 0)"></r-math>

属性

latex string

xml
  <r-math latex="x = {-b \pm \sqrt{b^2-4ac} \over 2a}"></r-math>

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranui/message/index.html b/cn/src/ranui/message/index.html index adbedd6fc0..8502971c1e 100644 --- a/cn/src/ranui/message/index.html +++ b/cn/src/ranui/message/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -46,8 +46,8 @@ <r-button onclick="message.warning('这是一条提示')">警告提示</r-button> <r-button onclick="message.error('这是一条提示')">错误提示</r-button> <r-button onclick="message.success('这是一条提示')">成功提示</r-button> -<r-button onclick="message.toast('这是一条提示')">toast提示</r-button>

方法

组件提供了一些静态方法,使用方式和参数如下:

  1. 可以只传一个参数,提示的内容,默认提示 3000 毫秒

message.info('这是一条提示')

message.warning('这是一条提示')

message.error('这是一条提示')

message.success('这是一条提示')

message.toast('这是一条提示')"

  1. 也可以传一个对象,设置提示内容,关闭延时,关闭时触发的回调函数

message.info({content:'这是一条提示', duration: 2000, close: () => {}})

message.warning({content:'这是一条提示', duration: 2000, close: () => {}})

message.error({content:'这是一条提示', duration: 2000, close: () => {}})

message.success({content:'这是一条提示', duration: 2000, close: () => {}})

message.toast({content:'这是一条提示', duration: 2000, close: () => {}})

参数说明类型
content提示内容string
duration自动关闭的延时,单位毫秒。默认 3000 毫秒number
close关闭时触发的回调函数() => void
- +<r-button onclick="message.toast('这是一条提示')">toast提示</r-button>

方法

组件提供了一些静态方法,使用方式和参数如下:

  1. 可以只传一个参数,提示的内容,默认提示 3000 毫秒

message.info('这是一条提示')

message.warning('这是一条提示')

message.error('这是一条提示')

message.success('这是一条提示')

message.toast('这是一条提示')"

  1. 也可以传一个对象,设置提示内容,关闭延时,关闭时触发的回调函数

message.info({content:'这是一条提示', duration: 2000, close: () => {}})

message.warning({content:'这是一条提示', duration: 2000, close: () => {}})

message.error({content:'这是一条提示', duration: 2000, close: () => {}})

message.success({content:'这是一条提示', duration: 2000, close: () => {}})

message.toast({content:'这是一条提示', duration: 2000, close: () => {}})

参数说明类型
content提示内容string
duration自动关闭的延时,单位毫秒。默认 3000 毫秒number
close关闭时触发的回调函数() => void
+ \ No newline at end of file diff --git a/cn/src/ranui/modal/index.html b/cn/src/ranui/modal/index.html index e15dba612c..ba01821875 100644 --- a/cn/src/ranui/modal/index.html +++ b/cn/src/ranui/modal/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

Released under the MIT License.

- +
Skip to content

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranui/player/index.html b/cn/src/ranui/player/index.html index 64995b0e9d..de012c5b50 100644 --- a/cn/src/ranui/player/index.html +++ b/cn/src/ranui/player/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

r-player 视频播放器

基于hlsjsweb components,让原生的标签r-player拥有统一的视频控件。 不采用new Player(options)的方式挂载到指定dom,视图的归视图,逻辑的归逻辑,所见及所得,更加直观。

  1. 可拖拽进度条
  2. 音量控制
  3. 根据当前带宽自适应码率切换
  4. 手动清晰度切换
  5. 倍速播放
  6. 样式自定义覆盖
  7. hls协议标准加密视频播放
  8. 基于原生开发,可在所有框架运行,统一跨框架情况
  9. 各浏览器控件统一

代码演示

xml
  <r-player src="/ran/hls/example.m3u8"></r-player>

属性

src

视频的资源地址

volume

设置初始音量,默认 0.5

currentTime

设置初始播放时间,默认从头开始播放

playbackRate

设置倍速,默认 1.0

debug

控制台会打印输出一些信息

事件event

onchange

监听任何播放器发生的变化,返回的值如下。

可通过这个方法获得播放器的实例

活着通过type判断不同的事件类型,进行不同的操作

属性说明类型
type发生变化的事件类型string
data事件的值Object
currentTime播放的当前时间number
duration视频的总时长number
tag播放器的实例Element

其中type类型有

名称说明
canplay浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容。
canplaythrough浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束。
completeOfflineAudioContext 渲染完成。
durationchangeduration 属性的值改变时触发。
emptied媒体内容变为空;例如,当这个 media 已经加载完成(或者部分加载完成),则发送此事件,并调用 load() 方法重新加载它。
ended视频停止播放,因为 media 已经到达结束点。
loadedmetadata已加载元数据。
progress在浏览器加载资源时周期性触发。
ratechange播放速率发生变化。
seeked跳帧(seek)操作完成。
seeking跳帧(seek)操作开始。
stalled用户代理(user agent)正在尝试获取媒体数据,但数据意外未出现。
suspend媒体数据加载已暂停。
loadeddatamedia 中的首帧已经完成加载。
timeupdatecurrentTime 属性指定的时间发生变化。
volumechange音量发生变化。
waiting由于暂时缺少数据,播放已停止。
play播放已开始。
playing由于缺乏数据而暂停或延迟后,播放准备开始。
pause播放已暂停。
volume音量发生变化。
fullscreen触发全屏事件

Released under the MIT License.

- +
Skip to content

r-player 视频播放器

基于hlsjsweb components,让原生的标签r-player拥有统一的视频控件。 不采用new Player(options)的方式挂载到指定dom,视图的归视图,逻辑的归逻辑,所见及所得,更加直观。

  1. 可拖拽进度条
  2. 音量控制
  3. 根据当前带宽自适应码率切换
  4. 手动清晰度切换
  5. 倍速播放
  6. 样式自定义覆盖
  7. hls协议标准加密视频播放
  8. 基于原生开发,可在所有框架运行,统一跨框架情况
  9. 各浏览器控件统一

代码演示

xml
  <r-player src="/ran/hls/example.m3u8"></r-player>

属性

src

视频的资源地址

volume

设置初始音量,默认 0.5

currentTime

设置初始播放时间,默认从头开始播放

playbackRate

设置倍速,默认 1.0

debug

控制台会打印输出一些信息

事件event

onchange

监听任何播放器发生的变化,返回的值如下。

可通过这个方法获得播放器的实例

活着通过type判断不同的事件类型,进行不同的操作

属性说明类型
type发生变化的事件类型string
data事件的值Object
currentTime播放的当前时间number
duration视频的总时长number
tag播放器的实例Element

其中type类型有

名称说明
canplay浏览器可以播放媒体文件了,但估计没有足够的数据来支撑播放到结束,不必停下来进一步缓冲内容。
canplaythrough浏览器估计它可以在不停止内容缓冲的情况下播放媒体直到结束。
completeOfflineAudioContext 渲染完成。
durationchangeduration 属性的值改变时触发。
emptied媒体内容变为空;例如,当这个 media 已经加载完成(或者部分加载完成),则发送此事件,并调用 load() 方法重新加载它。
ended视频停止播放,因为 media 已经到达结束点。
loadedmetadata已加载元数据。
progress在浏览器加载资源时周期性触发。
ratechange播放速率发生变化。
seeked跳帧(seek)操作完成。
seeking跳帧(seek)操作开始。
stalled用户代理(user agent)正在尝试获取媒体数据,但数据意外未出现。
suspend媒体数据加载已暂停。
loadeddatamedia 中的首帧已经完成加载。
timeupdatecurrentTime 属性指定的时间发生变化。
volumechange音量发生变化。
waiting由于暂时缺少数据,播放已停止。
play播放已开始。
playing由于缺乏数据而暂停或延迟后,播放准备开始。
pause播放已暂停。
volume音量发生变化。
fullscreen触发全屏事件

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranui/popover/index.html b/cn/src/ranui/popover/index.html index ed7a9071d2..97b422bf85 100644 --- a/cn/src/ranui/popover/index.html +++ b/cn/src/ranui/popover/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -67,8 +67,8 @@ <r-content> <div>top</div> </r-content> - </r-popover> - + </r-popover> + \ No newline at end of file diff --git a/cn/src/ranui/preview/index.html b/cn/src/ranui/preview/index.html index 27d3f90813..a1aacd850c 100644 --- a/cn/src/ranui/preview/index.html +++ b/cn/src/ranui/preview/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -61,8 +61,8 @@ } }; }; -</script>

属性

资源地址src

src 地址即可打开弹窗,没有src就不展示

html
<r-preview src=""></r-preview>

是否可关闭closeable

closeable 默认为 true ,可以关闭,设置成 false 时, 表示不可关闭,将不会展示右上角的关闭按钮

html
<r-preview closeable="false"></r-preview>
- +</script>

属性

资源地址src

src 地址即可打开弹窗,没有src就不展示

html
<r-preview src=""></r-preview>

是否可关闭closeable

closeable 默认为 true ,可以关闭,设置成 false 时, 表示不可关闭,将不会展示右上角的关闭按钮

html
<r-preview closeable="false"></r-preview>
+ \ No newline at end of file diff --git a/cn/src/ranui/progress/index.html b/cn/src/ranui/progress/index.html index 19a3b02011..55f903c728 100644 --- a/cn/src/ranui/progress/index.html +++ b/cn/src/ranui/progress/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -48,8 +48,8 @@ <r-progress type="primary" percent="40%"></r-progress> <r-progress type="primary" percent="100%"></r-progress>

进度条的点dot

默认展示,设置成false可隐藏

html
<r-progress type="drag" percent="30%" dot="false"></r-progress>
 <r-progress type="primary" percent="40%" dot="true"></r-progress>
-<r-progress type="primary" percent="40%"></r-progress>

类型type

html
<r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

方法

change

percenttotal属性发生变化时,触发change事件。

属性说明类型
value当前进度string|number
percent当前进度string|number
total总进度string|number
- +<r-progress type="primary" percent="40%"></r-progress>

类型type

html
<r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

方法

change

percenttotal属性发生变化时,触发change事件。

属性说明类型
value当前进度string|number
percent当前进度string|number
total总进度string|number
+ \ No newline at end of file diff --git a/cn/src/ranui/radar/index.html b/cn/src/ranui/radar/index.html index 5a10077a35..8ed5b4b032 100644 --- a/cn/src/ranui/radar/index.html +++ b/cn/src/ranui/radar/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -96,8 +96,8 @@ "abilityName": "暴击伤害", "scoreRate": "50" } -] - +] + \ No newline at end of file diff --git a/cn/src/ranui/select/index.html b/cn/src/ranui/select/index.html index ca940854a7..c79e50c06f 100644 --- a/cn/src/ranui/select/index.html +++ b/cn/src/ranui/select/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -83,8 +83,8 @@ <r-option value="185">Mike</r-option> <r-option value="186">Tom</r-option> <r-option value="187">Lucy</r-option> - </r-select> - + </r-select> + \ No newline at end of file diff --git a/cn/src/ranui/skeleton/index.html b/cn/src/ranui/skeleton/index.html index 547ee4e504..29aacc812b 100644 --- a/cn/src/ranui/skeleton/index.html +++ b/cn/src/ranui/skeleton/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

skeleton 骨架屏

在需要等待加载内容的位置提供一个占位图形组合。

代码演示

骨架长度跟随父级元素的长度

xml
<r-skeleton ></r-skeleton>

Released under the MIT License.

- +
Skip to content

skeleton 骨架屏

在需要等待加载内容的位置提供一个占位图形组合。

代码演示

骨架长度跟随父级元素的长度

xml
<r-skeleton ></r-skeleton>

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranui/tab/index.html b/cn/src/ranui/tab/index.html index eeb24b0e7f..d1924c3d5f 100644 --- a/cn/src/ranui/tab/index.html +++ b/cn/src/ranui/tab/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -84,8 +84,8 @@ <r-tab label="tab1">11111</r-tab> <r-tab label="tab2">22222</r-tab> <r-tab label="tab3">33333</r-tab> - </r-tabs> - + </r-tabs> + \ No newline at end of file diff --git a/cn/src/ranui/tabs/index.html b/cn/src/ranui/tabs/index.html index 880e4d2176..a4ad88493d 100644 --- a/cn/src/ranui/tabs/index.html +++ b/cn/src/ranui/tabs/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -66,8 +66,8 @@ <r-tab icon="home" iconSize="22">tab1</r-tab> <r-tab icon="message" iconSize="22">tab2</r-tab> <r-tab icon="user" iconSize="22">tab3</r-tab> -</r-tabs>

风格type

风格有 text,clean,

对齐align

事件event

onchange

切换完成时触发。

- +</r-tabs>

风格type

风格有 text,clean,

对齐align

事件event

onchange

切换完成时触发。

+ \ No newline at end of file diff --git a/cn/src/ranuts/binaryTree/index.html b/cn/src/ranuts/binaryTree/index.html index a750a594cd..4888fd5e3b 100644 --- a/cn/src/ranuts/binaryTree/index.html +++ b/cn/src/ranuts/binaryTree/index.html @@ -13,7 +13,7 @@ - + @@ -37,14 +37,14 @@ - + -
Skip to content

二叉树的定义

在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

二叉树的性质

  • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
  • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
  • 包含 n 个结点的二叉树的高度至少为(log2n)+1
  • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
  • 二叉树的总结点数 n = n1 + n2 + n0
  • 总连线数等于总节点数减一(B = n - 1)
  • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

二叉树的类型

满二叉树

一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

完全二叉树

一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

二叉搜索树

二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

平衡二叉树

平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

B 树

B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

B+树

B+树是 B 树的变体,也是一种多路搜索树。

B*树

B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

红黑树

红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

遍历

前序遍历

后序遍历

中序遍历

层序遍历

常见算法题

镜像二叉树

重建二叉树

二叉树深度

二叉树节点总数

判断二叉树子结构

输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

参考文档

  1. 维基百科二叉树
  2. 百度百科满二叉树

Released under the MIT License.

- +
Skip to content

二叉树的定义

在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

二叉树的性质

  • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
  • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
  • 包含 n 个结点的二叉树的高度至少为(log2n)+1
  • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
  • 二叉树的总结点数 n = n1 + n2 + n0
  • 总连线数等于总节点数减一(B = n - 1)
  • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

二叉树的类型

满二叉树

一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

完全二叉树

一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

二叉搜索树

二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

平衡二叉树

平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

B 树

B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

B+树

B+树是 B 树的变体,也是一种多路搜索树。

B*树

B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

红黑树

红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

遍历

前序遍历

后序遍历

中序遍历

层序遍历

常见算法题

镜像二叉树

重建二叉树

二叉树深度

二叉树节点总数

判断二叉树子结构

输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

参考文档

  1. 维基百科二叉树
  2. 百度百科满二叉树

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranuts/bundler/index.html b/cn/src/ranuts/bundler/index.html index 10b857dcc9..82d597b70b 100644 --- a/cn/src/ranuts/bundler/index.html +++ b/cn/src/ranuts/bundler/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -52,8 +52,8 @@ generate: () => bundle.render() }; }); -}

架构图

- +}

架构图

+ \ No newline at end of file diff --git a/cn/src/ranuts/file/appendFile.html b/cn/src/ranuts/file/appendFile.html index b71535adb6..742d73b996 100644 --- a/cn/src/ranuts/file/appendFile.html +++ b/cn/src/ranuts/file/appendFile.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

AppendFile

追加一些数据到文件内

API

Return

  • Promise
参数说明类型描述
success是否追加成功booleantrue 追加成功 false 追加失败
data追加失败的原因,添加成功后的文件内容any

Options

参数说明类型默认值
path文件路径,需要追加的文件stringundefined
content需要追加的内容string

Example

Released under the MIT License.

- +
Skip to content

AppendFile

追加一些数据到文件内

API

Return

  • Promise
参数说明类型描述
success是否追加成功booleantrue 追加成功 false 追加失败
data追加失败的原因,添加成功后的文件内容any

Options

参数说明类型默认值
path文件路径,需要追加的文件stringundefined
content需要追加的内容string

Example

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranuts/file/fileInfo.html b/cn/src/ranuts/file/fileInfo.html index eddda1499b..9c49b706b7 100644 --- a/cn/src/ranuts/file/fileInfo.html +++ b/cn/src/ranuts/file/fileInfo.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

QueryFileInfo

查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

API

Return

  • Promise
参数说明类型描述
success是否检查成功booleantrue 成功 false 失败
data文件的信息,或者错误的原因Stats

Options

参数说明类型默认值
path文件路径,需要检查的文件路径stringundefined

Example

Released under the MIT License.

- +
Skip to content

QueryFileInfo

查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

API

Return

  • Promise
参数说明类型描述
success是否检查成功booleantrue 成功 false 失败
data文件的信息,或者错误的原因Stats

Options

参数说明类型默认值
path文件路径,需要检查的文件路径stringundefined

Example

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranuts/file/readDir.html b/cn/src/ranuts/file/readDir.html index 180ea91694..8eb744f904 100644 --- a/cn/src/ranuts/file/readDir.html +++ b/cn/src/ranuts/file/readDir.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

ReadDir

读一个目录下的所有文件

API

Return

  • Promise
参数说明类型描述
result目录下所有文件的数组array传入函数的参数

Options

参数说明类型默认值
optionsobject传入函数的参数
dirPath文件的路径Stats

Example

Released under the MIT License.

- +
Skip to content

ReadDir

读一个目录下的所有文件

API

Return

  • Promise
参数说明类型描述
result目录下所有文件的数组array传入函数的参数

Options

参数说明类型默认值
optionsobject传入函数的参数
dirPath文件的路径Stats

Example

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranuts/file/readFile.html b/cn/src/ranuts/file/readFile.html index 5d600f31d6..982077b2d6 100644 --- a/cn/src/ranuts/file/readFile.html +++ b/cn/src/ranuts/file/readFile.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

ReadFile

观察一个文件是否改变

API

Return

  • Promise
参数说明类型描述
data文件是否被改变booleantrue 文件改变 false 文件没变

Options

参数说明类型默认值
path文件路径,需要监听的文件stringundefined
interval监听文件改变的时间,单位毫秒。number20

Example

Released under the MIT License.

- +
Skip to content

ReadFile

观察一个文件是否改变

API

Return

  • Promise
参数说明类型描述
data文件是否被改变booleantrue 文件改变 false 文件没变

Options

参数说明类型默认值
path文件路径,需要监听的文件stringundefined
interval监听文件改变的时间,单位毫秒。number20

Example

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranuts/file/watchFile.html b/cn/src/ranuts/file/watchFile.html index 6a2cb184c5..9d92cbf3e1 100644 --- a/cn/src/ranuts/file/watchFile.html +++ b/cn/src/ranuts/file/watchFile.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

WatchFile

观察一个文件是否改变

API

Return

  • Promise
参数说明类型描述
status文件是否被改变booleantrue 文件改变 false 文件没变

Options

参数说明类型默认值
path文件路径,需要监听的文件stringundefined
interval监听文件改变的时间,单位毫秒。number20

Released under the MIT License.

- +
Skip to content

WatchFile

观察一个文件是否改变

API

Return

  • Promise
参数说明类型描述
status文件是否被改变booleantrue 文件改变 false 文件没变

Options

参数说明类型默认值
path文件路径,需要监听的文件stringundefined
interval监听文件改变的时间,单位毫秒。number20

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranuts/file/writeFile.html b/cn/src/ranuts/file/writeFile.html index e10df1b0e2..ffc187b31b 100644 --- a/cn/src/ranuts/file/writeFile.html +++ b/cn/src/ranuts/file/writeFile.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

WriteFile

将内容写入文件

API

Return

  • Promise
参数说明类型描述
success是否写入成功booleantrue 成功 false 失败
data写入失败的原因,添加成功后的文件内容和文件路径any

Options

参数说明类型默认值
path文件路径,需要追加的文件stringundefined
content需要追加的内容string

Released under the MIT License.

- +
Skip to content

WriteFile

将内容写入文件

API

Return

  • Promise
参数说明类型描述
success是否写入成功booleantrue 成功 false 失败
data写入失败的原因,添加成功后的文件内容和文件路径any

Options

参数说明类型默认值
path文件路径,需要追加的文件stringundefined
content需要追加的内容string

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranuts/index.html b/cn/src/ranuts/index.html index 2d49cd6443..ee42fa2c81 100644 --- a/cn/src/ranuts/index.html +++ b/cn/src/ranuts/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

ranuts overview

方法列表

方法说明详细内容
writeFile写入文件writeFile
readFile读取文件readFile
readDir读取目录,获取目录下所有文件的名字readDir
watchFile观察文件的内容是否发生变化watchFile
queryFileInfo查询文件信息queryFileInfo
filterObj过滤对象filterObj
EventEmitter发布订阅类EventEmitter
str2Xml字符串转成xmlstr2Xml
getMime根据文件格式后缀获取 mime typegetMime
getCookie获取指定 cookie 的值writeFile
formatJson格式化 JSONformatJson

TOTP

2FA Verification
Generate
code:
expires:

Released under the MIT License.

- +
Skip to content

ranuts overview

方法列表

方法说明详细内容
writeFile写入文件writeFile
readFile读取文件readFile
readDir读取目录,获取目录下所有文件的名字readDir
watchFile观察文件的内容是否发生变化watchFile
queryFileInfo查询文件信息queryFileInfo
filterObj过滤对象filterObj
EventEmitter发布订阅类EventEmitter
str2Xml字符串转成xmlstr2Xml
getMime根据文件格式后缀获取 mime typegetMime
getCookie获取指定 cookie 的值writeFile
formatJson格式化 JSONformatJson

TOTP

2FA Verification
Generate
code:
expires:

Released under the MIT License.

+ \ No newline at end of file diff --git a/cn/src/ranuts/mimeType/mimeType.html b/cn/src/ranuts/mimeType/mimeType.html index 1aaebac3e7..14c9a9535b 100644 --- a/cn/src/ranuts/mimeType/mimeType.html +++ b/cn/src/ranuts/mimeType/mimeType.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -49,8 +49,8 @@ // 'application/vnd.openxmlformats-officedocument.presentationml.presentation const res = getMime('.txt'); console.log(result); -// text/plain - +// text/plain + \ No newline at end of file diff --git a/cn/src/ranuts/mode/subscribe.html b/cn/src/ranuts/mode/subscribe.html index 4385b2ca7a..ff67dc1532 100644 --- a/cn/src/ranuts/mode/subscribe.html +++ b/cn/src/ranuts/mode/subscribe.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -73,8 +73,8 @@ // 订阅一次,触发一次自动取消 subscribe.once('other', () => { console.log(5); -}); - +}); + \ No newline at end of file diff --git a/cn/src/ranuts/utils/convertImageToBase64.html b/cn/src/ranuts/utils/convertImageToBase64.html index a861941422..8c220b4830 100644 --- a/cn/src/ranuts/utils/convertImageToBase64.html +++ b/cn/src/ranuts/utils/convertImageToBase64.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -46,8 +46,8 @@ convertImageToBase64(file).then((res) => { console.log(result); -}); - +}); + \ No newline at end of file diff --git a/cn/src/ranuts/utils/filterObj.html b/cn/src/ranuts/utils/filterObj.html index 50144ddbee..65be946875 100644 --- a/cn/src/ranuts/utils/filterObj.html +++ b/cn/src/ranuts/utils/filterObj.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -54,8 +54,8 @@ console.log(result); -// { age:10 } - +// { age:10 } + \ No newline at end of file diff --git a/cn/src/ranuts/utils/formatJson.html b/cn/src/ranuts/utils/formatJson.html index 10679a0993..221dc7501a 100644 --- a/cn/src/ranuts/utils/formatJson.html +++ b/cn/src/ranuts/utils/formatJson.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -51,8 +51,8 @@ const result = formatJson(json); -console.log(result); - +console.log(result); + \ No newline at end of file diff --git a/cn/src/ranuts/utils/getCookie.html b/cn/src/ranuts/utils/getCookie.html index 39180aa37a..90e75da4bf 100644 --- a/cn/src/ranuts/utils/getCookie.html +++ b/cn/src/ranuts/utils/getCookie.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -48,8 +48,8 @@ console.log(result); -// '' - +// '' + \ No newline at end of file diff --git a/cn/src/ranuts/utils/ocr.html b/cn/src/ranuts/utils/ocr.html index 609334b34a..2ca4bbbab4 100644 --- a/cn/src/ranuts/utils/ocr.html +++ b/cn/src/ranuts/utils/ocr.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -56,8 +56,8 @@ // And when thou lovest thy pale orb to shroud // Behind the gather’d blackness lost on high; // And when thou dartest from the wind-rent cloud -// Thy placid lightning o’er the awaken’d sky.

Lang Code

Lang CodeLanguage
afrAfrikaans
amhAmharic
araArabic
asmAssamese
azeAzerbaijani
aze_cyrlAzerbaijani - Cyrillic
belBelarusian
benBengali
bodTibetan
bosBosnian
bulBulgarian
catCatalan; Valencian
cebCebuano
cesCzech
chi_simChinese - Simplified
chi_traChinese - Traditional
chrCherokee
cymWelsh
danDanish
deuGerman
dzoDzongkha
ellGreek, Modern (1453-)
engEnglish
enmEnglish, Middle (1100-1500)
epoEsperanto
estEstonian
eusBasque
fasPersian
finFinnish
fraFrench
frkGerman Fraktur
frmFrench, Middle (ca. 1400-1600)
gleIrish
glgGalician
grcGreek, Ancient (-1453)
gujGujarati
hatHaitian; Haitian Creole
hebHebrew
hinHindi
hrvCroatian
hunHungarian
ikuInuktitut
indIndonesian
islIcelandic
itaItalian
ita_oldItalian - Old
javJavanese
jpnJapanese
kanKannada
katGeorgian
kat_oldGeorgian - Old
kazKazakh
khmCentral Khmer
kirKirghiz; Kyrgyz
korKorean
kurKurdish
laoLao
latLatin
lavLatvian
litLithuanian
malMalayalam
marMarathi
mkdMacedonian
mltMaltese
msaMalay
myaBurmese
nepNepali
nldDutch; Flemish
norNorwegian
oriOriya
panPanjabi; Punjabi
polPolish
porPortuguese
pusPushto; Pashto
ronRomanian; Moldavian; Moldovan
rusRussian
sanSanskrit
sinSinhala; Sinhalese
slkSlovak
slvSlovenian
spaSpanish; Castilian
spa_oldSpanish; Castilian - Old
sqiAlbanian
srpSerbian
srp_latnSerbian - Latin
swaSwahili
sweSwedish
syrSyriac
tamTamil
telTelugu
tgkTajik
tglTagalog
thaThai
tirTigrinya
turTurkish
uigUighur; Uyghur
ukrUkrainian
urdUrdu
uzbUzbek
uzb_cyrlUzbek - Cyrillic
vieVietnamese
yidYiddish
- +// Thy placid lightning o’er the awaken’d sky.

Lang Code

Lang CodeLanguage
afrAfrikaans
amhAmharic
araArabic
asmAssamese
azeAzerbaijani
aze_cyrlAzerbaijani - Cyrillic
belBelarusian
benBengali
bodTibetan
bosBosnian
bulBulgarian
catCatalan; Valencian
cebCebuano
cesCzech
chi_simChinese - Simplified
chi_traChinese - Traditional
chrCherokee
cymWelsh
danDanish
deuGerman
dzoDzongkha
ellGreek, Modern (1453-)
engEnglish
enmEnglish, Middle (1100-1500)
epoEsperanto
estEstonian
eusBasque
fasPersian
finFinnish
fraFrench
frkGerman Fraktur
frmFrench, Middle (ca. 1400-1600)
gleIrish
glgGalician
grcGreek, Ancient (-1453)
gujGujarati
hatHaitian; Haitian Creole
hebHebrew
hinHindi
hrvCroatian
hunHungarian
ikuInuktitut
indIndonesian
islIcelandic
itaItalian
ita_oldItalian - Old
javJavanese
jpnJapanese
kanKannada
katGeorgian
kat_oldGeorgian - Old
kazKazakh
khmCentral Khmer
kirKirghiz; Kyrgyz
korKorean
kurKurdish
laoLao
latLatin
lavLatvian
litLithuanian
malMalayalam
marMarathi
mkdMacedonian
mltMaltese
msaMalay
myaBurmese
nepNepali
nldDutch; Flemish
norNorwegian
oriOriya
panPanjabi; Punjabi
polPolish
porPortuguese
pusPushto; Pashto
ronRomanian; Moldavian; Moldovan
rusRussian
sanSanskrit
sinSinhala; Sinhalese
slkSlovak
slvSlovenian
spaSpanish; Castilian
spa_oldSpanish; Castilian - Old
sqiAlbanian
srpSerbian
srp_latnSerbian - Latin
swaSwahili
sweSwedish
syrSyriac
tamTamil
telTelugu
tgkTajik
tglTagalog
thaThai
tirTigrinya
turTurkish
uigUighur; Uyghur
ukrUkrainian
urdUrdu
uzbUzbek
uzb_cyrlUzbek - Cyrillic
vieVietnamese
yidYiddish
+ \ No newline at end of file diff --git a/cn/src/ranuts/utils/str2xml.html b/cn/src/ranuts/utils/str2xml.html index af8bf8c434..81c45c432d 100644 --- a/cn/src/ranuts/utils/str2xml.html +++ b/cn/src/ranuts/utils/str2xml.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -49,8 +49,8 @@ const icon = str2Xml(svg, 'image/svg+xml'); -document.body.appendChild(icon); - +document.body.appendChild(icon); + \ No newline at end of file diff --git a/cn/src/ranuts/utils/task.html b/cn/src/ranuts/utils/task.html index dcb97aa559..7a3025294a 100644 --- a/cn/src/ranuts/utils/task.html +++ b/cn/src/ranuts/utils/task.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -48,8 +48,8 @@ const time = taskEnd(taskId); -console.log('task 执行花费的时间', time);

二.new Date().getTime()

new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

  1. 某些情况下,毫秒级精度可能不够。
  2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

    由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

三.console.time(), console.timeEnd()

启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

四.performance.now()

performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

- +console.log('task 执行花费的时间', time);

二.new Date().getTime()

new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

  1. 某些情况下,毫秒级精度可能不够。
  2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

    由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

三.console.time(), console.timeEnd()

启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

四.performance.now()

performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

+ \ No newline at end of file diff --git "a/cn/src/types/TS\347\261\273\345\236\213.html" "b/cn/src/types/TS\347\261\273\345\236\213.html" index 5086b35086..38adaed339 100644 --- "a/cn/src/types/TS\347\261\273\345\236\213.html" +++ "b/cn/src/types/TS\347\261\273\345\236\213.html" @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -89,8 +89,8 @@ age?: number; } -type tuple = [string, number?]; - +type tuple = [string, number?]; + \ No newline at end of file diff --git "a/cn/src/types/\346\250\241\345\274\217\345\214\271\351\205\215.html" "b/cn/src/types/\346\250\241\345\274\217\345\214\271\351\205\215.html" index 115ffa3d2e..ec932d102f 100644 --- "a/cn/src/types/\346\250\241\345\274\217\345\214\271\351\205\215.html" +++ "b/cn/src/types/\346\250\241\345\274\217\345\214\271\351\205\215.html" @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -52,8 +52,8 @@ new (name: string): Person; }

这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

ts
type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T
   ? T
-  : unknown;
- + : unknown; + \ No newline at end of file diff --git "a/cn/src/types/\347\261\273\345\236\213\350\277\220\347\256\227.html" "b/cn/src/types/\347\261\273\345\236\213\350\277\220\347\256\227.html" index 5d87f15c84..af08de89f3 100644 --- "a/cn/src/types/\347\261\273\345\236\213\350\277\220\347\256\227.html" +++ "b/cn/src/types/\347\261\273\345\236\213\350\277\220\347\256\227.html" @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -68,8 +68,8 @@ // type res = { // aaa:[1,1,1] // bbb:[2,2,2] -// }

这里的 & string 可能大家会迷惑,解释一下:

因为索引类型(对象、class 等)可以用 string、number 和 symbol 作为 key,这里 keyof T 取出的索引就是 string | number | symbol 的联合类型,和 string 取交叉部分就只剩下 string 了。就像前面所说,交叉类型会把同一类型做合并,不同类型舍弃。

因为 js 处理对象比较多,所以索引类型的映射比较重要。

- +// }

这里的 & string 可能大家会迷惑,解释一下:

因为索引类型(对象、class 等)可以用 string、number 和 symbol 作为 key,这里 keyof T 取出的索引就是 string | number | symbol 的联合类型,和 string 取交叉部分就只剩下 string 了。就像前面所说,交叉类型会把同一类型做合并,不同类型舍弃。

因为 js 处理对象比较多,所以索引类型的映射比较重要。

+ \ No newline at end of file diff --git "a/cn/src/types/\351\253\230\347\272\247\347\261\273\345\236\213.html" "b/cn/src/types/\351\253\230\347\272\247\347\261\273\345\236\213.html" index b177939cfe..9f55705064 100644 --- "a/cn/src/types/\351\253\230\347\272\247\347\261\273\345\236\213.html" +++ "b/cn/src/types/\351\253\230\347\272\247\347\261\273\345\236\213.html" @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

TypeScript 内置的高级类型

Parameters

Parameters 用于提取函数类型的参数类型。

ReturnType

ReturnType 用于提取函数类型的返回值类型。

ConstructorParameters

构造器类型和函数类型的区别就是可以被 new。

Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

InstanceType

提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

ThisParameterType

OmitThisParameter

Partial

Required

Readonly

Pick

Record

Exclude

Extract

Omit

Awaited

NonNullable

Uppercase

Lowercase

Capitalize

Uncapitalize

总结

比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

用模式匹配 + 重新构造可以实现:OmitThisParameter

用重新构造可以实现:Partial、Required、Readonly、Pick、Record

用模式匹配 + 递归可以实现: Awaited

用联合类型在分布式条件类型的特性可以实现: Exclude

此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

Last updated:

Released under the MIT License.

- +
Skip to content

TypeScript 内置的高级类型

Parameters

Parameters 用于提取函数类型的参数类型。

ReturnType

ReturnType 用于提取函数类型的返回值类型。

ConstructorParameters

构造器类型和函数类型的区别就是可以被 new。

Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

InstanceType

提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

ThisParameterType

OmitThisParameter

Partial

Required

Readonly

Pick

Record

Exclude

Extract

Omit

Awaited

NonNullable

Uppercase

Lowercase

Capitalize

Uncapitalize

总结

比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

用模式匹配 + 重新构造可以实现:OmitThisParameter

用重新构造可以实现:Partial、Required、Readonly、Pick、Record

用模式匹配 + 递归可以实现: Awaited

用联合类型在分布式条件类型的特性可以实现: Exclude

此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

Last updated:

Released under the MIT License.

+ \ No newline at end of file diff --git a/hashmap.json b/hashmap.json index 70dc2abc31..845e872d63 100644 --- a/hashmap.json +++ b/hashmap.json @@ -1 +1 @@ -{"cn_index.md":"DRjzDfRD","cn_src_article_astparse_tokenizer.md":"_qy1-yRL","cn_src_article_babel.md":"e4GAuw5X","cn_src_article_bundle.md":"CXbozmz-","cn_src_article_designmode.md":"DZ98r33q","cn_src_article_docpreview.md":"to4R_V9b","cn_src_article_functionalprogramming.md":"CkKiYr9L","cn_src_article_imagemin.md":"CHqS0vGt","cn_src_article_javascript_domload.md":"Ci82ToLN","cn_src_article_sort_bubble_index.md":"CjZlxYfr","cn_src_article_sort_bucket_index.md":"B4drqe-3","cn_src_article_sort_count_index.md":"DYoyFiDb","cn_src_article_sort_heap_index.md":"CkqW8bYY","cn_src_article_sort_index.md":"D92LVwEh","cn_src_article_sort_insert_index.md":"CmQ1YgOQ","cn_src_article_sort_merge_index.md":"MDU-inBg","cn_src_article_sort_quick_index.md":"CvZw-icp","cn_src_article_sort_radix_index.md":"D1vfzfWU","cn_src_article_sort_select_index.md":"HS1vLdcG","cn_src_article_sort_shell_index.md":"DecAJ1tS","cn_src_article_systemdesign.md":"hOp1x72G","cn_src_article_typescript_calculate.md":"CNAvvheA","cn_src_article_typescript_index.md":"1jbAHunE","cn_src_article_typescript_pattern.md":"rnM0NHZ9","cn_src_article_typescript_reconstruction.md":"BhFbdKZJ","cn_src_article_typescript_recursion.md":"D22JKCo3","cn_src_article_typescript_uniontype.md":"atUNmveE","cn_src_article_video.md":"Dr5fjwZA","cn_src_article_visual.md":"Du_v00-A","cn_src_note_centos.md":"CQEnE6Ac","cn_src_note_docker.md":"Cdo71zW_","cn_src_note_libreoffice2wasm.md":"D2SYnyUq","cn_src_note_ubuntu.md":"DgjTInOe","cn_src_ranui_button_index.md":"CGOk0U0f","cn_src_ranui_checkbox_index.md":"ZHU13zPM","cn_src_ranui_icon_index.md":"NbG8FVyF","cn_src_ranui_image_index.md":"DowaFgBv","cn_src_ranui_index.md":"DHsUGsLz","cn_src_ranui_input_index.md":"BcdnxU38","cn_src_ranui_loading_index.md":"CA72DxYe","cn_src_ranui_math_index.md":"VRI2riCL","cn_src_ranui_message_index.md":"C38PI1jt","cn_src_ranui_modal_index.md":"I-C9OtVX","cn_src_ranui_player_index.md":"CuAqghFD","cn_src_ranui_popover_index.md":"DRuLc3Ni","cn_src_ranui_preview_index.md":"BsAShiRh","cn_src_ranui_progress_index.md":"m21IXa5G","cn_src_ranui_radar_index.md":"A6jKbspG","cn_src_ranui_select_index.md":"CmisBOzA","cn_src_ranui_skeleton_index.md":"t-ZVwoSq","cn_src_ranui_tab_index.md":"D3FaivVj","cn_src_ranui_tabs_index.md":"D-Z5zQWG","cn_src_ranuts_binarytree_index.md":"By-o1AjL","cn_src_ranuts_bundler_index.md":"gFLefqgx","cn_src_ranuts_file_appendfile.md":"Kjwfv66v","cn_src_ranuts_file_fileinfo.md":"Dho5Tv6s","cn_src_ranuts_file_readdir.md":"BSttmwRD","cn_src_ranuts_file_readfile.md":"DqgoToSw","cn_src_ranuts_file_watchfile.md":"DAZXSmjV","cn_src_ranuts_file_writefile.md":"mwv7EGlj","cn_src_ranuts_index.md":"ImKijNhD","cn_src_ranuts_mimetype_mimetype.md":"DNyJyegy","cn_src_ranuts_mode_subscribe.md":"BhBmLNNr","cn_src_ranuts_utils_convertimagetobase64.md":"DXYg1zir","cn_src_ranuts_utils_filterobj.md":"DE1C38Kh","cn_src_ranuts_utils_formatjson.md":"C6zYMUay","cn_src_ranuts_utils_getcookie.md":"BomC6eQg","cn_src_ranuts_utils_ocr.md":"Bsfwykuh","cn_src_ranuts_utils_str2xml.md":"Bf-gtS9N","cn_src_ranuts_utils_task.md":"DwcnyfHt","cn_src_types_ts类型.md":"BdnhcvJe","cn_src_types_模式匹配.md":"LMxiYHqa","cn_src_types_类型运算.md":"Q4zNTo0P","cn_src_types_高级类型.md":"CX5Or8t7","index.md":"C05wkIRp","src_article_astparse_tokenizer.md":"B5PslVvl","src_article_babel.md":"Czc7FSEu","src_article_bundle.md":"DqBSsozI","src_article_designmode.md":"GNIygirc","src_article_functionalprogramming.md":"zs1zfDDr","src_article_imagemin.md":"BAQ0hCS3","src_article_javascript_domload.md":"BMbEujHQ","src_article_sort_bubble_index.md":"LfnS1mFU","src_article_sort_bucket_index.md":"B2XZzvVq","src_article_sort_count_index.md":"DPdRRb52","src_article_sort_heap_index.md":"DrKoQkIR","src_article_sort_index.md":"ILCQfWPM","src_article_sort_insert_index.md":"DkXN_nPk","src_article_sort_merge_index.md":"BrDl4p8K","src_article_sort_quick_index.md":"DR2SVz8M","src_article_sort_radix_index.md":"BfE2sE6Y","src_article_sort_select_index.md":"D6mV4SPJ","src_article_sort_shell_index.md":"D333S2vN","src_article_typescript_calculate.md":"xkHvMeV2","src_article_typescript_index.md":"DQFvubag","src_article_typescript_pattern.md":"ChySx5n3","src_article_typescript_reconstruction.md":"CohgiGIS","src_article_typescript_recursion.md":"PrJfeezf","src_article_typescript_uniontype.md":"D4NH8xmg","src_ranui_button_index.md":"OpGrfpg8","src_ranui_checkbox_index.md":"C6CmsGDw","src_ranui_icon_index.md":"BQTFP8u3","src_ranui_image_index.md":"ntBTaVra","src_ranui_index.md":"C5qoVF5Z","src_ranui_input_index.md":"D8sbP-uy","src_ranui_loading_index.md":"iV1VL5bO","src_ranui_math_index.md":"BJRXy7dX","src_ranui_message_index.md":"C7vn1gHP","src_ranui_modal_index.md":"DEMwPGEr","src_ranui_player_index.md":"DP3RaPdA","src_ranui_popover_index.md":"CfxjwwU_","src_ranui_preview_index.md":"fG1IQRia","src_ranui_progress_index.md":"cmnI4FIh","src_ranui_radar_index.md":"DC-fIIc-","src_ranui_select_index.md":"BtLjKVVg","src_ranui_skeleton_index.md":"J2D8qbZD","src_ranui_tab_index.md":"CnkY3B_Y","src_ranui_tabs_index.md":"CPGXXUJu","src_ranuts_binarytree_index.md":"9VY_7CtH","src_ranuts_bundler_index.md":"2d_kwA5U","src_ranuts_file_appendfile.md":"CHmuoXqR","src_ranuts_file_fileinfo.md":"BGMu3rbo","src_ranuts_file_readdir.md":"D-wGUvqF","src_ranuts_file_readfile.md":"DzoyHHIO","src_ranuts_file_watchfile.md":"6J1Mi6RC","src_ranuts_file_writefile.md":"D0A_cl3U","src_ranuts_index.md":"Q_PSqhjV","src_ranuts_mimetype_mimetype.md":"CD3nVZEO","src_ranuts_mode_subscribe.md":"CtPQvPCj","src_ranuts_utils_convertimagetobase64.md":"CGjlmYhP","src_ranuts_utils_filterobj.md":"BsaBmsvk","src_ranuts_utils_formatjson.md":"DNKXhroe","src_ranuts_utils_getcookie.md":"CDeVa4hl","src_ranuts_utils_ocr.md":"l96JLeA3","src_ranuts_utils_str2xml.md":"CwgfkeY1","src_ranuts_utils_task.md":"CgGq5wbB","src_types_ts类型.md":"BkjT3Xys","src_types_模式匹配.md":"CC8I3wm1","src_types_类型运算.md":"CYIL5e8N","src_types_高级类型.md":"DrTZYnDE"} +{"cn_index.md":"C-Prq36L","cn_src_article_astparse_tokenizer.md":"X9WaN6nP","cn_src_article_babel.md":"BRRU23MO","cn_src_article_bundle.md":"OaaTEdt2","cn_src_article_designmode.md":"DOHuh5Vx","cn_src_article_docpreview.md":"BriOMnC6","cn_src_article_functionalprogramming.md":"kIfOv665","cn_src_article_imagemin.md":"DFEWNSIZ","cn_src_article_javascript_domload.md":"B74fIpy6","cn_src_article_sort_bubble_index.md":"Cp1RBpmv","cn_src_article_sort_bucket_index.md":"DART29Tq","cn_src_article_sort_count_index.md":"00GyLjR_","cn_src_article_sort_heap_index.md":"CzO5sZ8i","cn_src_article_sort_index.md":"BocISVrP","cn_src_article_sort_insert_index.md":"DjxCK_3e","cn_src_article_sort_merge_index.md":"CkGKR7pJ","cn_src_article_sort_quick_index.md":"CGqy4-ZS","cn_src_article_sort_radix_index.md":"DL17V-7-","cn_src_article_sort_select_index.md":"CnGat9lb","cn_src_article_sort_shell_index.md":"DLjGy-JA","cn_src_article_systemdesign.md":"6LK-pZuK","cn_src_article_typescript_calculate.md":"CC_IXoWD","cn_src_article_typescript_index.md":"BUmi2po9","cn_src_article_typescript_pattern.md":"CyszQeR8","cn_src_article_typescript_reconstruction.md":"B9hETE9S","cn_src_article_typescript_recursion.md":"BuRNB37-","cn_src_article_typescript_uniontype.md":"wPcbHmYa","cn_src_article_video.md":"BmsbKb7b","cn_src_article_visual.md":"BO64nAx5","cn_src_note_centos.md":"DNrgG0Q4","cn_src_note_docker.md":"tDnzoB7w","cn_src_note_libreoffice2wasm.md":"DGtQ0t2p","cn_src_note_ubuntu.md":"pqpeIfp6","cn_src_ranui_button_index.md":"BoAZB7ta","cn_src_ranui_checkbox_index.md":"C3KmEc2G","cn_src_ranui_icon_index.md":"BB3PfUZM","cn_src_ranui_image_index.md":"C-xnLYah","cn_src_ranui_index.md":"CrHo0ngz","cn_src_ranui_input_index.md":"DottgzSq","cn_src_ranui_loading_index.md":"CO9CpYNH","cn_src_ranui_math_index.md":"DmcvA4-2","cn_src_ranui_message_index.md":"DQuTGF50","cn_src_ranui_modal_index.md":"C7YyXb2j","cn_src_ranui_player_index.md":"PhEE5Km4","cn_src_ranui_popover_index.md":"BNd4uUYL","cn_src_ranui_preview_index.md":"CjuF-KUm","cn_src_ranui_progress_index.md":"CLS6wwle","cn_src_ranui_radar_index.md":"BVnDbAlC","cn_src_ranui_select_index.md":"BygieB1y","cn_src_ranui_skeleton_index.md":"PVahOUCW","cn_src_ranui_tab_index.md":"CPn99LR8","cn_src_ranui_tabs_index.md":"7O7hxEi8","cn_src_ranuts_binarytree_index.md":"DrXBmpfQ","cn_src_ranuts_bundler_index.md":"CNoHThyX","cn_src_ranuts_file_appendfile.md":"BDgZPn7V","cn_src_ranuts_file_fileinfo.md":"KotpDHQJ","cn_src_ranuts_file_readdir.md":"rKDcx1fc","cn_src_ranuts_file_readfile.md":"nK6bqV_e","cn_src_ranuts_file_watchfile.md":"CAsEL4vf","cn_src_ranuts_file_writefile.md":"BoU7gKL6","cn_src_ranuts_index.md":"CuyLwwdp","cn_src_ranuts_mimetype_mimetype.md":"C1HE55kh","cn_src_ranuts_mode_subscribe.md":"DVNH30m1","cn_src_ranuts_utils_convertimagetobase64.md":"DeS8CqKI","cn_src_ranuts_utils_filterobj.md":"Dr_ls9ui","cn_src_ranuts_utils_formatjson.md":"DAOEUsMy","cn_src_ranuts_utils_getcookie.md":"DbhTAbDg","cn_src_ranuts_utils_ocr.md":"uNdytYyR","cn_src_ranuts_utils_str2xml.md":"s2QXhzVM","cn_src_ranuts_utils_task.md":"DbClSCsQ","cn_src_types_ts类型.md":"iJyVKiUM","cn_src_types_模式匹配.md":"CpwnVZOP","cn_src_types_类型运算.md":"HXO7_zmg","cn_src_types_高级类型.md":"DshdJwmZ","index.md":"B_9rwraW","src_article_astparse_tokenizer.md":"BvreBUpi","src_article_babel.md":"D6U-I50A","src_article_bundle.md":"ChxeIam8","src_article_designmode.md":"DUzkKke4","src_article_functionalprogramming.md":"dIGyJ6sB","src_article_imagemin.md":"CBY6W2re","src_article_javascript_domload.md":"Dd7Dzr5Y","src_article_sort_bubble_index.md":"BmVWI7FN","src_article_sort_bucket_index.md":"C8sI_tGv","src_article_sort_count_index.md":"BXZiVRgc","src_article_sort_heap_index.md":"D8fxvFJ4","src_article_sort_index.md":"Du9jHICi","src_article_sort_insert_index.md":"CBL5Zq0h","src_article_sort_merge_index.md":"DR-N5gUH","src_article_sort_quick_index.md":"B-15itZC","src_article_sort_radix_index.md":"DYGHdCvy","src_article_sort_select_index.md":"sRykeoeT","src_article_sort_shell_index.md":"H4IG1J-3","src_article_typescript_calculate.md":"C7yhKz7X","src_article_typescript_index.md":"DeH7pgUe","src_article_typescript_pattern.md":"3sU5fRCA","src_article_typescript_reconstruction.md":"CSOt7yMn","src_article_typescript_recursion.md":"BD02XaoF","src_article_typescript_uniontype.md":"BKfC5bWe","src_ranui_button_index.md":"C5LIQdyS","src_ranui_checkbox_index.md":"Dmwi-qhd","src_ranui_icon_index.md":"DHD0uzGs","src_ranui_image_index.md":"DuNw7DgW","src_ranui_index.md":"DftpvnGE","src_ranui_input_index.md":"DFv44XMF","src_ranui_loading_index.md":"EajM1Fh_","src_ranui_math_index.md":"BX7dsUxQ","src_ranui_message_index.md":"DpTwiP3x","src_ranui_modal_index.md":"BfBNxpQt","src_ranui_player_index.md":"_41AQgcv","src_ranui_popover_index.md":"Bq9gtddN","src_ranui_preview_index.md":"tg6oXUar","src_ranui_progress_index.md":"z1F0wQbE","src_ranui_radar_index.md":"B3Rqerka","src_ranui_select_index.md":"B8UBMGlm","src_ranui_skeleton_index.md":"8I5i20E1","src_ranui_tab_index.md":"CeQ2RW9Y","src_ranui_tabs_index.md":"CxBjn965","src_ranuts_binarytree_index.md":"BOOvvNkp","src_ranuts_bundler_index.md":"BBvegtDt","src_ranuts_file_appendfile.md":"Ba1ZPoPO","src_ranuts_file_fileinfo.md":"C3Zp4I69","src_ranuts_file_readdir.md":"BDf-8MWg","src_ranuts_file_readfile.md":"DZETE7kx","src_ranuts_file_watchfile.md":"CRypAqqF","src_ranuts_file_writefile.md":"ouweFqJg","src_ranuts_index.md":"DZGRxbxI","src_ranuts_mimetype_mimetype.md":"CxFL5631","src_ranuts_mode_subscribe.md":"Psp8bIgo","src_ranuts_utils_convertimagetobase64.md":"BvH8a7ux","src_ranuts_utils_filterobj.md":"BtAgodt-","src_ranuts_utils_formatjson.md":"CSMLr8Hr","src_ranuts_utils_getcookie.md":"C9JVGfW9","src_ranuts_utils_ocr.md":"DzafMtkn","src_ranuts_utils_str2xml.md":"DiJE8okl","src_ranuts_utils_task.md":"CapuHzRA","src_types_ts类型.md":"DIHmZPe4","src_types_模式匹配.md":"CjXSWGVq","src_types_类型运算.md":"Bf4-_Wi-","src_types_高级类型.md":"CufDmqA6"} diff --git a/index.html b/index.html index 881c1ac2f8..8810ca7f5c 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - +
Skip to content

ran

A Troupe of little vagrants of the world , leave your footprints in my words .

logo

Released under the MIT License.

- + \ No newline at end of file diff --git a/pagefind/fragment/en_16d01f2.pf_fragment b/pagefind/fragment/en_16d01f2.pf_fragment new file mode 100644 index 0000000000..7b212ebfee Binary files /dev/null and b/pagefind/fragment/en_16d01f2.pf_fragment differ diff --git a/pagefind/fragment/en_1d2a8f7.pf_fragment b/pagefind/fragment/en_1d2a8f7.pf_fragment deleted file mode 100644 index 199bdd5b04..0000000000 Binary files a/pagefind/fragment/en_1d2a8f7.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/en_1f28c1c.pf_fragment b/pagefind/fragment/en_1f28c1c.pf_fragment new file mode 100644 index 0000000000..840f271ccc Binary files /dev/null and b/pagefind/fragment/en_1f28c1c.pf_fragment differ diff --git a/pagefind/fragment/en_2942c3c.pf_fragment b/pagefind/fragment/en_2942c3c.pf_fragment deleted file mode 100644 index 5620cc7e92..0000000000 Binary files a/pagefind/fragment/en_2942c3c.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/en_4873c44.pf_fragment b/pagefind/fragment/en_324b2ed.pf_fragment similarity index 81% rename from pagefind/fragment/en_4873c44.pf_fragment rename to pagefind/fragment/en_324b2ed.pf_fragment index 15b7f8c263..f3b373ff21 100644 Binary files a/pagefind/fragment/en_4873c44.pf_fragment and b/pagefind/fragment/en_324b2ed.pf_fragment differ diff --git a/pagefind/fragment/en_34b032a.pf_fragment b/pagefind/fragment/en_34b032a.pf_fragment new file mode 100644 index 0000000000..8340088203 Binary files /dev/null and b/pagefind/fragment/en_34b032a.pf_fragment differ diff --git a/pagefind/fragment/en_3541bef.pf_fragment b/pagefind/fragment/en_3541bef.pf_fragment new file mode 100644 index 0000000000..03dd4b5647 Binary files /dev/null and b/pagefind/fragment/en_3541bef.pf_fragment differ diff --git a/pagefind/fragment/en_51f248e.pf_fragment b/pagefind/fragment/en_51f248e.pf_fragment deleted file mode 100644 index ee23da2dd9..0000000000 Binary files a/pagefind/fragment/en_51f248e.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/en_5f9a7eb.pf_fragment b/pagefind/fragment/en_5f9a7eb.pf_fragment deleted file mode 100644 index ab3266bfe1..0000000000 Binary files a/pagefind/fragment/en_5f9a7eb.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/en_63f4b5c.pf_fragment b/pagefind/fragment/en_63f4b5c.pf_fragment new file mode 100644 index 0000000000..21cdcf409e Binary files /dev/null and b/pagefind/fragment/en_63f4b5c.pf_fragment differ diff --git a/pagefind/fragment/en_8e7817f.pf_fragment b/pagefind/fragment/en_6b4c4a9.pf_fragment similarity index 76% rename from pagefind/fragment/en_8e7817f.pf_fragment rename to pagefind/fragment/en_6b4c4a9.pf_fragment index facf0e919e..5a527618a0 100644 Binary files a/pagefind/fragment/en_8e7817f.pf_fragment and b/pagefind/fragment/en_6b4c4a9.pf_fragment differ diff --git a/pagefind/fragment/en_901e811.pf_fragment b/pagefind/fragment/en_6e7d47a.pf_fragment similarity index 93% rename from pagefind/fragment/en_901e811.pf_fragment rename to pagefind/fragment/en_6e7d47a.pf_fragment index 50d7ded864..7e5c912beb 100644 Binary files a/pagefind/fragment/en_901e811.pf_fragment and b/pagefind/fragment/en_6e7d47a.pf_fragment differ diff --git a/pagefind/fragment/en_4cca5aa.pf_fragment b/pagefind/fragment/en_70bee3b.pf_fragment similarity index 95% rename from pagefind/fragment/en_4cca5aa.pf_fragment rename to pagefind/fragment/en_70bee3b.pf_fragment index e79f8dddc9..3b0dab07cc 100644 Binary files a/pagefind/fragment/en_4cca5aa.pf_fragment and b/pagefind/fragment/en_70bee3b.pf_fragment differ diff --git a/pagefind/fragment/en_75d5dcb.pf_fragment b/pagefind/fragment/en_75d5dcb.pf_fragment deleted file mode 100644 index 1c9dd3d027..0000000000 Binary files a/pagefind/fragment/en_75d5dcb.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/en_78f477e.pf_fragment b/pagefind/fragment/en_78f477e.pf_fragment new file mode 100644 index 0000000000..c2db080521 Binary files /dev/null and b/pagefind/fragment/en_78f477e.pf_fragment differ diff --git a/pagefind/fragment/en_7a4ca4f.pf_fragment b/pagefind/fragment/en_7a4ca4f.pf_fragment deleted file mode 100644 index b01eafa740..0000000000 Binary files a/pagefind/fragment/en_7a4ca4f.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/en_216410c.pf_fragment b/pagefind/fragment/en_7fffa0e.pf_fragment similarity index 82% rename from pagefind/fragment/en_216410c.pf_fragment rename to pagefind/fragment/en_7fffa0e.pf_fragment index 6c50693679..4b740b9a5c 100644 Binary files a/pagefind/fragment/en_216410c.pf_fragment and b/pagefind/fragment/en_7fffa0e.pf_fragment differ diff --git a/pagefind/fragment/en_a9c2374.pf_fragment b/pagefind/fragment/en_a9c2374.pf_fragment deleted file mode 100644 index 0da99bfeae..0000000000 Binary files a/pagefind/fragment/en_a9c2374.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/en_aab3547.pf_fragment b/pagefind/fragment/en_aab3547.pf_fragment new file mode 100644 index 0000000000..884682c597 Binary files /dev/null and b/pagefind/fragment/en_aab3547.pf_fragment differ diff --git a/pagefind/fragment/en_31bb7a6.pf_fragment b/pagefind/fragment/en_af4a67a.pf_fragment similarity index 85% rename from pagefind/fragment/en_31bb7a6.pf_fragment rename to pagefind/fragment/en_af4a67a.pf_fragment index 9674e7c306..c8db2dd51d 100644 Binary files a/pagefind/fragment/en_31bb7a6.pf_fragment and b/pagefind/fragment/en_af4a67a.pf_fragment differ diff --git a/pagefind/fragment/en_c84c5e7.pf_fragment b/pagefind/fragment/en_c84c5e7.pf_fragment deleted file mode 100644 index e787910bfa..0000000000 Binary files a/pagefind/fragment/en_c84c5e7.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/en_d792b8c.pf_fragment b/pagefind/fragment/en_d792b8c.pf_fragment deleted file mode 100644 index d015c5e9cb..0000000000 Binary files a/pagefind/fragment/en_d792b8c.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/en_c9c7c59.pf_fragment b/pagefind/fragment/en_dccebd7.pf_fragment similarity index 82% rename from pagefind/fragment/en_c9c7c59.pf_fragment rename to pagefind/fragment/en_dccebd7.pf_fragment index ec57f4cd9b..2dedeba66b 100644 Binary files a/pagefind/fragment/en_c9c7c59.pf_fragment and b/pagefind/fragment/en_dccebd7.pf_fragment differ diff --git a/pagefind/fragment/en_edda142.pf_fragment b/pagefind/fragment/en_edda142.pf_fragment new file mode 100644 index 0000000000..c78a163277 Binary files /dev/null and b/pagefind/fragment/en_edda142.pf_fragment differ diff --git a/pagefind/fragment/en_f575e71.pf_fragment b/pagefind/fragment/en_f575e71.pf_fragment new file mode 100644 index 0000000000..52fe3656c0 Binary files /dev/null and b/pagefind/fragment/en_f575e71.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_e7c7085.pf_fragment b/pagefind/fragment/zh-cn_20933c3.pf_fragment similarity index 94% rename from pagefind/fragment/zh-cn_e7c7085.pf_fragment rename to pagefind/fragment/zh-cn_20933c3.pf_fragment index ccdd075eb1..f803a8c39d 100644 Binary files a/pagefind/fragment/zh-cn_e7c7085.pf_fragment and b/pagefind/fragment/zh-cn_20933c3.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_aa1f32d.pf_fragment b/pagefind/fragment/zh-cn_217f9f1.pf_fragment similarity index 96% rename from pagefind/fragment/zh-cn_aa1f32d.pf_fragment rename to pagefind/fragment/zh-cn_217f9f1.pf_fragment index 00982d6432..d7a59ac231 100644 Binary files a/pagefind/fragment/zh-cn_aa1f32d.pf_fragment and b/pagefind/fragment/zh-cn_217f9f1.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_2ab4b75.pf_fragment b/pagefind/fragment/zh-cn_2ab4b75.pf_fragment deleted file mode 100644 index ccb668f442..0000000000 Binary files a/pagefind/fragment/zh-cn_2ab4b75.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_2bc07af.pf_fragment b/pagefind/fragment/zh-cn_2bc07af.pf_fragment new file mode 100644 index 0000000000..e7181b7eca Binary files /dev/null and b/pagefind/fragment/zh-cn_2bc07af.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_2e8f3b4.pf_fragment b/pagefind/fragment/zh-cn_2e8f3b4.pf_fragment deleted file mode 100644 index 3519bdb748..0000000000 Binary files a/pagefind/fragment/zh-cn_2e8f3b4.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_592cc95.pf_fragment b/pagefind/fragment/zh-cn_592cc95.pf_fragment deleted file mode 100644 index 24c0fb829b..0000000000 Binary files a/pagefind/fragment/zh-cn_592cc95.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_5b71249.pf_fragment b/pagefind/fragment/zh-cn_5b71249.pf_fragment deleted file mode 100644 index fc7248447f..0000000000 Binary files a/pagefind/fragment/zh-cn_5b71249.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_5f3328b.pf_fragment b/pagefind/fragment/zh-cn_5f3328b.pf_fragment new file mode 100644 index 0000000000..0602e96d92 Binary files /dev/null and b/pagefind/fragment/zh-cn_5f3328b.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_69610a7.pf_fragment b/pagefind/fragment/zh-cn_69610a7.pf_fragment new file mode 100644 index 0000000000..36093500dd Binary files /dev/null and b/pagefind/fragment/zh-cn_69610a7.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_707d8fd.pf_fragment b/pagefind/fragment/zh-cn_82b59c2.pf_fragment similarity index 86% rename from pagefind/fragment/zh-cn_707d8fd.pf_fragment rename to pagefind/fragment/zh-cn_82b59c2.pf_fragment index 18688db7e8..1a0fe3a398 100644 Binary files a/pagefind/fragment/zh-cn_707d8fd.pf_fragment and b/pagefind/fragment/zh-cn_82b59c2.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_8338621.pf_fragment b/pagefind/fragment/zh-cn_8338621.pf_fragment deleted file mode 100644 index 4ab3681151..0000000000 Binary files a/pagefind/fragment/zh-cn_8338621.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_88af4d0.pf_fragment b/pagefind/fragment/zh-cn_88af4d0.pf_fragment new file mode 100644 index 0000000000..d9e4c6f64d Binary files /dev/null and b/pagefind/fragment/zh-cn_88af4d0.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_caddc62.pf_fragment b/pagefind/fragment/zh-cn_8c8e8be.pf_fragment similarity index 88% rename from pagefind/fragment/zh-cn_caddc62.pf_fragment rename to pagefind/fragment/zh-cn_8c8e8be.pf_fragment index 302b1cfcea..6ead354b91 100644 Binary files a/pagefind/fragment/zh-cn_caddc62.pf_fragment and b/pagefind/fragment/zh-cn_8c8e8be.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_8d53abb.pf_fragment b/pagefind/fragment/zh-cn_8d53abb.pf_fragment deleted file mode 100644 index bd158baa0f..0000000000 Binary files a/pagefind/fragment/zh-cn_8d53abb.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_8dcd37a.pf_fragment b/pagefind/fragment/zh-cn_8dcd37a.pf_fragment new file mode 100644 index 0000000000..1b0dd27ad0 Binary files /dev/null and b/pagefind/fragment/zh-cn_8dcd37a.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_964a4fd.pf_fragment b/pagefind/fragment/zh-cn_964a4fd.pf_fragment new file mode 100644 index 0000000000..46270b9d83 Binary files /dev/null and b/pagefind/fragment/zh-cn_964a4fd.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_a47bf58.pf_fragment b/pagefind/fragment/zh-cn_99e62b8.pf_fragment similarity index 88% rename from pagefind/fragment/zh-cn_a47bf58.pf_fragment rename to pagefind/fragment/zh-cn_99e62b8.pf_fragment index df395a8114..b0949ec6aa 100644 Binary files a/pagefind/fragment/zh-cn_a47bf58.pf_fragment and b/pagefind/fragment/zh-cn_99e62b8.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_3aa282b.pf_fragment b/pagefind/fragment/zh-cn_ad77d75.pf_fragment similarity index 83% rename from pagefind/fragment/zh-cn_3aa282b.pf_fragment rename to pagefind/fragment/zh-cn_ad77d75.pf_fragment index 2994db4c50..03d7817dbc 100644 Binary files a/pagefind/fragment/zh-cn_3aa282b.pf_fragment and b/pagefind/fragment/zh-cn_ad77d75.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_af6e5c4.pf_fragment b/pagefind/fragment/zh-cn_af6e5c4.pf_fragment new file mode 100644 index 0000000000..30c445ab99 Binary files /dev/null and b/pagefind/fragment/zh-cn_af6e5c4.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_25694d5.pf_fragment b/pagefind/fragment/zh-cn_b2e449c.pf_fragment similarity index 92% rename from pagefind/fragment/zh-cn_25694d5.pf_fragment rename to pagefind/fragment/zh-cn_b2e449c.pf_fragment index d18837d5ed..85cb234633 100644 Binary files a/pagefind/fragment/zh-cn_25694d5.pf_fragment and b/pagefind/fragment/zh-cn_b2e449c.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_bc27649.pf_fragment b/pagefind/fragment/zh-cn_bc27649.pf_fragment new file mode 100644 index 0000000000..8b6226e438 Binary files /dev/null and b/pagefind/fragment/zh-cn_bc27649.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_c11a8a7.pf_fragment b/pagefind/fragment/zh-cn_c11a8a7.pf_fragment deleted file mode 100644 index 82f9ea4587..0000000000 Binary files a/pagefind/fragment/zh-cn_c11a8a7.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_c999918.pf_fragment b/pagefind/fragment/zh-cn_c999918.pf_fragment new file mode 100644 index 0000000000..af9850b644 Binary files /dev/null and b/pagefind/fragment/zh-cn_c999918.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_d04ce0b.pf_fragment b/pagefind/fragment/zh-cn_d04ce0b.pf_fragment deleted file mode 100644 index 739e2e2ac8..0000000000 Binary files a/pagefind/fragment/zh-cn_d04ce0b.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_ec79f02.pf_fragment b/pagefind/fragment/zh-cn_ec79f02.pf_fragment new file mode 100644 index 0000000000..7779eac22d Binary files /dev/null and b/pagefind/fragment/zh-cn_ec79f02.pf_fragment differ diff --git a/pagefind/fragment/zh-cn_edddd73.pf_fragment b/pagefind/fragment/zh-cn_edddd73.pf_fragment deleted file mode 100644 index a03141e31b..0000000000 Binary files a/pagefind/fragment/zh-cn_edddd73.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_ee19938.pf_fragment b/pagefind/fragment/zh-cn_ee19938.pf_fragment deleted file mode 100644 index 37a05b4bef..0000000000 Binary files a/pagefind/fragment/zh-cn_ee19938.pf_fragment and /dev/null differ diff --git a/pagefind/fragment/zh-cn_61c34a2.pf_fragment b/pagefind/fragment/zh-cn_f260254.pf_fragment similarity index 86% rename from pagefind/fragment/zh-cn_61c34a2.pf_fragment rename to pagefind/fragment/zh-cn_f260254.pf_fragment index 471d2d1069..0d4818200f 100644 Binary files a/pagefind/fragment/zh-cn_61c34a2.pf_fragment and b/pagefind/fragment/zh-cn_f260254.pf_fragment differ diff --git a/pagefind/pagefind-entry.json b/pagefind/pagefind-entry.json index 964cadb89a..d7975f7557 100644 --- a/pagefind/pagefind-entry.json +++ b/pagefind/pagefind-entry.json @@ -1 +1 @@ -{"version":"1.1.1","languages":{"zh-cn":{"hash":"zh-cn_8312be599cd33","wasm":null,"page_count":72},"en":{"hash":"en_6eed3d3977","wasm":"en","page_count":64}}} \ No newline at end of file +{"version":"1.1.1","languages":{"en":{"hash":"en_5a3caae56f","wasm":"en","page_count":64},"zh-cn":{"hash":"zh-cn_1f13bfc2f3221","wasm":null,"page_count":72}}} \ No newline at end of file diff --git a/pagefind/pagefind.en_5a3caae56f.pf_meta b/pagefind/pagefind.en_5a3caae56f.pf_meta new file mode 100644 index 0000000000..34ffeead60 Binary files /dev/null and b/pagefind/pagefind.en_5a3caae56f.pf_meta differ diff --git a/pagefind/pagefind.en_6eed3d3977.pf_meta b/pagefind/pagefind.en_6eed3d3977.pf_meta deleted file mode 100644 index f83e09b0d3..0000000000 Binary files a/pagefind/pagefind.en_6eed3d3977.pf_meta and /dev/null differ diff --git a/pagefind/pagefind.zh-cn_1f13bfc2f3221.pf_meta b/pagefind/pagefind.zh-cn_1f13bfc2f3221.pf_meta new file mode 100644 index 0000000000..ae716ffac9 Binary files /dev/null and b/pagefind/pagefind.zh-cn_1f13bfc2f3221.pf_meta differ diff --git a/pagefind/pagefind.zh-cn_8312be599cd33.pf_meta b/pagefind/pagefind.zh-cn_8312be599cd33.pf_meta deleted file mode 100644 index d7baa3abb5..0000000000 Binary files a/pagefind/pagefind.zh-cn_8312be599cd33.pf_meta and /dev/null differ diff --git a/src/article/astParse/tokenizer.html b/src/article/astParse/tokenizer.html index 87f606a012..ce8aa1479a 100644 --- a/src/article/astParse/tokenizer.html +++ b/src/article/astParse/tokenizer.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -226,8 +226,8 @@ { type: 'RightParen', value: ')', start: 17, end: 18 }, { type: 'LeftCurly', value: '{', start: 19, end: 20 }, { type: 'RightCurly', value: '}', start: 20, end: 21 }, -];

一个简易版本的分词器已经被我们开发出来了,不过目前的分词器还比较简陋,仅仅支持有限的语法,不过在明确了核心的开发步骤之后,后面继续完善的过程就比较简单了。

四。编写语法分析器(Parser)

在解析出词法 token 之后,我们就可以进入语法分析阶段了。在这个阶段,我们会依次遍历 token ,对代码进行语法结构层面的分析,最后的目标是生成 AST 数据结构。至于代码的 AST 结构到底是什么样子,你可以去 AST Explorer 网站进行在线预览:

接下来,我们要做的就是将 token 数组转换为上图所示的 AST 数据。

开发步骤主要分为:

- +];

一个简易版本的分词器已经被我们开发出来了,不过目前的分词器还比较简陋,仅仅支持有限的语法,不过在明确了核心的开发步骤之后,后面继续完善的过程就比较简单了。

四。编写语法分析器(Parser)

在解析出词法 token 之后,我们就可以进入语法分析阶段了。在这个阶段,我们会依次遍历 token ,对代码进行语法结构层面的分析,最后的目标是生成 AST 数据结构。至于代码的 AST 结构到底是什么样子,你可以去 AST Explorer 网站进行在线预览:

接下来,我们要做的就是将 token 数组转换为上图所示的 AST 数据。

开发步骤主要分为:

+ \ No newline at end of file diff --git a/src/article/babel.html b/src/article/babel.html index 09ef80ec26..aba15b1c1d 100644 --- a/src/article/babel.html +++ b/src/article/babel.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

Babel

babel 核心库主要是:

  • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
  • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
  • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
  • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
  • @babel/code-frame 可以创建友好的报错信息
  • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
  • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。

Released under the MIT License.

- +
Skip to content

Babel

babel 核心库主要是:

  • @babel/parser 对源码进行 parse,可以通过 plugins、sourceType 等来指定 parse 语法,功能是把源码转成 AST。
  • @babel/traverse 通过 visitor 函数对遍历到的 ast 进行处理,分为 enter 和 exit 两个阶段,具体操作 AST 使用 path 的 api,还可以通过 state 来在遍历过程中传递一些数据
  • @babel/types 用于创建、判断 AST 节点,提供了 xxx、isXxx、assertXxx 的 api
  • @babel/template 当需要批量创建 AST 的时候可以使用 @babel/template 来简化 AST 创建逻辑。
  • @babel/code-frame 可以创建友好的报错信息
  • @babel/generator 打印 AST 成目标代码字符串,支持 comments、minified、sourceMaps 等选项。
  • @babel/core 基于上面的包来完成 babel 的编译流程,并应用 plugin 和 preset。

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/article/bundle.html b/src/article/bundle.html index de5403a750..8036cef292 100644 --- a/src/article/bundle.html +++ b/src/article/bundle.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

Bundle

Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:

  • 编译能力
  • 插件机制
  • HMR
  • cli 和命令行能力

Released under the MIT License.

- +
Skip to content

Bundle

Bundle 的本质就是输入,转换,输出。在机器上直接运行的代码,往往都难以维护和理解,我们需要将开发者方便理解和维护的代码,通过打包等工具转换成方便机器或者程序使用的代码。对于 web 前端来说,打包工具,至少需要以下功能:

  • 编译能力
  • 插件机制
  • HMR
  • cli 和命令行能力

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/article/designMode.html b/src/article/designMode.html index 2484e5c40b..836df5e7b1 100644 --- a/src/article/designMode.html +++ b/src/article/designMode.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -785,8 +785,8 @@ Visitor.push(a,1,2,3,4); Visitor.push(a,4,5,6); Visitor.pop(a); -Visitor.splice(a,2);

The visitor pattern solves the coupling between the data and the manipulation of the data, making the manipulation of the data independent of the data, so that it can freely evolve. Therefore, the visitor pattern is more suitable for those environments where the data is stable but the data manipulation method is variable.

Advantages:

Disadvantage:

VII.Sum up

After systematically studying design patterns, you can see in your past development experience that design patterns are everywhere. Before learning design patterns, we often rely on past experience and wisdom to improve the design of a system, and many of these experiences coincide with the idea of a certain design pattern.

There are still some places that are not fully understood, and I would like to point out the mistakes in the article.

VIII.Reference material

- +Visitor.splice(a,2);

The visitor pattern solves the coupling between the data and the manipulation of the data, making the manipulation of the data independent of the data, so that it can freely evolve. Therefore, the visitor pattern is more suitable for those environments where the data is stable but the data manipulation method is variable.

Advantages:

Disadvantage:

VII.Sum up

After systematically studying design patterns, you can see in your past development experience that design patterns are everywhere. Before learning design patterns, we often rely on past experience and wisdom to improve the design of a system, and many of these experiences coincide with the idea of a certain design pattern.

There are still some places that are not fully understood, and I would like to point out the mistakes in the article.

VIII.Reference material

+ \ No newline at end of file diff --git a/src/article/functionalProgramming.html b/src/article/functionalProgramming.html index fe3f1b51c9..d1e9c6337b 100644 --- a/src/article/functionalProgramming.html +++ b/src/article/functionalProgramming.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -379,8 +379,8 @@ }; let r = readFile('package.json') //这里可以用 map 去处理内容 .flatMap(print) - .join();

参考资料

- + .join();

参考资料

+ \ No newline at end of file diff --git a/src/article/imagemin.html b/src/article/imagemin.html index 91b19ff7ef..4b96878578 100644 --- a/src/article/imagemin.html +++ b/src/article/imagemin.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

imagemin 图片压缩源码分析

Released under the MIT License.

- +
Skip to content

imagemin 图片压缩源码分析

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/article/javascript/domLoad.html b/src/article/javascript/domLoad.html index d0b4943bc0..5941b118a9 100644 --- a/src/article/javascript/domLoad.html +++ b/src/article/javascript/domLoad.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -44,8 +44,8 @@
Skip to content

页面加载完成后事件

window.onload

DOMContentLoaded

js
document.addEventListener('DOMContentLoaded', fun);

<body onload="fun()">

readyState

js
document.readyState;
 
-document.onreadystatechange;

一个文档的 readyState 可以是以下之一:

  • loading / 加载。document 仍在加载。
  • interactive / 互动。文档已经完成加载,文档已被解析,但是诸如图像,样式表和框架之类的子资源仍在加载。
  • complete / 完成。T 文档和所有子资源已完成加载。状态表示 load 事件即将被触发。

Released under the MIT License.

- +document.onreadystatechange;

一个文档的 readyState 可以是以下之一:

+ \ No newline at end of file diff --git a/src/article/sort/bubble/index.html b/src/article/sort/bubble/index.html index 0f6b452337..30b96de448 100644 --- a/src/article/sort/bubble/index.html +++ b/src/article/sort/bubble/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -55,8 +55,8 @@ } } return list; -}; - +}; + \ No newline at end of file diff --git a/src/article/sort/bucket/index.html b/src/article/sort/bucket/index.html index 34b7bb1025..ab4782fe69 100644 --- a/src/article/sort/bucket/index.html +++ b/src/article/sort/bucket/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -98,8 +98,8 @@ list = list.concat(count(buckets[i])); } return list; -};

Algorithm analysis

Bucket sorting best uses linear time O(n), and the time complexity of bucket sorting depends on the time complexity of sorting data between buckets, because the time complexity of other parts is O(n). Obviously, the smaller the buckets, the less data there is between them, and the less time it takes to sort them. But the corresponding space consumption will increase.

- +};

Algorithm analysis

Bucket sorting best uses linear time O(n), and the time complexity of bucket sorting depends on the time complexity of sorting data between buckets, because the time complexity of other parts is O(n). Obviously, the smaller the buckets, the less data there is between them, and the less time it takes to sort them. But the corresponding space consumption will increase.

+ \ No newline at end of file diff --git a/src/article/sort/count/index.html b/src/article/sort/count/index.html index 0b0e208cb0..06e5ec3b15 100644 --- a/src/article/sort/count/index.html +++ b/src/article/sort/count/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -76,8 +76,8 @@ } } return result; -};

Algorithm analysis

Counting sort is a stable sorting algorithm. When the input elements are n integers between 0 and k, the time complexity is O(n+k) and the space complexity is also O(n+k), which sorts faster than any comparison sorting algorithm. Counting sort is an efficient sorting algorithm when k is not large and the sequence is concentrated.

- +};

Algorithm analysis

Counting sort is a stable sorting algorithm. When the input elements are n integers between 0 and k, the time complexity is O(n+k) and the space complexity is also O(n+k), which sorts faster than any comparison sorting algorithm. Counting sort is an efficient sorting algorithm when k is not large and the sequence is concentrated.

+ \ No newline at end of file diff --git a/src/article/sort/heap/index.html b/src/article/sort/heap/index.html index 927725a1ce..fdcf85f64e 100644 --- a/src/article/sort/heap/index.html +++ b/src/article/sort/heap/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -92,8 +92,8 @@ const heap = (list: Array<number>): Array<number> => { const { value } = new Heap(list); return value; -}; - +}; + \ No newline at end of file diff --git a/src/article/sort/index.html b/src/article/sort/index.html index 52489abd7d..0aec429acb 100644 --- a/src/article/sort/index.html +++ b/src/article/sort/index.html @@ -13,7 +13,7 @@ - + @@ -37,14 +37,14 @@ - + -
Skip to content

Ten classic sorting algorithms

The ten common sorting algorithms can be divided into two broad categories:

  • Comparator sort:By comparison to determine the relative order between elements, because its time complexity can not break through O(nlogn), so it is also called nonlinear time comparison class sorting.
  • Non-comparison sort:Instead of determining the relative order between elements by comparison, it can break through the time lower bound based on comparison sort and run in linear time, so it is also called linear time non-comparison sort.

Sorting algorithm classification

Algorithm complexity

Algorithm complexity

  • Stable: If a was originally in front of b and a=b, a is still in front of b after sorting.
  • Unstable: If a originally comes before b and a=b, a may come after b after sorting.
  • Time complexity: The total number of operations on sorted data. Reflects what rule the number of operations presents when n changes.
  • Spatial complexity: refers to the measure of the storage space required when the algorithm is executed in the computer, and it is also a function of the data size n.

Released under the MIT License.

- +
Skip to content

Ten classic sorting algorithms

The ten common sorting algorithms can be divided into two broad categories:

  • Comparator sort:By comparison to determine the relative order between elements, because its time complexity can not break through O(nlogn), so it is also called nonlinear time comparison class sorting.
  • Non-comparison sort:Instead of determining the relative order between elements by comparison, it can break through the time lower bound based on comparison sort and run in linear time, so it is also called linear time non-comparison sort.

Sorting algorithm classification

Algorithm complexity

Algorithm complexity

  • Stable: If a was originally in front of b and a=b, a is still in front of b after sorting.
  • Unstable: If a originally comes before b and a=b, a may come after b after sorting.
  • Time complexity: The total number of operations on sorted data. Reflects what rule the number of operations presents when n changes.
  • Spatial complexity: refers to the measure of the storage space required when the algorithm is executed in the computer, and it is also a function of the data size n.

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/article/sort/insert/index.html b/src/article/sort/insert/index.html index 2e3cbb180e..f66fff34af 100644 --- a/src/article/sort/insert/index.html +++ b/src/article/sort/insert/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -55,8 +55,8 @@ list[preIndex + 1] = current; } return list; -};

Algorithm analysis

Insertion sort in the implementation, usually use in-place sort (that is, only need to use O(1) of the additional space of the sort), so in the process of scanning from back to forward, the sorted elements need to be repeatedly moved backward step by step, to provide insertion space for the latest elements.

- +};

Algorithm analysis

Insertion sort in the implementation, usually use in-place sort (that is, only need to use O(1) of the additional space of the sort), so in the process of scanning from back to forward, the sorted elements need to be repeatedly moved backward step by step, to provide insertion space for the latest elements.

+ \ No newline at end of file diff --git a/src/article/sort/merge/index.html b/src/article/sort/merge/index.html index d9bca566aa..049b65c603 100644 --- a/src/article/sort/merge/index.html +++ b/src/article/sort/merge/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -75,8 +75,8 @@ const left = list.slice(0, middle); const right = list.slice(middle); return combine(merge(left), merge(right)); -};

Algorithm analysis

Merge sort is a stable sort method. Like select sort, merge sort performs independently of the input data, but performs much better than select sort because it is always O(nlogn) in time complexity. The trade-off is extra memory space.

- +};

Algorithm analysis

Merge sort is a stable sort method. Like select sort, merge sort performs independently of the input data, but performs much better than select sort because it is always O(nlogn) in time complexity. The trade-off is extra memory space.

+ \ No newline at end of file diff --git a/src/article/sort/quick/index.html b/src/article/sort/quick/index.html index 7a268f375e..286e7810b0 100644 --- a/src/article/sort/quick/index.html +++ b/src/article/sort/quick/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -93,8 +93,8 @@ const quick = (list: number[] = []): number[] => { const size = list.length; return combine(list, 0, size - 1); -}; - +}; + \ No newline at end of file diff --git a/src/article/sort/radix/index.html b/src/article/sort/radix/index.html index 1c45f7cc16..186505255b 100644 --- a/src/article/sort/radix/index.html +++ b/src/article/sort/radix/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -78,8 +78,8 @@ list = list.concat(count(buckets[i])); } return list; -};

Algorithm analysis

Radix sort is based on distributive sort, so it is stable. But the performance of radix sort is slightly worse than bucket sort, each keyword bucket allocation requires O(n) time complexity, and after allocation to get a new keyword sequence requires O(n) time complexity. If the data to be sorted can be divided into d keywords, the time complexity of radix sort will be O(d*2n), of course, d is far less than n, so it is basically linear level.

The spatial complexity of radix sort is O(n+k), where k is the number of buckets. Generally speaking, n> > k, so you need about n extra Spaces.

- +};

Algorithm analysis

Radix sort is based on distributive sort, so it is stable. But the performance of radix sort is slightly worse than bucket sort, each keyword bucket allocation requires O(n) time complexity, and after allocation to get a new keyword sequence requires O(n) time complexity. If the data to be sorted can be divided into d keywords, the time complexity of radix sort will be O(d*2n), of course, d is far less than n, so it is basically linear level.

The spatial complexity of radix sort is O(n+k), where k is the number of buckets. Generally speaking, n> > k, so you need about n extra Spaces.

+ \ No newline at end of file diff --git a/src/article/sort/select/index.html b/src/article/sort/select/index.html index b21f7aa920..0cbeeb3bae 100644 --- a/src/article/sort/select/index.html +++ b/src/article/sort/select/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -59,8 +59,8 @@ } } return list; -};

Algorithm analysis

One of the most stable sorting algorithms, because whatever data goes in is O(n2) time complexity, so when using it, the smaller the data size, the better. The only benefit may be that it doesn't take up extra memory space. In theory, selection sorting may also be the most common sorting method that people think of.

- +};

Algorithm analysis

One of the most stable sorting algorithms, because whatever data goes in is O(n2) time complexity, so when using it, the smaller the data size, the better. The only benefit may be that it doesn't take up extra memory space. In theory, selection sorting may also be the most common sorting method that people think of.

+ \ No newline at end of file diff --git a/src/article/sort/shell/index.html b/src/article/sort/shell/index.html index fe841196c2..0d7d414e3e 100644 --- a/src/article/sort/shell/index.html +++ b/src/article/sort/shell/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -62,8 +62,8 @@ } } return list; -};

Algorithm analysis

The core of Hill sort is the setting of interval sequence. The interval sequence can be set in advance, and the interval sequence can be defined dynamically. The algorithm for dynamically defining interval sequences was developed by Robert Sedgewick, co-author of Algorithms (4th Edition).

- +};

Algorithm analysis

The core of Hill sort is the setting of interval sequence. The interval sequence can be set in advance, and the interval sequence can be defined dynamically. The algorithm for dynamically defining interval sequences was developed by Robert Sedgewick, co-author of Algorithms (4th Edition).

+ \ No newline at end of file diff --git a/src/article/typescript/calculate.html b/src/article/typescript/calculate.html index 988ddfa708..2f70de5db0 100644 --- a/src/article/typescript/calculate.html +++ b/src/article/typescript/calculate.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -72,8 +72,8 @@ ? CurrentArr['length'] : FibonacciLoop<CurrentArr, [...PrevArr, ...CurrentArr], [...IndexArr, unknown], Num>; -type Fibonacci<Num extends number> = FibonacciLoop<[1], [], [], Num>;

类型参数 PrevArr 是代表之前的累加值的数组。类型参数 CurrentArr 是代表当前数值的数组。

类型参数 IndexArr 用于记录 index,每次递归加一,默认值是 [],代表从 0 开始。

类型参数 Num 代表求数列的第几个数。

判断当前 index 也就是 IndexArr['length'] 是否到了 Num,到了就返回当前的数值 CurrentArr['length']。

否则求出当前 index 对应的数值,用之前的数加上当前的数 [...PrevArr, ... CurrentArr]。

然后继续递归,index + 1,也就是 [...IndexArr, unknown]。

这就是递归计算 Fibinacci 数列的数的过程。

可以正确的算出第 8 个数是 21:

- +type Fibonacci<Num extends number> = FibonacciLoop<[1], [], [], Num>;

类型参数 PrevArr 是代表之前的累加值的数组。类型参数 CurrentArr 是代表当前数值的数组。

类型参数 IndexArr 用于记录 index,每次递归加一,默认值是 [],代表从 0 开始。

类型参数 Num 代表求数列的第几个数。

判断当前 index 也就是 IndexArr['length'] 是否到了 Num,到了就返回当前的数值 CurrentArr['length']。

否则求出当前 index 对应的数值,用之前的数加上当前的数 [...PrevArr, ... CurrentArr]。

然后继续递归,index + 1,也就是 [...IndexArr, unknown]。

这就是递归计算 Fibinacci 数列的数的过程。

可以正确的算出第 8 个数是 21:

+ \ No newline at end of file diff --git a/src/article/typescript/index.html b/src/article/typescript/index.html index 7624bd7cd9..f7cbaef503 100644 --- a/src/article/typescript/index.html +++ b/src/article/typescript/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -197,8 +197,8 @@ type TestAnyResult = TestAny<any>; // type TestAnyResult = 1 | 2

联合类型、never、any 在作为条件类型的类型参数时的这些特殊情况,也会在后面的原理篇来解释原因。

IsTuple

元组类型怎么判断呢?它和数组有什么区别呢?

元组类型的 length 是数字字面量,而数组的 length 是 number。

ts
type len

UnionToIntersection

类型之间是有父子关系的,更具体的那个是子类型,比如 A 和 B 的交叉类型 A & B 就是联合类型 A | B 的子类型,因为更具体。

如果允许父类型赋值给子类型,就叫做逆变

如果允许子类型赋值给父类型,就叫做协变

(关于逆变、协变等概念的详细解释可以看原理篇)

在 TypeScript 中有函数参数是有逆变的性质的,也就是如果参数可能是多个类型,参数类型会变成它们的交叉类型。

所以联合转交叉可以这样实现:

ts
type UnionToIntersection<U> = (U extends U ? (x: U) => unknown : never) extends (x: infer R) => unknown ? R : never;

类型参数 U 是要转换的联合类型。

U extends U 是为了触发联合类型的 distributive 的性质,让每个类型单独传入做计算,最后合并。

利用 U 做为参数构造个函数,通过模式匹配取参数的类型。

结果就是交叉类型

函数参数的逆变性质一般就联合类型转交叉类型会用,记住就行。

GetOptional

如何提取索引类型中的可选索引呢?

这也要利用可选索引的特性:可选索引的值为 undefined 和值类型的联合类型。

过滤可选索引,就要构造一个新的索引类型,过程中做过滤:

ts
type GetOptional<Obj extends Record<string, any>> = {
   [Key in keyof Obj as {} extends Pick<Obj, Key> ? Key : never]: Obj[Key];
-};

类型参数 Obj 为待处理的索引类型,类型约束为索引为 string、值为任意类型的索引类型 Record<string, any>。

用映射类型的语法重新构造索引类型,索引是之前的索引也就是 Key in keyof Obj,但要做一些过滤,也就是 as 之后的部分。

过滤的方式就是单独取出该索引之后,判断空对象是否是其子类型。

这里的 Pick 是 ts 提供的内置高级类型,就是取出某个 Key 构造新的索引类型:

ts
type Pick<T, K extends keyof T> = { [P in K]: T[P] };

比如单独取出 age 构造的新的索引类型是这样的:

可选的意思是这个索引可能没有,没有的时候,那 Pick<Obj, Key> 就是空的,所以 {} extends Pick<Obj, Key> 就能过滤出可选索引。

值的类型依然是之前的,也就是 Obj[Key]。

这样,就能过滤出所有可选索引,构造成新的索引类型:

总结

- +};

类型参数 Obj 为待处理的索引类型,类型约束为索引为 string、值为任意类型的索引类型 Record<string, any>。

用映射类型的语法重新构造索引类型,索引是之前的索引也就是 Key in keyof Obj,但要做一些过滤,也就是 as 之后的部分。

过滤的方式就是单独取出该索引之后,判断空对象是否是其子类型。

这里的 Pick 是 ts 提供的内置高级类型,就是取出某个 Key 构造新的索引类型:

ts
type Pick<T, K extends keyof T> = { [P in K]: T[P] };

比如单独取出 age 构造的新的索引类型是这样的:

可选的意思是这个索引可能没有,没有的时候,那 Pick<Obj, Key> 就是空的,所以 {} extends Pick<Obj, Key> 就能过滤出可选索引。

值的类型依然是之前的,也就是 Obj[Key]。

这样,就能过滤出所有可选索引,构造成新的索引类型:

总结

+ \ No newline at end of file diff --git a/src/article/typescript/pattern.html b/src/article/typescript/pattern.html index 982abb2989..f92571aba4 100644 --- a/src/article/typescript/pattern.html +++ b/src/article/typescript/pattern.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -134,8 +134,8 @@ : never : never;

类型参数 Props 为待处理的类型。

通过 keyof Props 取出 Props 的所有索引构成的联合类型,判断下 ref 是否在其中,也就是 'ref' extends keyof Props。

为什么要做这个判断,上面注释里写了:

在 ts3.0 里面如果没有对应的索引,Obj[Key] 返回的是 {} 而不是 never,所以这样做下兼容处理。

如果有 ref 这个索引的话,就通过 infer 提取 Value 的类型返回,否则返回 never。

ts
type GetPropsRefResult = GetPropsRef<{ ref: 1; name: 'str' }>;
 // type GetPropsRefResult = 1

当 ref 为 undefined 时:

ts
type GetPropsRefResult = GetPropsRef<{ ref: undefined; name: 'str' }>;
-// type GetPropsRefResult = undefined
- +// type GetPropsRefResult = undefined + \ No newline at end of file diff --git a/src/article/typescript/reconstruction.html b/src/article/typescript/reconstruction.html index bb6a7db4e4..e397333920 100644 --- a/src/article/typescript/reconstruction.html +++ b/src/article/typescript/reconstruction.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -89,8 +89,8 @@ [Key in keyof T]-?: T[Key]; };

给索引类型 T 的索引去掉 ? 的修饰,其余保持不变。

FilterByValueType

可以在构造新索引类型的时候根据值的类型做下过滤:

ts
type FilterByValueType<Obj extends Record<string, any>, ValueType> = {
   [Key in keyof Obj as Obj[Key] extends ValueType ? Key : never]: Obj[Key];
-};

类型参数 Obj 为要处理的索引类型,通过 extends 约束为索引为 string,值为任意类型的索引类型 Record<string, any>。

类型参数 ValueType 为要过滤出的值的类型。

构造新的索引类型,索引为 Obj 的索引,也就是 Key in keyof Obj,但要做一些变换,也就是 as 之后的部分。

如果原来索引的值 Obj[Key] 是 ValueType 类型,索引依然为之前的索引 Key,否则索引设置为 never,never 的索引会在生成新的索引类型时被去掉。

值保持不变,依然为原来索引的值,也就是 Obj[Key]。

这样就达到了过滤索引类型的索引,产生新的索引类型的目的:

- +};

类型参数 Obj 为要处理的索引类型,通过 extends 约束为索引为 string,值为任意类型的索引类型 Record<string, any>。

类型参数 ValueType 为要过滤出的值的类型。

构造新的索引类型,索引为 Obj 的索引,也就是 Key in keyof Obj,但要做一些变换,也就是 as 之后的部分。

如果原来索引的值 Obj[Key] 是 ValueType 类型,索引依然为之前的索引 Key,否则索引设置为 never,never 的索引会在生成新的索引类型时被去掉。

值保持不变,依然为原来索引的值,也就是 Obj[Key]。

这样就达到了过滤索引类型的索引,产生新的索引类型的目的:

+ \ No newline at end of file diff --git a/src/article/typescript/recursion.html b/src/article/typescript/recursion.html index d534b00927..b2581dc257 100644 --- a/src/article/typescript/recursion.html +++ b/src/article/typescript/recursion.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -106,8 +106,8 @@ : DeepReadonly<Obj[Key]> : Obj[Key]; } - : never; - + : never; + \ No newline at end of file diff --git a/src/article/typescript/unionType.html b/src/article/typescript/unionType.html index e5d0cd37f2..0db591d7d8 100644 --- a/src/article/typescript/unionType.html +++ b/src/article/typescript/unionType.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -62,8 +62,8 @@ > = `${Block}__${Element[number]}--${Modifiers[number]}`;

类型参数 Block、Element、Modifiers 分别是 bem 规范的三部分,其中 Element 和 Modifiers 都可能多个,约束为 string[]。

构造一个字符串类型,其中 Element 和 Modifiers 通过索引访问来变为联合类型。

字符串类型中遇到联合类型的时候,会每个元素单独传入计算,也就是这样的效果:

ts
type RemResult = BEM<'a', ['b', 'c'], ['d', 'e']>;
 // type RemResult = 'a__b--d' | 'a__b--e' | 'a__c--d' | 'a__b--e'

可以看到,用好了联合类型,确实能简化类型编程逻辑。

AllCombinations

我们再来实现一个全组合的高级类型,也是联合类型相关的:

希望传入 'A' | 'B' 的时候,能够返回所有的组合: 'A' | 'B' | 'BA' | 'AB'。

这种全组合问题的实现思路就是两两组合,组合出的字符串再和其他字符串两两组和:

比如 'A' | 'B' | 'c',就是 A 和 B、C 组合,B 和 A、C 组合,C 和 A、B 组合。然后组合出来的字符串再和其他字符串组合。

任何两个类型的组合有四种:A、B、AB、BA

ts
type Combination<A extends string, B extends string> = A | B | `${A}${B}` | `${B}${A}`;

然后构造出来的字符串再和其他字符串组合。

所以全组合的高级类型就是这样:

ts
type AllCombinations<A extends string, B extends string = A> = A extends A
   ? Combination<A, AllCombinations<Exclude<B, A>>>
-  : never;

类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

总结

联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

有两点特别要注意:

我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

- + : never;

类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。

A extends A 的意义就是让联合类型每个类型单独传入做处理,上面我们刚学会。

A 的处理就是 A 和 B 中去掉 A 以后的所有类型组合,也就是 Combination<A, B 去掉 A 以后的所有组合>。

而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>,所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。

总结

联合类型中的每个类型都是相互独立的,TypeScript 对它做了特殊处理,也就是遇到字符串类型、条件类型的时候会把每个类型单独传入做计算,最后把每个类型的计算结果合并成联合类型。

条件类型左边是联合类型的时候就会触法这种处理,叫做分布式条件类型。

有两点特别要注意:

我们后面做了一些案例,发现联合类型的这种 distributive 的特性确实能简化类型编程,但是也增加了认知成本,不过这也是不可避免的事。

+ \ No newline at end of file diff --git a/src/ranui/button/index.html b/src/ranui/button/index.html index d3a6b80ff1..70c6d51bb9 100644 --- a/src/ranui/button/index.html +++ b/src/ranui/button/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -50,8 +50,8 @@ <r-button type="text" disabled>Text button</r-button> <r-button disabled>Default button</r-button>

icon

When you need to embed an Icon inside a Button, you can set the icon property or use the Icon component directly inside a Button.

If you want to control the specific position of the Icon, you can only use the Icon component directly, not the icon property.

Default button
Primary button
xml
<r-button type="default" icon="user">Default button</r-button>
 <r-button type="primary" icon="home">Primary button</r-button>

特效 effect

If you want a pure Button, you can add effect = false to block the water ripple effect when clicked

Default buttonPrimary button
xml
<r-button type="default" icon="user">Default button</r-button>
-<r-button type="primary" icon="home">Primary button</r-button>
- +<r-button type="primary" icon="home">Primary button</r-button> + \ No newline at end of file diff --git a/src/ranui/checkbox/index.html b/src/ranui/checkbox/index.html index 9a7351ce90..ab4b0e7bc5 100644 --- a/src/ranui/checkbox/index.html +++ b/src/ranui/checkbox/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -45,8 +45,8 @@
Skip to content

CheckBox

Code demo

xml
 <r-checkbox ></r-checkbox>

Attribute

checked

xml
 <r-checkbox checked="true"></r-checkbox>
  <r-checkbox checked="false"></r-checkbox>

disabled

xml
 <r-checkbox checked="true" disabled></r-checkbox>
  <r-checkbox checked="false" disabled></r-checkbox>

event

Common callback events.

onchange

xml
 <r-checkbox onchange="console.log(this.checked)"></r-checkbox>
- <r-checkbox onchange="console.log(this.checked)"></r-checkbox>

Released under the MIT License.

- + <r-checkbox onchange="console.log(this.checked)"></r-checkbox> + \ No newline at end of file diff --git a/src/ranui/icon/index.html b/src/ranui/icon/index.html index 8baf31fb29..4e8177123e 100644 --- a/src/ranui/icon/index.html +++ b/src/ranui/icon/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -53,8 +53,8 @@ <r-icon name="lock" size="50" color="#F44336"></r-icon> <r-icon name="lock" size="50" color="#3F51B5"></r-icon>

spin

Set spin to turn on the rotation, and pass in a number to control the rotation speed. The smaller the number, the faster the rotation

html
<r-icon name="loading" size="50" color="#1E90FF" spin="0.7"></r-icon>
 <r-icon name="loading" size="50" color="#1E90FF" spin></r-icon>
-<r-icon name="loading" size="50" color="#1E90FF" spin="5"></r-icon>

Icon list

- +<r-icon name="loading" size="50" color="#1E90FF" spin="5"></r-icon>

Icon list

+ \ No newline at end of file diff --git a/src/ranui/image/index.html b/src/ranui/image/index.html index 33d74bc164..b7d9a0fcb5 100644 --- a/src/ranui/image/index.html +++ b/src/ranui/image/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

Image

Code demo

xml
 <r-img src="" fallback=""></r-img>

Attribute

src

Image address

Image loading failurefallback

srcConfiguration of the picture loading failure, the bottom of the picture address, the following is the default loading failure picture

Released under the MIT License.

- +
Skip to content

Image

Code demo

xml
 <r-img src="" fallback=""></r-img>

Attribute

src

Image address

Image loading failurefallback

srcConfiguration of the picture loading failure, the bottom of the picture address, the following is the default loading failure picture

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranui/index.html b/src/ranui/index.html index c77bcf2427..2b0b27b940 100644 --- a/src/ranui/index.html +++ b/src/ranui/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -127,8 +127,8 @@ percent="0.70" type="drag" style="--ran-progress-wrap-background:linear-gradient(to right, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);" -></r-progress>

For specific CSS3 variable names, refer to the introduction and description of each component.

Compatibility

Contributors

Other

  1. 优秀的组件设计
  2. 在线生成 CSS 渐变色
  3. 优秀设计作品,有 psd 和 sketch
  4. 3D UI 设计,类似于 3D 版的 figma
  5. 设计规范
  6. 优秀设计作品
  7. element UI 中文网
  8. Ant design 中文网
  9. 在线绘制 CSS 动画
  10. tailwindcss
  11. animate css
  12. can i use
  13. figma

Protocols and standards

  1. RFCs
  2. ECMA
  3. w3c
- +></r-progress>

For specific CSS3 variable names, refer to the introduction and description of each component.

Compatibility

Contributors

Other

  1. 优秀的组件设计
  2. 在线生成 CSS 渐变色
  3. 优秀设计作品,有 psd 和 sketch
  4. 3D UI 设计,类似于 3D 版的 figma
  5. 设计规范
  6. 优秀设计作品
  7. element UI 中文网
  8. Ant design 中文网
  9. 在线绘制 CSS 动画
  10. tailwindcss
  11. animate css
  12. can i use
  13. figma

Protocols and standards

  1. RFCs
  2. ECMA
  3. w3c
+ \ No newline at end of file diff --git a/src/ranui/input/index.html b/src/ranui/input/index.html index 39e79e51e3..858d5f9efb 100644 --- a/src/ranui/input/index.html +++ b/src/ranui/input/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -53,8 +53,8 @@ const func = (e) => { console.log(e); }; -input.addEventListener('input', func);

The e parameter structure of the event

input method

- +input.addEventListener('input', func);

The e parameter structure of the event

input method

+ \ No newline at end of file diff --git a/src/ranui/loading/index.html b/src/ranui/loading/index.html index e5b58d1aa9..54bafca88a 100644 --- a/src/ranui/loading/index.html +++ b/src/ranui/loading/index.html @@ -14,7 +14,7 @@ - + @@ -38,7 +38,7 @@ - + @@ -47,8 +47,8 @@
Skip to content

Loading

Some nice looking loading.

Code demo

xml
<r-loading name="circle"></r-loading>

Attribute

name

There's a lot of different loading here

xml
<r-loading name="double-bounce"></r-loading>
 <r-loading name="rotate"></r-loading>
 <r-loading name="stretch"></r-loading>
-<r-loading name="cube"></r-loading>

Loading list

Move the mouse over the icon to see the loading animation

stretch
rotate
double-bounce
cube
dot
triple-bounce
scale-out
circle
circle-line
square
pulse
solar
cube-fold
circle-fold
cube-grid
circle-turn
circle-rotate
circle-spin
dot-bar
dot-circle
line
dot-pulse
line-scale
text
cube-dim
dot-line
arc
drop
pacman

Released under the MIT License.

- +<r-loading name="cube"></r-loading>

Loading list

Move the mouse over the icon to see the loading animation

stretch
rotate
double-bounce
cube
dot
triple-bounce
scale-out
circle
circle-line
square
pulse
solar
cube-fold
circle-fold
cube-grid
circle-turn
circle-rotate
circle-spin
dot-bar
dot-circle
line
dot-pulse
line-scale
text
cube-dim
dot-line
arc
drop
pacman
+ \ No newline at end of file diff --git a/src/ranui/math/index.html b/src/ranui/math/index.html index b4b3623a6f..3923db4d50 100644 --- a/src/ranui/math/index.html +++ b/src/ranui/math/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

math

High-quality display of LaTeX in HTML pages

Code demo

xml
<r-math latex="\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1 \quad (a > b > 0)"></r-math>

Attribute

latex string

xml
  <r-math latex="x = {-b \pm \sqrt{b^2-4ac} \over 2a}"></r-math>

Released under the MIT License.

- +
Skip to content

math

High-quality display of LaTeX in HTML pages

Code demo

xml
<r-math latex="\frac{x^2}{a^2} + \frac{y^2}{b^2} = 1 \quad (a > b > 0)"></r-math>

Attribute

latex string

xml
  <r-math latex="x = {-b \pm \sqrt{b^2-4ac} \over 2a}"></r-math>

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranui/message/index.html b/src/ranui/message/index.html index 4aad731c62..4f536350b9 100644 --- a/src/ranui/message/index.html +++ b/src/ranui/message/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -46,8 +46,8 @@ <r-button onclick="message.warning('This is a hint')">Warning prompt</r-button> <r-button onclick="message.error('This is a hint')">Error prompt</r-button> <r-button onclick="message.success('This is a hint')">Success tip</r-button> -<r-button onclick="message.toast('This is a hint')">toast tip</r-button>

Method

The component provides a number of static methods, using the following methods and parameters:

  1. You can pass only one parameter, prompt the content, the default prompt 3000 milliseconds

message.info('This is a hint')

message.warning('This is a hint')

message.error('This is a hint')

message.success('This is a hint')

message.toast('This is a hint')"

  1. You can also pass an object, set the prompt content, turn off the delay, and trigger the callback function when you close it

message.info({content:'This is a hint', duration: 2000, close: () => {}})

message.warning({content:'This is a hint', duration: 2000, close: () => {}})

message.error({content:'This is a hint', duration: 2000, close: () => {}})

message.success({content:'This is a hint', duration: 2000, close: () => {}})

message.toast({content:'This is a hint', duration: 2000, close: () => {}})

参数说明类型
contentPrompt contentstring
durationAutomatic shutdown delay, in milliseconds. Default 3000 msnumber
closeCallback function triggered when closed() => void
- +<r-button onclick="message.toast('This is a hint')">toast tip</r-button>

Method

The component provides a number of static methods, using the following methods and parameters:

  1. You can pass only one parameter, prompt the content, the default prompt 3000 milliseconds

message.info('This is a hint')

message.warning('This is a hint')

message.error('This is a hint')

message.success('This is a hint')

message.toast('This is a hint')"

  1. You can also pass an object, set the prompt content, turn off the delay, and trigger the callback function when you close it

message.info({content:'This is a hint', duration: 2000, close: () => {}})

message.warning({content:'This is a hint', duration: 2000, close: () => {}})

message.error({content:'This is a hint', duration: 2000, close: () => {}})

message.success({content:'This is a hint', duration: 2000, close: () => {}})

message.toast({content:'This is a hint', duration: 2000, close: () => {}})

参数说明类型
contentPrompt contentstring
durationAutomatic shutdown delay, in milliseconds. Default 3000 msnumber
closeCallback function triggered when closed() => void
+ \ No newline at end of file diff --git a/src/ranui/modal/index.html b/src/ranui/modal/index.html index 6f8b30f1eb..6c2b4c0daf 100644 --- a/src/ranui/modal/index.html +++ b/src/ranui/modal/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

Released under the MIT License.

- +
Skip to content

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranui/player/index.html b/src/ranui/player/index.html index fb7e6275c7..7d4e04e47b 100644 --- a/src/ranui/player/index.html +++ b/src/ranui/player/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

r-player

Video player

Based on 'hlsjs' and' web components', let the native tag 'r-player' have a unified video control. Do not use the 'new Player(options)' way to mount to the specified 'dom', view return view, logic return logic, see and get, more intuitive.

  1. Drag and drop the progress bar
  2. Volume control
  3. The bitrate is automatically switched based on the current bandwidth
  4. Manual definition switch
  5. Play at double speed
  6. Style custom overlay
  7. 'hls' protocol standard encryption video playback
  8. Based on native development, it can run in all frameworks and unify the cross-framework situation
  9. Unified browser controls

Code demo

xml
  <r-player src="/ran/hls/example.m3u8"></r-player>

Attribute

src

Resource address of the video

volume

Set the initial volume. The default is 0.5

currentTime

Set the initial playback time. By default, the playback starts from the beginning

playbackRate

Set the double speed. The default is 1.0

debug

console.log some info

event

onchange

Listen for any player changes, and the value returned is as follows.

An 'instance of the player' can be obtained through this method.

Live by 'type' to judge different event types, perform different operations

propertyexplains thatis of type
typeIndicates the type of the changed event'string'
dataThe value of the'Object'
currentTimeThe current playback time'number'
durationTotal duration of videos'number'
tagAn example of the player'Element'

Where 'type' type has

NameDescription
canplayYour browser is ready to play the media file, but it probably doesn't have enough data to play it to the end without pausing to buffer the content further.
canplaythroughThe browser estimates that it canplay media until the end without stopping content buffering.
completeOfflineAudioContext The rendering is complete.
durationchangeduration is triggered when the value of the duration property changes.
emptiedMedia content emptied; For example, when the media is already loaded (or partially loaded), this event is sent and the load() method is called to reload it.
endedThe video stops playing because the media has reached the end point.
loadedmetadataThe metadata is loaded.
progressis triggered periodically when the browser loads the resource.
ratechangeThe play rate changes.
seekedThe seek operation is complete.
seekingseek begins.
stalledThe user agent is trying to obtain media data but it has not appeared unexpectedly.
suspendMedia data loading has been suspended.
loadeddataThe first frame in media has been added. media has loaded.
timeupdateThe time specified by the currentTime property changes. currentTime attribute has changed.
volumechangeThe volume changes.
waitingPlaying has stopped due to lack of data.
playPlayback has started.
playingAfter a pause or delay due to lack of data, playback is ready to begin.
pausePlay is paused.
volumeThe volume changes.
fullscreenTriggers a full-screen event

Released under the MIT License.

- +
Skip to content

r-player

Video player

Based on 'hlsjs' and' web components', let the native tag 'r-player' have a unified video control. Do not use the 'new Player(options)' way to mount to the specified 'dom', view return view, logic return logic, see and get, more intuitive.

  1. Drag and drop the progress bar
  2. Volume control
  3. The bitrate is automatically switched based on the current bandwidth
  4. Manual definition switch
  5. Play at double speed
  6. Style custom overlay
  7. 'hls' protocol standard encryption video playback
  8. Based on native development, it can run in all frameworks and unify the cross-framework situation
  9. Unified browser controls

Code demo

xml
  <r-player src="/ran/hls/example.m3u8"></r-player>

Attribute

src

Resource address of the video

volume

Set the initial volume. The default is 0.5

currentTime

Set the initial playback time. By default, the playback starts from the beginning

playbackRate

Set the double speed. The default is 1.0

debug

console.log some info

event

onchange

Listen for any player changes, and the value returned is as follows.

An 'instance of the player' can be obtained through this method.

Live by 'type' to judge different event types, perform different operations

propertyexplains thatis of type
typeIndicates the type of the changed event'string'
dataThe value of the'Object'
currentTimeThe current playback time'number'
durationTotal duration of videos'number'
tagAn example of the player'Element'

Where 'type' type has

NameDescription
canplayYour browser is ready to play the media file, but it probably doesn't have enough data to play it to the end without pausing to buffer the content further.
canplaythroughThe browser estimates that it canplay media until the end without stopping content buffering.
completeOfflineAudioContext The rendering is complete.
durationchangeduration is triggered when the value of the duration property changes.
emptiedMedia content emptied; For example, when the media is already loaded (or partially loaded), this event is sent and the load() method is called to reload it.
endedThe video stops playing because the media has reached the end point.
loadedmetadataThe metadata is loaded.
progressis triggered periodically when the browser loads the resource.
ratechangeThe play rate changes.
seekedThe seek operation is complete.
seekingseek begins.
stalledThe user agent is trying to obtain media data but it has not appeared unexpectedly.
suspendMedia data loading has been suspended.
loadeddataThe first frame in media has been added. media has loaded.
timeupdateThe time specified by the currentTime property changes. currentTime attribute has changed.
volumechangeThe volume changes.
waitingPlaying has stopped due to lack of data.
playPlayback has started.
playingAfter a pause or delay due to lack of data, playback is ready to begin.
pausePlay is paused.
volumeThe volume changes.
fullscreenTriggers a full-screen event

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranui/popover/index.html b/src/ranui/popover/index.html index c399f8d183..9b15234d83 100644 --- a/src/ranui/popover/index.html +++ b/src/ranui/popover/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -67,8 +67,8 @@ <r-content> <div>top</div> </r-content> - </r-popover> - + </r-popover> + \ No newline at end of file diff --git a/src/ranui/preview/index.html b/src/ranui/preview/index.html index e3c5ef16a7..b035090cfa 100644 --- a/src/ranui/preview/index.html +++ b/src/ranui/preview/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -61,8 +61,8 @@ } }; }; -</script>

Attribute

src

If there is a 'src' address, the popup window will be opened, and if there is no 'src', it will not be displayed

html
<r-preview src=""></r-preview>

closeable

'closeable' defaults to 'true' and can be closed, when set to 'false', it cannot be closed, and the close button in the upper right corner will not be displayed

html
<r-preview closeable="false"></r-preview>
- +</script>

Attribute

src

If there is a 'src' address, the popup window will be opened, and if there is no 'src', it will not be displayed

html
<r-preview src=""></r-preview>

closeable

'closeable' defaults to 'true' and can be closed, when set to 'false', it cannot be closed, and the close button in the upper right corner will not be displayed

html
<r-preview closeable="false"></r-preview>
+ \ No newline at end of file diff --git a/src/ranui/progress/index.html b/src/ranui/progress/index.html index 63aac76ecd..fced5ebe6d 100644 --- a/src/ranui/progress/index.html +++ b/src/ranui/progress/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -48,8 +48,8 @@ <r-progress type="primary" percent="40%"></r-progress> <r-progress type="primary" percent="100%"></r-progress>

dot

Point of the progress bar, Default display, set to 'false' can be hidden

html
<r-progress type="drag" percent="30%" dot="false"></r-progress>
 <r-progress type="primary" percent="40%" dot="true"></r-progress>
-<r-progress type="primary" percent="40%"></r-progress>

type

html
<r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

Method

change

The 'change' event is triggered when the 'percent' and 'total' properties change.

propertyexplains thattype
valueCurrent progress'string or number'
percentCurrent progress'string or number'
totalTotal progress'string or number'
- +<r-progress type="primary" percent="40%"></r-progress>

type

html
<r-progress type="drag" percent="30%"></r-progress> <r-progress type="primary" percent="40%"></r-progress>

Method

change

The 'change' event is triggered when the 'percent' and 'total' properties change.

propertyexplains thattype
valueCurrent progress'string or number'
percentCurrent progress'string or number'
totalTotal progress'string or number'
+ \ No newline at end of file diff --git a/src/ranui/radar/index.html b/src/ranui/radar/index.html index cad3e01645..54431ae722 100644 --- a/src/ranui/radar/index.html +++ b/src/ranui/radar/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -96,8 +96,8 @@ "abilityName": "Critical hit damage", "scoreRate": "50" } -] - +] + \ No newline at end of file diff --git a/src/ranui/select/index.html b/src/ranui/select/index.html index 5ce5667826..bf63d95830 100644 --- a/src/ranui/select/index.html +++ b/src/ranui/select/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -83,8 +83,8 @@ <r-option value="185">Mike</r-option> <r-option value="186">Tom</r-option> <r-option value="187">Lucy</r-option> - </r-select> - + </r-select> + \ No newline at end of file diff --git a/src/ranui/skeleton/index.html b/src/ranui/skeleton/index.html index 54759a44c9..5ef2fe4d8e 100644 --- a/src/ranui/skeleton/index.html +++ b/src/ranui/skeleton/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

skeleton

Provides a combination of placeholder graphics where you need to wait for content to load.

Code demo

The skeleton length follows the length of the parent element

xml
<r-skeleton ></r-skeleton>

Released under the MIT License.

- +
Skip to content

skeleton

Provides a combination of placeholder graphics where you need to wait for content to load.

Code demo

The skeleton length follows the length of the parent element

xml
<r-skeleton ></r-skeleton>

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranui/tab/index.html b/src/ranui/tab/index.html index 627d879178..fe0918f23f 100644 --- a/src/ranui/tab/index.html +++ b/src/ranui/tab/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -84,8 +84,8 @@ <r-tab label="tab1">11111</r-tab> <r-tab label="tab2">22222</r-tab> <r-tab label="tab3">33333</r-tab> - </r-tabs> - + </r-tabs> + \ No newline at end of file diff --git a/src/ranui/tabs/index.html b/src/ranui/tabs/index.html index 3f6fd58c11..e9b8277e86 100644 --- a/src/ranui/tabs/index.html +++ b/src/ranui/tabs/index.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -66,8 +66,8 @@ <r-tab icon="home" iconSize="22">tab1</r-tab> <r-tab icon="message" iconSize="22">tab2</r-tab> <r-tab icon="user" iconSize="22">tab3</r-tab> -</r-tabs>

'type'

The style is text, clean,

event '

onchange

Triggered when the switch is complete.

- +</r-tabs>

'type'

The style is text, clean,

event '

onchange

Triggered when the switch is complete.

+ \ No newline at end of file diff --git a/src/ranuts/binaryTree/index.html b/src/ranuts/binaryTree/index.html index 880309dc1c..49013e1bd2 100644 --- a/src/ranuts/binaryTree/index.html +++ b/src/ranuts/binaryTree/index.html @@ -13,7 +13,7 @@ - + @@ -37,14 +37,14 @@ - + -
Skip to content

二叉树的定义

在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

二叉树的性质

  • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
  • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
  • 包含 n 个结点的二叉树的高度至少为(log2n)+1
  • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
  • 二叉树的总结点数 n = n1 + n2 + n0
  • 总连线数等于总节点数减一(B = n - 1)
  • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

二叉树的类型

满二叉树

一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

完全二叉树

一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

二叉搜索树

二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

平衡二叉树

平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

B 树

B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

B+树

B+树是 B 树的变体,也是一种多路搜索树。

B*树

B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

红黑树

红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

遍历

前序遍历

后序遍历

中序遍历

层序遍历

常见算法题

镜像二叉树

重建二叉树

二叉树深度

二叉树节点总数

判断二叉树子结构

输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

参考文档

  1. 维基百科二叉树
  2. 百度百科满二叉树

Released under the MIT License.

- +
Skip to content

二叉树的定义

在计算机科学中,二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒[1]。。

二叉树的性质

  • 在二叉树的第 i 层上最多有 2^(i-1)个结点(i>=1)
  • 深度为 h 的二叉树,最多有 2^h-1 个结点,最少有 h 个结点(h>=1)
  • 包含 n 个结点的二叉树的高度至少为(log2n)+1
  • 非空的二叉树,分支度为 0 的总数为 n0,分支度为 2 的总数为 n2,则 n0=n2+1
  • 二叉树的总结点数 n = n1 + n2 + n0
  • 总连线数等于总节点数减一(B = n - 1)
  • 总连线数等于分支度为 2 的节点的两倍加上分支度为 1 的节点(B = n2 _ 2 + n1 _ 1)

二叉树的类型

满二叉树

一棵深度为 k 且有 2k-1 个节点的二叉树称为满二叉树。 除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树[2]

完全二叉树

一棵深度为 k 的有 n 个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为 i(1≤i≤n)的结点与满二叉树中编号为 i 的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。

二叉搜索树

二叉搜索树(BST)又称二叉查找树或二叉排序树。它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

平衡二叉树

平衡二叉树(AVL)一定是二叉搜索树,且左子树和右子树的高度差的绝对值不超过 1。 平衡二叉树

B 树

B 树属于多叉树又名平衡多路查找树(查找路径不只两个)

B+树

B+树是 B 树的变体,也是一种多路搜索树。

B*树

B* 树是 B+树的变体,在 B+树的非根和非叶子结点再增加指向兄弟的指针;B* 树定义了非叶子结点关键字个数至少为(2/3)M,即块的最低使用率为 2/3(代替 B+树的 1/2)。B 树分配新结点的概率比 B+树要低,空间使用率更高;

红黑树

红黑树是一种平衡二叉查找树的变体,它的左右子树高差有可能大于 1,所以红黑树不是严格意义上的平衡二叉树(AVL),但对它进行平衡的代价较低, 其平均统计性能要强于 AVL 。

遍历

前序遍历

后序遍历

中序遍历

层序遍历

常见算法题

镜像二叉树

重建二叉树

二叉树深度

二叉树节点总数

判断二叉树子结构

输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。(ps:约定空树不是任意一个树的子结构)

参考文档

  1. 维基百科二叉树
  2. 百度百科满二叉树

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranuts/bundler/index.html b/src/ranuts/bundler/index.html index 89ea72cf0d..53c3e66d22 100644 --- a/src/ranuts/bundler/index.html +++ b/src/ranuts/bundler/index.html @@ -13,7 +13,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -52,8 +52,8 @@ generate: () => bundle.render() }; }); -}

架构图

- +}

架构图

+ \ No newline at end of file diff --git a/src/ranuts/file/appendFile.html b/src/ranuts/file/appendFile.html index d4e0d857ce..9650b428d7 100644 --- a/src/ranuts/file/appendFile.html +++ b/src/ranuts/file/appendFile.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

AppendFile

追加一些数据到文件内

API

Return

  • Promise
参数说明类型描述
success是否追加成功booleantrue 追加成功 false 追加失败
data追加失败的原因,添加成功后的文件内容any

Options

参数说明类型默认值
path文件路径,需要追加的文件stringundefined
content需要追加的内容string

Example

Released under the MIT License.

- +
Skip to content

AppendFile

追加一些数据到文件内

API

Return

  • Promise
参数说明类型描述
success是否追加成功booleantrue 追加成功 false 追加失败
data追加失败的原因,添加成功后的文件内容any

Options

参数说明类型默认值
path文件路径,需要追加的文件stringundefined
content需要追加的内容string

Example

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranuts/file/fileInfo.html b/src/ranuts/file/fileInfo.html index a574ec611b..42b8eddb17 100644 --- a/src/ranuts/file/fileInfo.html +++ b/src/ranuts/file/fileInfo.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

QueryFileInfo

查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

API

Return

  • Promise
参数说明类型描述
success是否检查成功booleantrue 成功 false 失败
data文件的信息,或者错误的原因Stats

Options

参数说明类型默认值
path文件路径,需要检查的文件路径stringundefined

Example

Released under the MIT License.

- +
Skip to content

QueryFileInfo

查询一个文件的详细信息,一般用于区分文件还是目录,可以通过返回的 data 来判断(data.isDirectory())

API

Return

  • Promise
参数说明类型描述
success是否检查成功booleantrue 成功 false 失败
data文件的信息,或者错误的原因Stats

Options

参数说明类型默认值
path文件路径,需要检查的文件路径stringundefined

Example

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranuts/file/readDir.html b/src/ranuts/file/readDir.html index 6f7532418f..b1ec5d34ae 100644 --- a/src/ranuts/file/readDir.html +++ b/src/ranuts/file/readDir.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

ReadDir

读一个目录下的所有文件

API

Return

  • Promise
参数说明类型描述
result目录下所有文件的数组array传入函数的参数

Options

参数说明类型默认值
optionsobject传入函数的参数
dirPath文件的路径Stats

Example

Released under the MIT License.

- +
Skip to content

ReadDir

读一个目录下的所有文件

API

Return

  • Promise
参数说明类型描述
result目录下所有文件的数组array传入函数的参数

Options

参数说明类型默认值
optionsobject传入函数的参数
dirPath文件的路径Stats

Example

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranuts/file/readFile.html b/src/ranuts/file/readFile.html index 4389663827..6bc41c96fa 100644 --- a/src/ranuts/file/readFile.html +++ b/src/ranuts/file/readFile.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

ReadFile

观察一个文件是否改变

API

Return

  • Promise
参数说明类型描述
data文件是否被改变booleantrue 文件改变 false 文件没变

Options

参数说明类型默认值
path文件路径,需要监听的文件stringundefined
interval监听文件改变的时间,单位毫秒。number20

Example

Released under the MIT License.

- +
Skip to content

ReadFile

观察一个文件是否改变

API

Return

  • Promise
参数说明类型描述
data文件是否被改变booleantrue 文件改变 false 文件没变

Options

参数说明类型默认值
path文件路径,需要监听的文件stringundefined
interval监听文件改变的时间,单位毫秒。number20

Example

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranuts/file/watchFile.html b/src/ranuts/file/watchFile.html index 459b4f799d..a021126a43 100644 --- a/src/ranuts/file/watchFile.html +++ b/src/ranuts/file/watchFile.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

WatchFile

观察一个文件是否改变

API

Return

  • Promise
参数说明类型描述
status文件是否被改变booleantrue 文件改变 false 文件没变

Options

参数说明类型默认值
path文件路径,需要监听的文件stringundefined
interval监听文件改变的时间,单位毫秒。number20

Released under the MIT License.

- +
Skip to content

WatchFile

观察一个文件是否改变

API

Return

  • Promise
参数说明类型描述
status文件是否被改变booleantrue 文件改变 false 文件没变

Options

参数说明类型默认值
path文件路径,需要监听的文件stringundefined
interval监听文件改变的时间,单位毫秒。number20

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranuts/file/writeFile.html b/src/ranuts/file/writeFile.html index 44f06e4e6d..75ec6113fd 100644 --- a/src/ranuts/file/writeFile.html +++ b/src/ranuts/file/writeFile.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

WriteFile

将内容写入文件

API

Return

  • Promise
参数说明类型描述
success是否写入成功booleantrue 成功 false 失败
data写入失败的原因,添加成功后的文件内容和文件路径any

Options

参数说明类型默认值
path文件路径,需要追加的文件stringundefined
content需要追加的内容string

Released under the MIT License.

- +
Skip to content

WriteFile

将内容写入文件

API

Return

  • Promise
参数说明类型描述
success是否写入成功booleantrue 成功 false 失败
data写入失败的原因,添加成功后的文件内容和文件路径any

Options

参数说明类型默认值
path文件路径,需要追加的文件stringundefined
content需要追加的内容string

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranuts/index.html b/src/ranuts/index.html index 06540d24f2..4b6a203268 100644 --- a/src/ranuts/index.html +++ b/src/ranuts/index.html @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

ranuts overview

Method list

Methoddescriptiondetail
writeFileWrite to filewriteFile
readFileRead filereadFile
readDirRead the directory and get the names of all the files in the directoryreadDir
watchFileCheck whether the contents of the file have changedwatchFile
queryFileInfoQuery file informationqueryFileInfo
filterObjFilter objectfilterObj
EventEmitterPublish-subscribe classEventEmitter
str2XmlString is converted to xmlstr2Xml
getMimeGets the mime type based on the file format suffixgetMime
getCookieGets the value of the specified cookiewriteFile
formatJsonFormatted JSONformatJson

TOTP

2FA Verification
Generate
code:
expires:

Released under the MIT License.

- +
Skip to content

ranuts overview

Method list

Methoddescriptiondetail
writeFileWrite to filewriteFile
readFileRead filereadFile
readDirRead the directory and get the names of all the files in the directoryreadDir
watchFileCheck whether the contents of the file have changedwatchFile
queryFileInfoQuery file informationqueryFileInfo
filterObjFilter objectfilterObj
EventEmitterPublish-subscribe classEventEmitter
str2XmlString is converted to xmlstr2Xml
getMimeGets the mime type based on the file format suffixgetMime
getCookieGets the value of the specified cookiewriteFile
formatJsonFormatted JSONformatJson

TOTP

2FA Verification
Generate
code:
expires:

Released under the MIT License.

+ \ No newline at end of file diff --git a/src/ranuts/mimeType/mimeType.html b/src/ranuts/mimeType/mimeType.html index bc25bd60c2..d9308b2b4f 100644 --- a/src/ranuts/mimeType/mimeType.html +++ b/src/ranuts/mimeType/mimeType.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -49,8 +49,8 @@ // 'application/vnd.openxmlformats-officedocument.presentationml.presentation const res = getMime('.txt'); console.log(result); -// text/plain - +// text/plain + \ No newline at end of file diff --git a/src/ranuts/mode/subscribe.html b/src/ranuts/mode/subscribe.html index f866c84282..ead6c6c7ad 100644 --- a/src/ranuts/mode/subscribe.html +++ b/src/ranuts/mode/subscribe.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -73,8 +73,8 @@ // 订阅一次,触发一次自动取消 subscribe.once('other', () => { console.log(5); -}); - +}); + \ No newline at end of file diff --git a/src/ranuts/utils/convertImageToBase64.html b/src/ranuts/utils/convertImageToBase64.html index 63c1ecbf18..91b0c0e05a 100644 --- a/src/ranuts/utils/convertImageToBase64.html +++ b/src/ranuts/utils/convertImageToBase64.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -46,8 +46,8 @@ convertImageToBase64(file).then((res) => { console.log(result); -}); - +}); + \ No newline at end of file diff --git a/src/ranuts/utils/filterObj.html b/src/ranuts/utils/filterObj.html index 2e43f67bd4..4013994061 100644 --- a/src/ranuts/utils/filterObj.html +++ b/src/ranuts/utils/filterObj.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -54,8 +54,8 @@ console.log(result); -// { age:10 } - +// { age:10 } + \ No newline at end of file diff --git a/src/ranuts/utils/formatJson.html b/src/ranuts/utils/formatJson.html index 22338271a5..8c5ff9c849 100644 --- a/src/ranuts/utils/formatJson.html +++ b/src/ranuts/utils/formatJson.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -51,8 +51,8 @@ const result = formatJson(json); -console.log(result); - +console.log(result); + \ No newline at end of file diff --git a/src/ranuts/utils/getCookie.html b/src/ranuts/utils/getCookie.html index 9fb44f4250..3d42c1bf7f 100644 --- a/src/ranuts/utils/getCookie.html +++ b/src/ranuts/utils/getCookie.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -48,8 +48,8 @@ console.log(result); -// '' - +// '' + \ No newline at end of file diff --git a/src/ranuts/utils/ocr.html b/src/ranuts/utils/ocr.html index c0099ab5c7..e65a7d9729 100644 --- a/src/ranuts/utils/ocr.html +++ b/src/ranuts/utils/ocr.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -56,8 +56,8 @@ // And when thou lovest thy pale orb to shroud // Behind the gather’d blackness lost on high; // And when thou dartest from the wind-rent cloud -// Thy placid lightning o’er the awaken’d sky.

Lang Code

Lang CodeLanguage
afrAfrikaans
amhAmharic
araArabic
asmAssamese
azeAzerbaijani
aze_cyrlAzerbaijani - Cyrillic
belBelarusian
benBengali
bodTibetan
bosBosnian
bulBulgarian
catCatalan; Valencian
cebCebuano
cesCzech
chi_simChinese - Simplified
chi_traChinese - Traditional
chrCherokee
cymWelsh
danDanish
deuGerman
dzoDzongkha
ellGreek, Modern (1453-)
engEnglish
enmEnglish, Middle (1100-1500)
epoEsperanto
estEstonian
eusBasque
fasPersian
finFinnish
fraFrench
frkGerman Fraktur
frmFrench, Middle (ca. 1400-1600)
gleIrish
glgGalician
grcGreek, Ancient (-1453)
gujGujarati
hatHaitian; Haitian Creole
hebHebrew
hinHindi
hrvCroatian
hunHungarian
ikuInuktitut
indIndonesian
islIcelandic
itaItalian
ita_oldItalian - Old
javJavanese
jpnJapanese
kanKannada
katGeorgian
kat_oldGeorgian - Old
kazKazakh
khmCentral Khmer
kirKirghiz; Kyrgyz
korKorean
kurKurdish
laoLao
latLatin
lavLatvian
litLithuanian
malMalayalam
marMarathi
mkdMacedonian
mltMaltese
msaMalay
myaBurmese
nepNepali
nldDutch; Flemish
norNorwegian
oriOriya
panPanjabi; Punjabi
polPolish
porPortuguese
pusPushto; Pashto
ronRomanian; Moldavian; Moldovan
rusRussian
sanSanskrit
sinSinhala; Sinhalese
slkSlovak
slvSlovenian
spaSpanish; Castilian
spa_oldSpanish; Castilian - Old
sqiAlbanian
srpSerbian
srp_latnSerbian - Latin
swaSwahili
sweSwedish
syrSyriac
tamTamil
telTelugu
tgkTajik
tglTagalog
thaThai
tirTigrinya
turTurkish
uigUighur; Uyghur
ukrUkrainian
urdUrdu
uzbUzbek
uzb_cyrlUzbek - Cyrillic
vieVietnamese
yidYiddish
- +// Thy placid lightning o’er the awaken’d sky.

Lang Code

Lang CodeLanguage
afrAfrikaans
amhAmharic
araArabic
asmAssamese
azeAzerbaijani
aze_cyrlAzerbaijani - Cyrillic
belBelarusian
benBengali
bodTibetan
bosBosnian
bulBulgarian
catCatalan; Valencian
cebCebuano
cesCzech
chi_simChinese - Simplified
chi_traChinese - Traditional
chrCherokee
cymWelsh
danDanish
deuGerman
dzoDzongkha
ellGreek, Modern (1453-)
engEnglish
enmEnglish, Middle (1100-1500)
epoEsperanto
estEstonian
eusBasque
fasPersian
finFinnish
fraFrench
frkGerman Fraktur
frmFrench, Middle (ca. 1400-1600)
gleIrish
glgGalician
grcGreek, Ancient (-1453)
gujGujarati
hatHaitian; Haitian Creole
hebHebrew
hinHindi
hrvCroatian
hunHungarian
ikuInuktitut
indIndonesian
islIcelandic
itaItalian
ita_oldItalian - Old
javJavanese
jpnJapanese
kanKannada
katGeorgian
kat_oldGeorgian - Old
kazKazakh
khmCentral Khmer
kirKirghiz; Kyrgyz
korKorean
kurKurdish
laoLao
latLatin
lavLatvian
litLithuanian
malMalayalam
marMarathi
mkdMacedonian
mltMaltese
msaMalay
myaBurmese
nepNepali
nldDutch; Flemish
norNorwegian
oriOriya
panPanjabi; Punjabi
polPolish
porPortuguese
pusPushto; Pashto
ronRomanian; Moldavian; Moldovan
rusRussian
sanSanskrit
sinSinhala; Sinhalese
slkSlovak
slvSlovenian
spaSpanish; Castilian
spa_oldSpanish; Castilian - Old
sqiAlbanian
srpSerbian
srp_latnSerbian - Latin
swaSwahili
sweSwedish
syrSyriac
tamTamil
telTelugu
tgkTajik
tglTagalog
thaThai
tirTigrinya
turTurkish
uigUighur; Uyghur
ukrUkrainian
urdUrdu
uzbUzbek
uzb_cyrlUzbek - Cyrillic
vieVietnamese
yidYiddish
+ \ No newline at end of file diff --git a/src/ranuts/utils/str2xml.html b/src/ranuts/utils/str2xml.html index 0a2b14806e..213f86bb9a 100644 --- a/src/ranuts/utils/str2xml.html +++ b/src/ranuts/utils/str2xml.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -49,8 +49,8 @@ const icon = str2Xml(svg, 'image/svg+xml'); -document.body.appendChild(icon); - +document.body.appendChild(icon); + \ No newline at end of file diff --git a/src/ranuts/utils/task.html b/src/ranuts/utils/task.html index 41ffad905a..3bd3d5e616 100644 --- a/src/ranuts/utils/task.html +++ b/src/ranuts/utils/task.html @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -48,8 +48,8 @@ const time = taskEnd(taskId); -console.log('task 执行花费的时间', time);

二.new Date().getTime()

new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

  1. 某些情况下,毫秒级精度可能不够。
  2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

    由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

三.console.time(), console.timeEnd()

启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

四.performance.now()

performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

- +console.log('task 执行花费的时间', time);

二.new Date().getTime()

new Date().getTime() 返回一个数值,表示从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)距离该日期对象所代表时间的毫秒数。用来计算 JS 执行时间会有两个问题:

  1. 某些情况下,毫秒级精度可能不够。
  2. new Date() 解析的时间在不同浏览器,或者不同设备上可能并不一致。MDN 说明

    由于浏览器之间的差异与不一致性,强烈不推荐使用 Date 构造函数来解析日期字符串 (或使用与其等价的 Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。

三.console.time(), console.timeEnd()

启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。当以此计时器名字为参数调用 console.timeEnd() 时,浏览器将以毫秒为单位,输出对应计时器所经过的时间。比起new Date().getTime(),统计时间更加精确,可以统计到 0.001 毫秒(比如:0.134ms)

四.performance.now()

performance.now()返回的时间精度最高可达微秒级,且不会受到系统时间的影响(系统时钟可能会被手动调整或被 NTP 等软件篡改)。另外,performance.timing.navigationStart + performance.now() 约等于 Date.now()。因此对于统计 JS 执行耗时方面,更推荐使用performance.now()

注意:为了提供对定时攻击和指纹的保护,performance.now() 的精度可能会根据浏览器的设置而被舍弃。 在 Firefox 中,privacy.reduceTimerPrecision 偏好是默认启用的,默认值为 1ms。可以启用 privacy.resistFingerprinting 这将精度改为 100ms 或privacy.resistFingerprinting.reduceTimerPrecision.microseconds 的值,以较大者为准。

+ \ No newline at end of file diff --git "a/src/types/TS\347\261\273\345\236\213.html" "b/src/types/TS\347\261\273\345\236\213.html" index 0b4417018e..593f50c079 100644 --- "a/src/types/TS\347\261\273\345\236\213.html" +++ "b/src/types/TS\347\261\273\345\236\213.html" @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -89,8 +89,8 @@ age?: number; } -type tuple = [string, number?]; - +type tuple = [string, number?]; + \ No newline at end of file diff --git "a/src/types/\346\250\241\345\274\217\345\214\271\351\205\215.html" "b/src/types/\346\250\241\345\274\217\345\214\271\351\205\215.html" index 1fbf6a2123..094f992b30 100644 --- "a/src/types/\346\250\241\345\274\217\345\214\271\351\205\215.html" +++ "b/src/types/\346\250\241\345\274\217\345\214\271\351\205\215.html" @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -52,8 +52,8 @@ new (name: string): Person; }

这里的 PersonConstructor 返回的是 Person 类型的实例对象,这个也可以通过模式匹配取出来。

ts
type GetInstanceType<C extends new (...args: unknown[]) => unknown> = C extends new (...args: unknown[]) => infer T
   ? T
-  : unknown;
- + : unknown; + \ No newline at end of file diff --git "a/src/types/\347\261\273\345\236\213\350\277\220\347\256\227.html" "b/src/types/\347\261\273\345\236\213\350\277\220\347\256\227.html" index 6dc3b6c258..c6115037b8 100644 --- "a/src/types/\347\261\273\345\236\213\350\277\220\347\256\227.html" +++ "b/src/types/\347\261\273\345\236\213\350\277\220\347\256\227.html" @@ -12,7 +12,7 @@ - + @@ -36,7 +36,7 @@ - + @@ -68,8 +68,8 @@ // type res = { // aaa:[1,1,1] // bbb:[2,2,2] -// }

这里的 & string 可能大家会迷惑,解释一下:

因为索引类型(对象、class 等)可以用 string、number 和 symbol 作为 key,这里 keyof T 取出的索引就是 string | number | symbol 的联合类型,和 string 取交叉部分就只剩下 string 了。就像前面所说,交叉类型会把同一类型做合并,不同类型舍弃。

因为 js 处理对象比较多,所以索引类型的映射比较重要。

- +// }

这里的 & string 可能大家会迷惑,解释一下:

因为索引类型(对象、class 等)可以用 string、number 和 symbol 作为 key,这里 keyof T 取出的索引就是 string | number | symbol 的联合类型,和 string 取交叉部分就只剩下 string 了。就像前面所说,交叉类型会把同一类型做合并,不同类型舍弃。

因为 js 处理对象比较多,所以索引类型的映射比较重要。

+ \ No newline at end of file diff --git "a/src/types/\351\253\230\347\272\247\347\261\273\345\236\213.html" "b/src/types/\351\253\230\347\272\247\347\261\273\345\236\213.html" index dfedb0fb40..e1222b494a 100644 --- "a/src/types/\351\253\230\347\272\247\347\261\273\345\236\213.html" +++ "b/src/types/\351\253\230\347\272\247\347\261\273\345\236\213.html" @@ -12,7 +12,7 @@ - + @@ -36,14 +36,14 @@ - + -
Skip to content

TypeScript 内置的高级类型

Parameters

Parameters 用于提取函数类型的参数类型。

ReturnType

ReturnType 用于提取函数类型的返回值类型。

ConstructorParameters

构造器类型和函数类型的区别就是可以被 new。

Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

InstanceType

提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

ThisParameterType

OmitThisParameter

Partial

Required

Readonly

Pick

Record

Exclude

Extract

Omit

Awaited

NonNullable

Uppercase

Lowercase

Capitalize

Uncapitalize

总结

比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

用模式匹配 + 重新构造可以实现:OmitThisParameter

用重新构造可以实现:Partial、Required、Readonly、Pick、Record

用模式匹配 + 递归可以实现: Awaited

用联合类型在分布式条件类型的特性可以实现: Exclude

此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

Last updated:

Released under the MIT License.

- +
Skip to content

TypeScript 内置的高级类型

Parameters

Parameters 用于提取函数类型的参数类型。

ReturnType

ReturnType 用于提取函数类型的返回值类型。

ConstructorParameters

构造器类型和函数类型的区别就是可以被 new。

Parameters 用于提取函数参数的类型,而 ConstructorParameters 用于提取构造器参数的类型。

InstanceType

提取了构造器参数的类型,自然也可以提取构造器返回值的类型,就是 InstanceType。

ThisParameterType

OmitThisParameter

Partial

Required

Readonly

Pick

Record

Exclude

Extract

Omit

Awaited

NonNullable

Uppercase

Lowercase

Capitalize

Uncapitalize

总结

比如用模式匹配可以实现:Parameters、ReturnType、ConstructorParameters、InstanceType、ThisParameterType。

用模式匹配 + 重新构造可以实现:OmitThisParameter

用重新构造可以实现:Partial、Required、Readonly、Pick、Record

用模式匹配 + 递归可以实现: Awaited

用联合类型在分布式条件类型的特性可以实现: Exclude

此外还有 NonNullable 和四个编译器内部实现的类型:Uppercase、Lowercase、Capitalize、Uncapitalize。

Last updated:

Released under the MIT License.

+ \ No newline at end of file diff --git a/sw1728828594.js b/sw1728921819.js similarity index 56% rename from sw1728828594.js rename to sw1728921819.js index f89eb4c917..c35390349a 100644 --- a/sw1728828594.js +++ b/sw1728921819.js @@ -162,265 +162,261 @@ const SERVICE_WORK_CACHE_FILE_PATHS = [ "/ran/hls/5_1701577771368/5_00002.ts", "/ran/hls/example.m3u8", "/ran/home.svg", +"/ran/sw1728921819.js", "/ran/hashmap.json", -"/ran/sw1728828594.js", "/ran/icon_144.png", -"/ran/assets/cn_src_ranui_loading_index.md.CA72DxYe.lean.js", "/ran/assets/解释器.DymUKGTa.jpg", -"/ran/assets/src_ranui_icon_index.md.BQTFP8u3.js", "/ran/assets/export.ne8l5ppO.jpeg", -"/ran/assets/src_ranuts_file_fileInfo.md.BGMu3rbo.lean.js", -"/ran/assets/cn_src_ranuts_utils_filterObj.md.DE1C38Kh.lean.js", "/ran/assets/heap.D4myjC6C.gif", -"/ran/assets/cn_src_article_sort_insert_index.md.CmQ1YgOQ.js", -"/ran/assets/src_article_typescript_reconstruction.md.CohgiGIS.js", -"/ran/assets/cn_src_article_sort_insert_index.md.CmQ1YgOQ.lean.js", -"/ran/assets/cn_src_ranui_progress_index.md.m21IXa5G.js", -"/ran/assets/src_ranuts_utils_str2xml.md.CwgfkeY1.lean.js", -"/ran/assets/cn_src_ranui_player_index.md.CuAqghFD.js", +"/ran/assets/cn_src_ranuts_utils_task.md.DbClSCsQ.js", +"/ran/assets/src_article_typescript_unionType.md.BKfC5bWe.js", +"/ran/assets/cn_src_article_sort_insert_index.md.DjxCK_3e.lean.js", +"/ran/assets/cn_src_article_video.md.BmsbKb7b.js", +"/ran/assets/cn_src_ranuts_file_readDir.md.rKDcx1fc.js", +"/ran/assets/cn_src_article_sort_merge_index.md.CkGKR7pJ.js", +"/ran/assets/cn_src_ranui_loading_index.md.CO9CpYNH.js", "/ran/assets/ow365.CXWyYekS.webp", "/ran/assets/kkfile_output.DD8iZdbo.webp", -"/ran/assets/src_ranuts_file_appendFile.md.CHmuoXqR.js", -"/ran/assets/src_ranuts_index.md.Q_PSqhjV.lean.js", +"/ran/assets/cn_src_article_typescript_pattern.md.CyszQeR8.lean.js", +"/ran/assets/src_ranuts_utils_convertImageToBase64.md.BvH8a7ux.js", +"/ran/assets/src_ranuts_utils_str2xml.md.DiJE8okl.lean.js", +"/ran/assets/cn_src_article_sort_bucket_index.md.DART29Tq.js", "/ran/assets/firefox_pdf.BWQR-ogn.webp", -"/ran/assets/cn_src_article_sort_select_index.md.HS1vLdcG.js", "/ran/assets/tiktik_video_demo.mxxBzLay.webp", +"/ran/assets/src_article_astParse_tokenizer.md.BvreBUpi.js", "/ran/assets/Program.BBf_t-me.jpeg", -"/ran/assets/cn_src_note_ubuntu.md.DgjTInOe.js", -"/ran/assets/src_ranui_image_index.md.ntBTaVra.js", +"/ran/assets/src_ranuts_utils_convertImageToBase64.md.BvH8a7ux.lean.js", +"/ran/assets/cn_src_article_typescript_index.md.BUmi2po9.lean.js", +"/ran/assets/cn_src_ranuts_file_readFile.md.nK6bqV_e.js", +"/ran/assets/cn_src_types_模式匹配.md.CpwnVZOP.lean.js", +"/ran/assets/cn_src_article_typescript_calculate.md.CC_IXoWD.js", +"/ran/assets/src_ranuts_mode_subscribe.md.Psp8bIgo.lean.js", "/ran/assets/kkfile_des.CENUMtpY.webp", -"/ran/assets/src_ranui_index.md.C5qoVF5Z.lean.js", -"/ran/assets/src_article_functionalProgramming.md.zs1zfDDr.lean.js", -"/ran/assets/cn_src_ranui_message_index.md.C38PI1jt.lean.js", +"/ran/assets/cn_src_types_TS类型.md.iJyVKiUM.lean.js", "/ran/assets/wps_office_price.ler9htjh.webp", -"/ran/assets/src_types_TS类型.md.BkjT3Xys.js", +"/ran/assets/src_article_typescript_unionType.md.BKfC5bWe.lean.js", +"/ran/assets/index.md.B_9rwraW.js", +"/ran/assets/cn_src_article_babel.md.BRRU23MO.js", "/ran/assets/kkfile.X1tAqvNa.webp", +"/ran/assets/src_article_sort_bucket_index.md.C8sI_tGv.js", +"/ran/assets/src_ranuts_utils_filterObj.md.BtAgodt-.js", +"/ran/assets/src_ranuts_bundler_index.md.BBvegtDt.lean.js", +"/ran/assets/cn_src_article_visual.md.BO64nAx5.lean.js", "/ran/assets/Literal.Dl-JxujV.jpeg", -"/ran/assets/cn_src_ranuts_utils_formatJson.md.C6zYMUay.lean.js", -"/ran/assets/cn_src_article_sort_merge_index.md.MDU-inBg.lean.js", -"/ran/assets/cn_src_ranuts_utils_getCookie.md.BomC6eQg.js", -"/ran/assets/src_ranuts_utils_convertImageToBase64.md.CGjlmYhP.js", -"/ran/assets/cn_src_ranui_select_index.md.CmisBOzA.lean.js", -"/ran/assets/cn_src_ranuts_bundler_index.md.gFLefqgx.js", -"/ran/assets/src_ranuts_utils_filterObj.md.BsaBmsvk.lean.js", -"/ran/assets/cn_src_ranuts_file_fileInfo.md.Dho5Tv6s.js", -"/ran/assets/src_ranuts_utils_ocr.md.l96JLeA3.js", -"/ran/assets/src_ranui_preview_index.md.fG1IQRia.lean.js", -"/ran/assets/cn_src_article_typescript_calculate.md.CNAvvheA.lean.js", -"/ran/assets/cn_src_article_sort_shell_index.md.DecAJ1tS.js", -"/ran/assets/src_types_高级类型.md.DrTZYnDE.lean.js", -"/ran/assets/cn_src_article_sort_quick_index.md.CvZw-icp.js", -"/ran/assets/cn_src_types_TS类型.md.BdnhcvJe.js", -"/ran/assets/cn_src_ranui_tab_index.md.D3FaivVj.lean.js", +"/ran/assets/cn_src_ranuts_bundler_index.md.CNoHThyX.js", +"/ran/assets/src_article_sort_heap_index.md.D8fxvFJ4.lean.js", +"/ran/assets/cn_src_article_video.md.BmsbKb7b.lean.js", +"/ran/assets/src_types_TS类型.md.DIHmZPe4.js", +"/ran/assets/cn_src_types_类型运算.md.HXO7_zmg.js", +"/ran/assets/src_ranui_skeleton_index.md.8I5i20E1.js", +"/ran/assets/src_ranuts_utils_formatJson.md.CSMLr8Hr.js", +"/ran/assets/cn_src_article_typescript_index.md.BUmi2po9.js", +"/ran/assets/src_article_bundle.md.ChxeIam8.js", +"/ran/assets/cn_src_ranuts_utils_str2xml.md.s2QXhzVM.js", +"/ran/assets/cn_src_types_模式匹配.md.CpwnVZOP.js", +"/ran/assets/src_ranui_loading_index.md.EajM1Fh_.lean.js", +"/ran/assets/cn_src_ranui_popover_index.md.BNd4uUYL.js", +"/ran/assets/src_article_sort_shell_index.md.H4IG1J-3.js", "/ran/assets/rplayer_demo.CoJ7kuJt.webp", +"/ran/assets/src_ranui_icon_index.md.DHD0uzGs.js", +"/ran/assets/src_article_typescript_recursion.md.BD02XaoF.js", "/ran/assets/ali_doc.CYo30EHy.webp", "/ran/assets/tiktok_video.DuwKyIdt.webp", -"/ran/assets/src_article_sort_shell_index.md.D333S2vN.js", "/ran/assets/继承.Dta6_xdc.png", -"/ran/assets/cn_src_ranui_message_index.md.C38PI1jt.js", -"/ran/assets/cn_src_article_typescript_pattern.md.rnM0NHZ9.js", -"/ran/assets/src_ranui_index.md.C5qoVF5Z.js", -"/ran/assets/cn_src_note_libreoffice2wasm.md.D2SYnyUq.js", -"/ran/assets/cn_src_article_docPreview.md.to4R_V9b.js", -"/ran/assets/src_ranui_icon_index.md.BQTFP8u3.lean.js", +"/ran/assets/src_ranui_tab_index.md.CeQ2RW9Y.lean.js", +"/ran/assets/src_ranuts_file_readFile.md.DZETE7kx.js", "/ran/assets/Expression.DczLaznn.jpeg", "/ran/assets/抽象工厂.DlwNEriZ.png", "/ran/assets/insert.gf3GhDvq.gif", "/ran/assets/适配器.C2VH4lXy.png", -"/ran/assets/cn_src_article_designMode.md.DZ98r33q.lean.js", -"/ran/assets/cn_src_article_sort_count_index.md.DYoyFiDb.lean.js", +"/ran/assets/cn_src_ranuts_binaryTree_index.md.DrXBmpfQ.js", "/ran/assets/radix.Bwrylu8F.gif", +"/ran/assets/src_ranuts_file_readFile.md.DZETE7kx.lean.js", "/ran/assets/Identifier.lJSxyFTe.jpeg", -"/ran/assets/cn_src_ranuts_utils_task.md.DwcnyfHt.lean.js", -"/ran/assets/src_types_TS类型.md.BkjT3Xys.lean.js", -"/ran/assets/src_ranuts_utils_str2xml.md.CwgfkeY1.js", +"/ran/assets/src_article_typescript_calculate.md.C7yhKz7X.lean.js", +"/ran/assets/cn_src_ranuts_file_watchFile.md.CAsEL4vf.lean.js", +"/ran/assets/src_ranui_tabs_index.md.CxBjn965.lean.js", +"/ran/assets/src_article_astParse_tokenizer.md.BvreBUpi.lean.js", "/ran/assets/mdn_pdf.DbNmeC8H.webp", -"/ran/assets/cn_index.md.DRjzDfRD.lean.js", -"/ran/assets/src_ranui_tabs_index.md.CPGXXUJu.lean.js", -"/ran/assets/src_article_sort_radix_index.md.BfE2sE6Y.js", -"/ran/assets/src_ranui_popover_index.md.CfxjwwU_.lean.js", -"/ran/assets/src_ranuts_utils_filterObj.md.BsaBmsvk.js", +"/ran/assets/cn_src_ranuts_file_readFile.md.nK6bqV_e.lean.js", +"/ran/assets/cn_src_article_typescript_recursion.md.BuRNB37-.lean.js", +"/ran/assets/src_ranui_progress_index.md.z1F0wQbE.lean.js", +"/ran/assets/cn_src_ranui_preview_index.md.CjuF-KUm.lean.js", +"/ran/assets/src_ranui_button_index.md.C5LIQdyS.js", +"/ran/assets/src_article_sort_merge_index.md.DR-N5gUH.js", +"/ran/assets/cn_src_article_sort_bubble_index.md.Cp1RBpmv.lean.js", +"/ran/assets/cn_src_ranuts_mode_subscribe.md.DVNH30m1.lean.js", +"/ran/assets/cn_src_ranuts_utils_task.md.DbClSCsQ.lean.js", "/ran/assets/组合.StqZ1pDc.png", +"/ran/assets/src_article_sort_shell_index.md.H4IG1J-3.lean.js", "/ran/assets/extra.Da45cF33.jpeg", -"/ran/assets/cn_src_ranui_popover_index.md.DRuLc3Ni.lean.js", "/ran/assets/wps_office.DiET-U8x.webp", "/ran/assets/inter-roman-greek.BBVDIX6e.woff2", -"/ran/assets/src_ranuts_file_writeFile.md.D0A_cl3U.js", -"/ran/assets/cn_src_article_sort_bubble_index.md.CjZlxYfr.js", -"/ran/assets/cn_src_ranui_image_index.md.DowaFgBv.lean.js", -"/ran/assets/cn_src_article_sort_index.md.D92LVwEh.js", -"/ran/assets/cn_src_ranui_radar_index.md.A6jKbspG.lean.js", -"/ran/assets/src_ranuts_bundler_index.md.2d_kwA5U.js", -"/ran/assets/src_ranui_preview_index.md.fG1IQRia.js", -"/ran/assets/cn_src_ranuts_mimeType_mimeType.md.DNyJyegy.lean.js", -"/ran/assets/cn_src_ranuts_utils_getCookie.md.BomC6eQg.lean.js", -"/ran/assets/src_article_sort_quick_index.md.DR2SVz8M.js", +"/ran/assets/src_article_typescript_reconstruction.md.CSOt7yMn.js", +"/ran/assets/cn_src_ranui_player_index.md.PhEE5Km4.js", +"/ran/assets/cn_index.md.C-Prq36L.js", "/ran/assets/bubble.Csp5B4TH.gif", -"/ran/assets/cn_src_ranui_modal_index.md.I-C9OtVX.lean.js", -"/ran/assets/cn_src_article_functionalProgramming.md.CkKiYr9L.lean.js", -"/ran/assets/src_article_sort_index.md.ILCQfWPM.js", -"/ran/assets/src_ranuts_binaryTree_index.md.9VY_7CtH.lean.js", -"/ran/assets/src_ranui_message_index.md.C7vn1gHP.js", -"/ran/assets/cn_src_ranui_preview_index.md.BsAShiRh.lean.js", +"/ran/assets/src_article_functionalProgramming.md.dIGyJ6sB.js", +"/ran/assets/cn_src_article_sort_merge_index.md.CkGKR7pJ.lean.js", +"/ran/assets/cn_src_article_sort_index.md.BocISVrP.js", "/ran/assets/bilibili_video_m4s.BccuY7bk.webp", -"/ran/assets/cn_src_types_类型运算.md.Q4zNTo0P.js", +"/ran/assets/cn_src_article_sort_bubble_index.md.Cp1RBpmv.js", +"/ran/assets/src_ranuts_utils_formatJson.md.CSMLr8Hr.lean.js", +"/ran/assets/src_types_高级类型.md.CufDmqA6.js", +"/ran/assets/src_article_sort_count_index.md.BXZiVRgc.lean.js", +"/ran/assets/src_ranui_popover_index.md.Bq9gtddN.lean.js", +"/ran/assets/cn_src_types_高级类型.md.DshdJwmZ.lean.js", +"/ran/assets/src_ranuts_utils_ocr.md.DzafMtkn.lean.js", +"/ran/assets/index.md.B_9rwraW.lean.js", "/ran/assets/sort.CSVZS1AV.png", -"/ran/assets/src_ranuts_file_writeFile.md.D0A_cl3U.lean.js", "/ran/assets/Class.Cx5QD1OX.jpeg", -"/ran/assets/src_article_sort_bucket_index.md.B2XZzvVq.lean.js", -"/ran/assets/src_ranuts_utils_ocr.md.l96JLeA3.lean.js", -"/ran/assets/cn_src_ranui_math_index.md.VRI2riCL.js", "/ran/assets/bili_demo.CI8Ur8IA.webp", -"/ran/assets/cn_src_ranuts_bundler_index.md.gFLefqgx.lean.js", -"/ran/assets/src_ranui_tab_index.md.CnkY3B_Y.js", -"/ran/assets/src_article_typescript_pattern.md.ChySx5n3.lean.js", -"/ran/assets/src_types_模式匹配.md.CC8I3wm1.lean.js", -"/ran/assets/cn_src_ranuts_file_readFile.md.DqgoToSw.lean.js", -"/ran/assets/cn_src_article_typescript_pattern.md.rnM0NHZ9.lean.js", -"/ran/assets/src_article_imagemin.md.BAQ0hCS3.js", -"/ran/assets/src_ranui_radar_index.md.DC-fIIc-.lean.js", -"/ran/assets/cn_src_article_astParse_tokenizer.md._qy1-yRL.lean.js", -"/ran/assets/cn_src_ranuts_file_readDir.md.BSttmwRD.lean.js", +"/ran/assets/cn_src_ranui_message_index.md.DQuTGF50.lean.js", +"/ran/assets/cn_src_note_ubuntu.md.pqpeIfp6.js", +"/ran/assets/src_ranui_player_index.md._41AQgcv.js", +"/ran/assets/cn_src_article_typescript_unionType.md.wPcbHmYa.js", +"/ran/assets/src_article_javascript_domLoad.md.Dd7Dzr5Y.lean.js", +"/ran/assets/src_ranui_index.md.DftpvnGE.js", +"/ran/assets/cn_src_ranui_loading_index.md.CO9CpYNH.lean.js", +"/ran/assets/src_ranui_checkbox_index.md.Dmwi-qhd.js", +"/ran/assets/cn_src_ranui_select_index.md.BygieB1y.lean.js", +"/ran/assets/cn_src_ranui_select_index.md.BygieB1y.js", +"/ran/assets/src_ranuts_file_appendFile.md.Ba1ZPoPO.js", +"/ran/assets/src_ranuts_file_readDir.md.BDf-8MWg.lean.js", "/ran/assets/File.BiH2GpuW.jpeg", -"/ran/assets/src_ranuts_mode_subscribe.md.CtPQvPCj.js", -"/ran/assets/src_ranui_loading_index.md.iV1VL5bO.lean.js", -"/ran/assets/src_article_typescript_pattern.md.ChySx5n3.js", -"/ran/assets/src_article_typescript_calculate.md.xkHvMeV2.lean.js", -"/ran/assets/src_article_babel.md.Czc7FSEu.js", -"/ran/assets/src_article_javascript_domLoad.md.BMbEujHQ.lean.js", -"/ran/assets/cn_src_article_functionalProgramming.md.CkKiYr9L.js", -"/ran/assets/src_ranui_skeleton_index.md.J2D8qbZD.js", -"/ran/assets/cn_src_ranuts_mode_subscribe.md.BhBmLNNr.lean.js", -"/ran/assets/src_article_babel.md.Czc7FSEu.lean.js", +"/ran/assets/src_types_模式匹配.md.CjXSWGVq.js", +"/ran/assets/cn_src_article_typescript_pattern.md.CyszQeR8.js", +"/ran/assets/cn_src_ranui_image_index.md.C-xnLYah.lean.js", +"/ran/assets/src_ranuts_mimeType_mimeType.md.CxFL5631.js", +"/ran/assets/cn_src_article_bundle.md.OaaTEdt2.lean.js", +"/ran/assets/src_ranui_modal_index.md.BfBNxpQt.lean.js", "/ran/assets/ms_excel.CJXFi2bf.webp", -"/ran/assets/cn_src_article_systemDesign.md.hOp1x72G.js", -"/ran/assets/src_ranui_input_index.md.D8sbP-uy.lean.js", +"/ran/assets/cn_src_ranui_input_index.md.DottgzSq.lean.js", +"/ran/assets/src_ranuts_file_watchFile.md.CRypAqqF.lean.js", +"/ran/assets/src_ranui_radar_index.md.B3Rqerka.js", +"/ran/assets/src_ranui_tabs_index.md.CxBjn965.js", +"/ran/assets/cn_src_ranui_skeleton_index.md.PVahOUCW.js", +"/ran/assets/cn_src_ranuts_file_watchFile.md.CAsEL4vf.js", "/ran/assets/inter-roman-cyrillic.C5lxZ8CY.woff2", +"/ran/assets/src_article_sort_quick_index.md.B-15itZC.js", "/ran/assets/inter-roman-vietnamese.BjW4sHH5.woff2", -"/ran/assets/cn_src_ranuts_file_appendFile.md.Kjwfv66v.lean.js", -"/ran/assets/cn_src_article_sort_heap_index.md.CkqW8bYY.lean.js", -"/ran/assets/cn_src_ranui_modal_index.md.I-C9OtVX.js", -"/ran/assets/cn_src_ranuts_index.md.ImKijNhD.lean.js", -"/ran/assets/src_ranui_player_index.md.DP3RaPdA.lean.js", -"/ran/assets/cn_src_article_typescript_unionType.md.atUNmveE.lean.js", +"/ran/assets/cn_src_ranuts_index.md.CuyLwwdp.js", "/ran/assets/ExpressionStatement.zaIHlhIF.jpeg", -"/ran/assets/cn_src_ranuts_utils_convertImageToBase64.md.DXYg1zir.lean.js", +"/ran/assets/cn_src_ranuts_utils_convertImageToBase64.md.DeS8CqKI.js", +"/ran/assets/cn_src_types_类型运算.md.HXO7_zmg.lean.js", +"/ran/assets/src_ranui_player_index.md._41AQgcv.lean.js", "/ran/assets/red_book.DiBEvryP.webp", -"/ran/assets/src_ranui_button_index.md.OpGrfpg8.lean.js", -"/ran/assets/cn_src_ranui_skeleton_index.md.t-ZVwoSq.js", -"/ran/assets/cn_src_article_typescript_index.md.1jbAHunE.js", -"/ran/assets/src_ranui_button_index.md.OpGrfpg8.js", -"/ran/assets/cn_src_article_javascript_domLoad.md.Ci82ToLN.lean.js", +"/ran/assets/src_ranui_modal_index.md.BfBNxpQt.js", +"/ran/assets/cn_src_ranui_tab_index.md.CPn99LR8.js", +"/ran/assets/src_ranuts_index.md.DZGRxbxI.lean.js", +"/ran/assets/cn_src_ranuts_file_writeFile.md.BoU7gKL6.js", +"/ran/assets/src_ranui_math_index.md.BX7dsUxQ.js", +"/ran/assets/src_ranuts_file_appendFile.md.Ba1ZPoPO.lean.js", +"/ran/assets/src_article_sort_index.md.Du9jHICi.js", +"/ran/assets/cn_src_ranui_checkbox_index.md.C3KmEc2G.js", "/ran/assets/ms_word.3k-0mjp0.webp", "/ran/assets/ms_support.CaZSSiRt.webp", -"/ran/assets/src_types_模式匹配.md.CC8I3wm1.js", -"/ran/assets/cn_src_ranuts_utils_filterObj.md.DE1C38Kh.js", "/ran/assets/ms_file_not.DgOrkG3n.webp", -"/ran/assets/src_ranui_select_index.md.BtLjKVVg.js", -"/ran/assets/cn_src_article_visual.md.Du_v00-A.js", -"/ran/assets/cn_src_note_ubuntu.md.DgjTInOe.lean.js", -"/ran/assets/cn_src_note_centos.md.CQEnE6Ac.lean.js", +"/ran/assets/src_ranui_icon_index.md.DHD0uzGs.lean.js", +"/ran/assets/src_article_sort_select_index.md.sRykeoeT.lean.js", +"/ran/assets/src_ranuts_binaryTree_index.md.BOOvvNkp.lean.js", +"/ran/assets/src_ranui_progress_index.md.z1F0wQbE.js", +"/ran/assets/src_article_typescript_pattern.md.3sU5fRCA.lean.js", +"/ran/assets/src_article_typescript_index.md.DeH7pgUe.lean.js", +"/ran/assets/cn_src_note_libreoffice2wasm.md.DGtQ0t2p.js", "/ran/assets/inter-roman-greek-ext.CqjqNYQ-.woff2", -"/ran/assets/src_ranui_progress_index.md.cmnI4FIh.lean.js", -"/ran/assets/cn_src_types_模式匹配.md.LMxiYHqa.lean.js", -"/ran/assets/cn_src_article_visual.md.Du_v00-A.lean.js", -"/ran/assets/cn_src_ranui_preview_index.md.BsAShiRh.js", +"/ran/assets/src_article_babel.md.D6U-I50A.lean.js", +"/ran/assets/src_ranuts_file_fileInfo.md.C3Zp4I69.lean.js", +"/ran/assets/cn_src_article_typescript_reconstruction.md.B9hETE9S.js", "/ran/assets/input-input.1X1aE5oH.jpg", -"/ran/assets/src_article_designMode.md.GNIygirc.lean.js", +"/ran/assets/cn_src_ranui_skeleton_index.md.PVahOUCW.lean.js", +"/ran/assets/cn_src_article_sort_bucket_index.md.DART29Tq.lean.js", "/ran/assets/inter-roman-latin.Di8DUHzh.woff2", -"/ran/assets/cn_src_article_typescript_calculate.md.CNAvvheA.js", +"/ran/assets/cn_src_ranui_progress_index.md.CLS6wwle.lean.js", "/ran/assets/ts_demo.D_l_mv9k.webp", -"/ran/assets/cn_src_ranui_input_index.md.BcdnxU38.lean.js", -"/ran/assets/src_article_sort_quick_index.md.DR2SVz8M.lean.js", -"/ran/assets/cn_src_ranuts_file_readFile.md.DqgoToSw.js", -"/ran/assets/src_ranuts_bundler_index.md.2d_kwA5U.lean.js", -"/ran/assets/src_ranuts_utils_getCookie.md.CDeVa4hl.js", -"/ran/assets/cn_src_ranuts_utils_task.md.DwcnyfHt.js", +"/ran/assets/cn_src_note_docker.md.tDnzoB7w.js", +"/ran/assets/src_ranuts_utils_task.md.CapuHzRA.js", +"/ran/assets/cn_src_ranuts_file_fileInfo.md.KotpDHQJ.js", +"/ran/assets/src_ranui_button_index.md.C5LIQdyS.lean.js", +"/ran/assets/src_article_designMode.md.DUzkKke4.js", +"/ran/assets/cn_src_ranuts_binaryTree_index.md.DrXBmpfQ.lean.js", "/ran/assets/inter-roman-latin-ext.4ZJIpNVo.woff2", -"/ran/assets/cn_src_ranuts_file_appendFile.md.Kjwfv66v.js", -"/ran/assets/src_article_typescript_index.md.DQFvubag.js", -"/ran/assets/src_ranuts_utils_task.md.CgGq5wbB.js", -"/ran/assets/src_ranui_input_index.md.D8sbP-uy.js", +"/ran/assets/src_ranui_select_index.md.B8UBMGlm.lean.js", +"/ran/assets/cn_src_ranuts_mimeType_mimeType.md.C1HE55kh.js", "/ran/assets/inter-italic-cyrillic.By2_1cv3.woff2", -"/ran/assets/src_ranui_math_index.md.BJRXy7dX.lean.js", -"/ran/assets/cn_src_article_typescript_unionType.md.atUNmveE.js", -"/ran/assets/src_ranuts_index.md.Q_PSqhjV.js", -"/ran/assets/cn_src_types_高级类型.md.CX5Or8t7.lean.js", -"/ran/assets/src_article_sort_select_index.md.D6mV4SPJ.js", -"/ran/assets/src_article_designMode.md.GNIygirc.js", -"/ran/assets/cn_src_article_typescript_index.md.1jbAHunE.lean.js", -"/ran/assets/cn_src_article_systemDesign.md.hOp1x72G.lean.js", -"/ran/assets/cn_src_article_sort_bucket_index.md.B4drqe-3.js", -"/ran/assets/src_ranuts_utils_formatJson.md.DNKXhroe.lean.js", -"/ran/assets/cn_src_article_designMode.md.DZ98r33q.js", +"/ran/assets/cn_src_ranuts_utils_ocr.md.uNdytYyR.lean.js", +"/ran/assets/cn_src_ranui_tabs_index.md.7O7hxEi8.js", +"/ran/assets/src_ranuts_utils_task.md.CapuHzRA.lean.js", +"/ran/assets/src_ranui_radar_index.md.B3Rqerka.lean.js", +"/ran/assets/cn_src_ranuts_bundler_index.md.CNoHThyX.lean.js", +"/ran/assets/cn_src_note_centos.md.DNrgG0Q4.lean.js", +"/ran/assets/cn_src_types_高级类型.md.DshdJwmZ.js", +"/ran/assets/cn_src_article_visual.md.BO64nAx5.js", "/ran/assets/状态.Bt_a2OKX.png", -"/ran/assets/cn_src_article_typescript_recursion.md.D22JKCo3.js", +"/ran/assets/src_article_sort_select_index.md.sRykeoeT.js", "/ran/assets/原型.DYbH0CSA.jpg", -"/ran/assets/src_article_sort_index.md.ILCQfWPM.lean.js", -"/ran/assets/cn_src_ranuts_index.md.ImKijNhD.js", -"/ran/assets/src_ranuts_utils_convertImageToBase64.md.CGjlmYhP.lean.js", +"/ran/assets/cn_src_ranui_button_index.md.BoAZB7ta.lean.js", +"/ran/assets/cn_src_ranui_preview_index.md.CjuF-KUm.js", "/ran/assets/xgplayer_docs.CpHb1Wan.webp", -"/ran/assets/src_ranui_modal_index.md.DEMwPGEr.js", +"/ran/assets/cn_src_article_typescript_reconstruction.md.B9hETE9S.lean.js", "/ran/assets/bundle.bky0NmdF.png", -"/ran/assets/cn_src_ranui_loading_index.md.CA72DxYe.js", "/ran/assets/axtexplorerSave.a5hTrvd2.jpeg", +"/ran/assets/cn_src_ranui_popover_index.md.BNd4uUYL.lean.js", "/ran/assets/axtexplorer.D7PG-3cx.jpeg", -"/ran/assets/cn_src_types_TS类型.md.BdnhcvJe.lean.js", -"/ran/assets/cn_src_article_sort_bubble_index.md.CjZlxYfr.lean.js", -"/ran/assets/src_article_sort_heap_index.md.DrKoQkIR.lean.js", -"/ran/assets/cn_src_ranuts_utils_convertImageToBase64.md.DXYg1zir.js", -"/ran/assets/cn_src_article_typescript_recursion.md.D22JKCo3.lean.js", "/ran/assets/装饰.CuuWN9YK.jpg", -"/ran/assets/src_article_bundle.md.DqBSsozI.lean.js", -"/ran/assets/cn_src_ranui_select_index.md.CmisBOzA.js", -"/ran/assets/cn_src_article_video.md.Dr5fjwZA.js", -"/ran/assets/src_ranui_tabs_index.md.CPGXXUJu.js", -"/ran/assets/cn_src_article_sort_radix_index.md.D1vfzfWU.lean.js", +"/ran/assets/cn_src_article_sort_index.md.BocISVrP.lean.js", "/ran/assets/Declaration.CplvpFd-.jpeg", -"/ran/assets/cn_src_ranui_radar_index.md.A6jKbspG.js", +"/ran/assets/cn_src_ranui_message_index.md.DQuTGF50.js", +"/ran/assets/src_article_sort_insert_index.md.CBL5Zq0h.js", "/ran/assets/Statement.9lGuRes5.jpeg", -"/ran/assets/src_article_typescript_unionType.md.D4NH8xmg.lean.js", -"/ran/assets/cn_src_article_babel.md.e4GAuw5X.lean.js", +"/ran/assets/cn_src_article_bundle.md.OaaTEdt2.js", +"/ran/assets/src_ranui_input_index.md.DFv44XMF.lean.js", +"/ran/assets/cn_src_ranuts_index.md.CuyLwwdp.lean.js", +"/ran/assets/cn_src_article_functionalProgramming.md.kIfOv665.lean.js", +"/ran/assets/cn_src_ranuts_utils_ocr.md.uNdytYyR.js", +"/ran/assets/src_ranuts_file_writeFile.md.ouweFqJg.lean.js", +"/ran/assets/src_ranuts_file_fileInfo.md.C3Zp4I69.js", +"/ran/assets/cn_src_article_sort_radix_index.md.DL17V-7-.js", +"/ran/assets/src_ranui_popover_index.md.Bq9gtddN.js", "/ran/assets/app.BdCz2uAc.js", -"/ran/assets/cn_src_article_docPreview.md.to4R_V9b.lean.js", -"/ran/assets/cn_src_ranui_player_index.md.CuAqghFD.lean.js", -"/ran/assets/cn_src_ranui_image_index.md.DowaFgBv.js", -"/ran/assets/cn_src_ranui_popover_index.md.DRuLc3Ni.js", -"/ran/assets/src_ranuts_mimeType_mimeType.md.CD3nVZEO.lean.js", -"/ran/assets/cn_src_ranui_tabs_index.md.D-Z5zQWG.lean.js", -"/ran/assets/cn_src_note_docker.md.Cdo71zW_.lean.js", -"/ran/assets/src_ranui_popover_index.md.CfxjwwU_.js", -"/ran/assets/cn_src_ranuts_file_writeFile.md.mwv7EGlj.js", -"/ran/assets/src_article_astParse_tokenizer.md.B5PslVvl.lean.js", -"/ran/assets/index.md.C05wkIRp.lean.js", -"/ran/assets/src_article_sort_radix_index.md.BfE2sE6Y.lean.js", -"/ran/assets/src_ranui_radar_index.md.DC-fIIc-.js", -"/ran/assets/cn_src_article_imagemin.md.CHqS0vGt.lean.js", -"/ran/assets/cn_src_article_sort_shell_index.md.DecAJ1tS.lean.js", -"/ran/assets/src_article_typescript_recursion.md.PrJfeezf.js", -"/ran/assets/src_article_sort_bucket_index.md.B2XZzvVq.js", -"/ran/assets/src_ranuts_file_readDir.md.D-wGUvqF.js", -"/ran/assets/cn_src_article_bundle.md.CXbozmz-.js", -"/ran/assets/cn_src_types_模式匹配.md.LMxiYHqa.js", -"/ran/assets/cn_src_article_sort_quick_index.md.CvZw-icp.lean.js", +"/ran/assets/src_ranuts_bundler_index.md.BBvegtDt.js", +"/ran/assets/src_article_typescript_index.md.DeH7pgUe.js", +"/ran/assets/src_article_sort_merge_index.md.DR-N5gUH.lean.js", +"/ran/assets/src_ranui_preview_index.md.tg6oXUar.lean.js", +"/ran/assets/cn_src_note_libreoffice2wasm.md.DGtQ0t2p.lean.js", +"/ran/assets/src_article_sort_bubble_index.md.BmVWI7FN.lean.js", +"/ran/assets/src_article_functionalProgramming.md.dIGyJ6sB.lean.js", +"/ran/assets/src_ranui_math_index.md.BX7dsUxQ.lean.js", +"/ran/assets/src_types_TS类型.md.DIHmZPe4.lean.js", +"/ran/assets/cn_src_article_typescript_unionType.md.wPcbHmYa.lean.js", +"/ran/assets/src_ranui_message_index.md.DpTwiP3x.lean.js", +"/ran/assets/src_article_typescript_reconstruction.md.CSOt7yMn.lean.js", +"/ran/assets/cn_src_note_centos.md.DNrgG0Q4.js", +"/ran/assets/src_types_模式匹配.md.CjXSWGVq.lean.js", +"/ran/assets/cn_src_article_sort_count_index.md.00GyLjR_.lean.js", +"/ran/assets/cn_src_article_sort_quick_index.md.CGqy4-ZS.lean.js", +"/ran/assets/src_article_imagemin.md.CBY6W2re.js", +"/ran/assets/src_ranui_image_index.md.DuNw7DgW.lean.js", +"/ran/assets/cn_src_ranuts_mimeType_mimeType.md.C1HE55kh.lean.js", +"/ran/assets/src_article_sort_bucket_index.md.C8sI_tGv.lean.js", +"/ran/assets/src_ranuts_utils_filterObj.md.BtAgodt-.lean.js", +"/ran/assets/src_ranuts_utils_ocr.md.DzafMtkn.js", "/ran/assets/xdoc.CeowcMPq.webp", -"/ran/assets/src_article_sort_heap_index.md.DrKoQkIR.js", +"/ran/assets/src_ranui_skeleton_index.md.8I5i20E1.lean.js", +"/ran/assets/cn_src_ranuts_utils_convertImageToBase64.md.DeS8CqKI.lean.js", +"/ran/assets/cn_src_ranui_modal_index.md.C7YyXb2j.lean.js", "/ran/assets/bilibili_video_code.DgWtgAEf.webp", -"/ran/assets/cn_src_ranui_tab_index.md.D3FaivVj.js", -"/ran/assets/src_ranuts_file_readFile.md.DzoyHHIO.js", -"/ran/assets/src_ranui_modal_index.md.DEMwPGEr.lean.js", -"/ran/assets/cn_src_ranuts_file_readDir.md.BSttmwRD.js", -"/ran/assets/src_ranuts_file_readFile.md.DzoyHHIO.lean.js", -"/ran/assets/src_ranui_image_index.md.ntBTaVra.lean.js", -"/ran/assets/cn_src_note_libreoffice2wasm.md.D2SYnyUq.lean.js", +"/ran/assets/cn_src_article_sort_select_index.md.CnGat9lb.lean.js", +"/ran/assets/cn_src_article_javascript_domLoad.md.B74fIpy6.js", +"/ran/assets/cn_src_article_sort_heap_index.md.CzO5sZ8i.lean.js", +"/ran/assets/cn_src_article_imagemin.md.DFEWNSIZ.lean.js", +"/ran/assets/cn_src_ranui_index.md.CrHo0ngz.lean.js", "/ran/assets/firefox_support_media.BLmSeBNy.webp", -"/ran/assets/cn_src_article_sort_heap_index.md.CkqW8bYY.js", -"/ran/assets/src_ranuts_file_watchFile.md.6J1Mi6RC.js", -"/ran/assets/cn_src_article_astParse_tokenizer.md._qy1-yRL.js", -"/ran/assets/src_article_imagemin.md.BAQ0hCS3.lean.js", -"/ran/assets/cn_src_ranuts_binaryTree_index.md.By-o1AjL.js", -"/ran/assets/cn_src_note_docker.md.Cdo71zW_.js", -"/ran/assets/src_ranui_tab_index.md.CnkY3B_Y.lean.js", +"/ran/assets/cn_src_ranui_modal_index.md.C7YyXb2j.js", +"/ran/assets/src_article_typescript_calculate.md.C7yhKz7X.js", +"/ran/assets/cn_src_ranui_math_index.md.DmcvA4-2.js", +"/ran/assets/cn_src_article_sort_shell_index.md.DLjGy-JA.js", +"/ran/assets/cn_src_article_imagemin.md.DFEWNSIZ.js", "/ran/assets/chunks/check-circle-szyAJiap.CM_vbBX5.js", "/ran/assets/chunks/loading-scene-BMc2wqKm.Di19NrRU.js", "/ran/assets/chunks/team-tl4NJXPC.D7881a1v.js", @@ -478,134 +474,136 @@ const SERVICE_WORK_CACHE_FILE_PATHS = [ "/ran/assets/chunks/bubble.Dg5jgvyl.js", "/ran/assets/chunks/power-off-lQRbiBak.r13EH4bb.js", "/ran/assets/style.0WEJ_Nz4.css", -"/ran/assets/cn_src_note_centos.md.CQEnE6Ac.js", +"/ran/assets/cn_src_ranui_player_index.md.PhEE5Km4.lean.js", "/ran/assets/ms_ppt.C2zYd_IC.webp", -"/ran/assets/src_ranuts_file_watchFile.md.6J1Mi6RC.lean.js", -"/ran/assets/cn_src_article_sort_radix_index.md.D1vfzfWU.js", -"/ran/assets/src_ranuts_mode_subscribe.md.CtPQvPCj.lean.js", +"/ran/assets/src_article_sort_radix_index.md.DYGHdCvy.lean.js", +"/ran/assets/src_ranuts_binaryTree_index.md.BOOvvNkp.js", +"/ran/assets/src_ranui_image_index.md.DuNw7DgW.js", +"/ran/assets/src_ranui_checkbox_index.md.Dmwi-qhd.lean.js", +"/ran/assets/src_article_sort_insert_index.md.CBL5Zq0h.lean.js", "/ran/assets/quick.DD28bswc.gif", -"/ran/assets/cn_src_article_sort_select_index.md.HS1vLdcG.lean.js", -"/ran/assets/src_article_javascript_domLoad.md.BMbEujHQ.js", +"/ran/assets/cn_src_article_sort_heap_index.md.CzO5sZ8i.js", "/ran/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2", -"/ran/assets/cn_src_article_bundle.md.CXbozmz-.lean.js", -"/ran/assets/src_ranuts_utils_formatJson.md.DNKXhroe.js", +"/ran/assets/cn_src_article_astParse_tokenizer.md.X9WaN6nP.js", +"/ran/assets/cn_src_ranui_progress_index.md.CLS6wwle.js", +"/ran/assets/src_ranuts_file_watchFile.md.CRypAqqF.js", +"/ran/assets/src_article_babel.md.D6U-I50A.js", +"/ran/assets/cn_src_article_systemDesign.md.6LK-pZuK.lean.js", +"/ran/assets/cn_src_article_functionalProgramming.md.kIfOv665.js", +"/ran/assets/cn_src_ranuts_utils_formatJson.md.DAOEUsMy.lean.js", "/ran/assets/select.B8GwndZy.gif", "/ran/assets/建造者.B6neb_7R.jpeg", "/ran/assets/ms_answer_2.D-D9H1v0.webp", -"/ran/assets/src_ranui_progress_index.md.cmnI4FIh.js", -"/ran/assets/src_ranui_loading_index.md.iV1VL5bO.js", -"/ran/assets/src_ranui_select_index.md.BtLjKVVg.lean.js", -"/ran/assets/cn_src_ranuts_utils_ocr.md.Bsfwykuh.lean.js", +"/ran/assets/src_article_sort_count_index.md.BXZiVRgc.js", +"/ran/assets/cn_src_ranuts_mode_subscribe.md.DVNH30m1.js", +"/ran/assets/src_ranui_message_index.md.DpTwiP3x.js", +"/ran/assets/src_article_sort_radix_index.md.DYGHdCvy.js", "/ran/assets/import.BTsVI5Tc.jpeg", -"/ran/assets/src_ranui_checkbox_index.md.C6CmsGDw.lean.js", -"/ran/assets/cn_src_ranuts_file_watchFile.md.DAZXSmjV.lean.js", -"/ran/assets/src_article_bundle.md.DqBSsozI.js", -"/ran/assets/src_article_sort_bubble_index.md.LfnS1mFU.js", +"/ran/assets/cn_src_article_javascript_domLoad.md.B74fIpy6.lean.js", +"/ran/assets/cn_src_article_typescript_recursion.md.BuRNB37-.js", "/ran/assets/safari_support_media.Bafr23bR.webp", "/ran/assets/访问者.aEI4m-5a.png", -"/ran/assets/src_article_typescript_recursion.md.PrJfeezf.lean.js", "/ran/assets/ms_answer.Cgv6ylFF.webp", -"/ran/assets/src_article_sort_select_index.md.D6mV4SPJ.lean.js", -"/ran/assets/src_article_typescript_reconstruction.md.CohgiGIS.lean.js", +"/ran/assets/cn_src_article_designMode.md.DOHuh5Vx.js", "/ran/assets/桥接.DX0mO5JC.png", "/ran/assets/google_doc_view.BknjnOKw.webp", -"/ran/assets/src_ranuts_file_appendFile.md.CHmuoXqR.lean.js", -"/ran/assets/cn_src_ranui_icon_index.md.NbG8FVyF.lean.js", +"/ran/assets/cn_index.md.C-Prq36L.lean.js", +"/ran/assets/src_ranui_preview_index.md.tg6oXUar.js", +"/ran/assets/cn_src_article_sort_insert_index.md.DjxCK_3e.js", +"/ran/assets/cn_src_ranuts_file_appendFile.md.BDgZPn7V.lean.js", +"/ran/assets/cn_src_ranui_icon_index.md.BB3PfUZM.lean.js", +"/ran/assets/cn_src_article_designMode.md.DOHuh5Vx.lean.js", "/ran/assets/inter-italic-greek.DJ8dCoTZ.woff2", -"/ran/assets/src_article_typescript_unionType.md.D4NH8xmg.js", +"/ran/assets/cn_src_ranuts_utils_str2xml.md.s2QXhzVM.lean.js", "/ran/assets/inter-italic-greek-ext.1u6EdAuj.woff2", -"/ran/assets/src_article_sort_insert_index.md.DkXN_nPk.lean.js", -"/ran/assets/cn_src_ranuts_utils_str2xml.md.Bf-gtS9N.js", "/ran/assets/策略.BAijEgGz.png", -"/ran/assets/cn_src_ranui_progress_index.md.m21IXa5G.lean.js", -"/ran/assets/cn_src_types_类型运算.md.Q4zNTo0P.lean.js", -"/ran/assets/cn_src_article_sort_bucket_index.md.B4drqe-3.lean.js", -"/ran/assets/src_ranui_checkbox_index.md.C6CmsGDw.js", -"/ran/assets/cn_src_article_typescript_reconstruction.md.BhFbdKZJ.js", -"/ran/assets/cn_src_ranui_icon_index.md.NbG8FVyF.js", -"/ran/assets/cn_src_ranui_checkbox_index.md.ZHU13zPM.lean.js", -"/ran/assets/src_article_sort_bubble_index.md.LfnS1mFU.lean.js", +"/ran/assets/src_article_typescript_recursion.md.BD02XaoF.lean.js", +"/ran/assets/cn_src_article_sort_quick_index.md.CGqy4-ZS.js", +"/ran/assets/cn_src_ranuts_utils_getCookie.md.DbhTAbDg.lean.js", +"/ran/assets/cn_src_ranui_math_index.md.DmcvA4-2.lean.js", +"/ran/assets/cn_src_article_astParse_tokenizer.md.X9WaN6nP.lean.js", +"/ran/assets/src_ranuts_utils_getCookie.md.C9JVGfW9.js", +"/ran/assets/cn_src_ranuts_file_fileInfo.md.KotpDHQJ.lean.js", +"/ran/assets/src_ranuts_file_readDir.md.BDf-8MWg.js", "/ran/assets/count.CWSWBe_h.gif", -"/ran/assets/src_ranuts_file_fileInfo.md.BGMu3rbo.js", +"/ran/assets/cn_src_note_ubuntu.md.pqpeIfp6.lean.js", "/ran/assets/inter-italic-latin.C2AdPX0b.woff2", "/ran/assets/customElements.DbqgaaNb.png", -"/ran/assets/src_article_sort_merge_index.md.BrDl4p8K.js", -"/ran/assets/cn_src_article_sort_merge_index.md.MDU-inBg.js", -"/ran/assets/cn_src_ranuts_mimeType_mimeType.md.DNyJyegy.js", -"/ran/assets/src_types_类型运算.md.CYIL5e8N.lean.js", -"/ran/assets/cn_src_ranui_index.md.DHsUGsLz.js", +"/ran/assets/src_article_sort_quick_index.md.B-15itZC.lean.js", +"/ran/assets/cn_src_ranuts_utils_filterObj.md.Dr_ls9ui.lean.js", +"/ran/assets/cn_src_ranui_tabs_index.md.7O7hxEi8.lean.js", +"/ran/assets/src_types_高级类型.md.CufDmqA6.lean.js", "/ran/assets/inter-italic-latin-ext.CN1xVJS-.woff2", -"/ran/assets/cn_src_article_sort_count_index.md.DYoyFiDb.js", -"/ran/assets/src_ranui_math_index.md.BJRXy7dX.js", +"/ran/assets/src_ranui_loading_index.md.EajM1Fh_.js", "/ran/assets/Comment.BYtNY-L1.jpeg", -"/ran/assets/cn_src_ranui_button_index.md.CGOk0U0f.lean.js", -"/ran/assets/cn_src_ranui_checkbox_index.md.ZHU13zPM.js", "/ran/assets/balanceTree.DP_9yIkO.png", -"/ran/assets/cn_src_ranuts_file_writeFile.md.mwv7EGlj.lean.js", -"/ran/assets/src_ranuts_utils_getCookie.md.CDeVa4hl.lean.js", -"/ran/assets/src_article_sort_count_index.md.DPdRRb52.js", -"/ran/assets/cn_src_article_video.md.Dr5fjwZA.lean.js", -"/ran/assets/src_ranuts_binaryTree_index.md.9VY_7CtH.js", -"/ran/assets/cn_src_ranui_button_index.md.CGOk0U0f.js", -"/ran/assets/src_article_sort_insert_index.md.DkXN_nPk.js", -"/ran/assets/src_ranui_player_index.md.DP3RaPdA.js", -"/ran/assets/cn_src_ranuts_utils_ocr.md.Bsfwykuh.js", -"/ran/assets/src_types_高级类型.md.DrTZYnDE.js", -"/ran/assets/index.md.C05wkIRp.js", +"/ran/assets/src_ranuts_file_writeFile.md.ouweFqJg.js", +"/ran/assets/cn_src_article_sort_count_index.md.00GyLjR_.js", +"/ran/assets/src_article_typescript_pattern.md.3sU5fRCA.js", +"/ran/assets/cn_src_ranui_radar_index.md.BVnDbAlC.lean.js", +"/ran/assets/cn_src_types_TS类型.md.iJyVKiUM.js", +"/ran/assets/cn_src_article_docPreview.md.BriOMnC6.js", +"/ran/assets/src_article_sort_bubble_index.md.BmVWI7FN.js", +"/ran/assets/cn_src_article_typescript_calculate.md.CC_IXoWD.lean.js", +"/ran/assets/src_ranuts_mode_subscribe.md.Psp8bIgo.js", +"/ran/assets/cn_src_article_sort_shell_index.md.DLjGy-JA.lean.js", +"/ran/assets/cn_src_article_systemDesign.md.6LK-pZuK.js", +"/ran/assets/src_ranuts_utils_getCookie.md.C9JVGfW9.lean.js", +"/ran/assets/src_types_类型运算.md.Bf4-_Wi-.lean.js", +"/ran/assets/cn_src_ranui_index.md.CrHo0ngz.js", +"/ran/assets/cn_src_ranui_checkbox_index.md.C3KmEc2G.lean.js", "/ran/assets/享元.EIifVVTy.png", -"/ran/assets/cn_src_ranui_index.md.DHsUGsLz.lean.js", +"/ran/assets/src_ranui_input_index.md.DFv44XMF.js", +"/ran/assets/cn_src_ranuts_utils_getCookie.md.DbhTAbDg.js", +"/ran/assets/cn_src_ranuts_utils_formatJson.md.DAOEUsMy.js", +"/ran/assets/src_ranui_select_index.md.B8UBMGlm.js", +"/ran/assets/src_article_designMode.md.DUzkKke4.lean.js", +"/ran/assets/cn_src_ranui_icon_index.md.BB3PfUZM.js", "/ran/assets/complexity.DSLVsjHt.png", -"/ran/assets/cn_src_ranuts_binaryTree_index.md.By-o1AjL.lean.js", -"/ran/assets/src_ranui_skeleton_index.md.J2D8qbZD.lean.js", -"/ran/assets/src_ranuts_mimeType_mimeType.md.CD3nVZEO.js", -"/ran/assets/src_article_astParse_tokenizer.md.B5PslVvl.js", -"/ran/assets/src_ranuts_utils_task.md.CgGq5wbB.lean.js", -"/ran/assets/cn_src_ranui_input_index.md.BcdnxU38.js", -"/ran/assets/src_article_typescript_index.md.DQFvubag.lean.js", -"/ran/assets/cn_src_article_sort_index.md.D92LVwEh.lean.js", +"/ran/assets/src_ranuts_mimeType_mimeType.md.CxFL5631.lean.js", +"/ran/assets/cn_src_ranuts_file_appendFile.md.BDgZPn7V.js", +"/ran/assets/cn_src_ranui_image_index.md.C-xnLYah.js", +"/ran/assets/cn_src_article_sort_select_index.md.CnGat9lb.js", +"/ran/assets/src_types_类型运算.md.Bf4-_Wi-.js", +"/ran/assets/cn_src_ranuts_file_readDir.md.rKDcx1fc.lean.js", +"/ran/assets/src_ranui_tab_index.md.CeQ2RW9Y.js", +"/ran/assets/cn_src_article_babel.md.BRRU23MO.lean.js", +"/ran/assets/src_article_bundle.md.ChxeIam8.lean.js", +"/ran/assets/src_ranuts_index.md.DZGRxbxI.js", +"/ran/assets/cn_src_ranui_button_index.md.BoAZB7ta.js", "/ran/assets/merge.Bguw-KQu.gif", "/ran/assets/aqiyi_demo.s0swGzvF.webp", -"/ran/assets/cn_src_article_babel.md.e4GAuw5X.js", +"/ran/assets/cn_src_article_docPreview.md.BriOMnC6.lean.js", +"/ran/assets/src_article_javascript_domLoad.md.Dd7Dzr5Y.js", "/ran/assets/inter-italic-cyrillic-ext.r48I6akx.woff2", -"/ran/assets/src_ranui_message_index.md.C7vn1gHP.lean.js", -"/ran/assets/cn_src_ranui_math_index.md.VRI2riCL.lean.js", -"/ran/assets/src_article_sort_shell_index.md.D333S2vN.lean.js", -"/ran/assets/cn_src_ranuts_file_watchFile.md.DAZXSmjV.js", +"/ran/assets/cn_src_ranuts_utils_filterObj.md.Dr_ls9ui.js", "/ran/assets/外观.Cm0-J0eF.png", "/ran/assets/单例.B4dKFqxx.jpg", "/ran/assets/kkfile_doc.CPfEUxoD.webp", "/ran/assets/备忘录.meL0YZxn.jpg", -"/ran/assets/cn_src_ranui_tabs_index.md.D-Z5zQWG.js", -"/ran/assets/src_article_sort_merge_index.md.BrDl4p8K.lean.js", -"/ran/assets/cn_src_ranuts_mode_subscribe.md.BhBmLNNr.js", -"/ran/assets/cn_src_ranuts_utils_str2xml.md.Bf-gtS9N.lean.js", -"/ran/assets/src_article_typescript_calculate.md.xkHvMeV2.js", -"/ran/assets/src_ranuts_file_readDir.md.D-wGUvqF.lean.js", -"/ran/assets/cn_src_article_imagemin.md.CHqS0vGt.js", -"/ran/assets/cn_src_article_typescript_reconstruction.md.BhFbdKZJ.lean.js", +"/ran/assets/src_article_imagemin.md.CBY6W2re.lean.js", +"/ran/assets/src_article_sort_heap_index.md.D8fxvFJ4.js", +"/ran/assets/cn_src_ranuts_file_writeFile.md.BoU7gKL6.lean.js", +"/ran/assets/cn_src_article_sort_radix_index.md.DL17V-7-.lean.js", +"/ran/assets/src_article_sort_index.md.Du9jHICi.lean.js", "/ran/assets/shell.CZ-z1IVg.gif", -"/ran/assets/src_article_sort_count_index.md.DPdRRb52.lean.js", -"/ran/assets/cn_src_ranui_skeleton_index.md.t-ZVwoSq.lean.js", +"/ran/assets/cn_src_ranui_input_index.md.DottgzSq.js", "/ran/assets/bili_demo_url.BQDGtHUp.webp", -"/ran/assets/src_article_functionalProgramming.md.zs1zfDDr.js", -"/ran/assets/src_types_类型运算.md.CYIL5e8N.js", -"/ran/assets/cn_index.md.DRjzDfRD.js", -"/ran/assets/cn_src_ranuts_file_fileInfo.md.Dho5Tv6s.lean.js", +"/ran/assets/src_ranui_index.md.DftpvnGE.lean.js", +"/ran/assets/cn_src_ranui_radar_index.md.BVnDbAlC.js", +"/ran/assets/cn_src_note_docker.md.tDnzoB7w.lean.js", +"/ran/assets/cn_src_ranui_tab_index.md.CPn99LR8.lean.js", +"/ran/assets/src_ranuts_utils_str2xml.md.DiJE8okl.js", "/ran/assets/xml.NyzOyhr4.webp", -"/ran/assets/cn_src_article_javascript_domLoad.md.Ci82ToLN.js", -"/ran/assets/cn_src_ranuts_utils_formatJson.md.C6zYMUay.js", "/ran/assets/video_format.CRMCTmKB.webp", "/ran/assets/inter-italic-vietnamese.BSbpV94h.woff2", -"/ran/assets/cn_src_types_高级类型.md.CX5Or8t7.js", "/ran/icon.png", "/ran/pagefind/wasm.unknown.pagefind", "/ran/pagefind/pagefind-ui.css", "/ran/pagefind/wasm.en.pagefind", "/ran/pagefind/pagefind-ui.js", "/ran/pagefind/pagefind-modular-ui.js", -"/ran/pagefind/pagefind.en_6eed3d3977.pf_meta", "/ran/pagefind/pagefind.js", -"/ran/pagefind/pagefind.zh-cn_8312be599cd33.pf_meta", "/ran/pagefind/index/zh-cn_bb272b7.pf_index", "/ran/pagefind/index/zh-cn_5d1d145.pf_index", "/ran/pagefind/index/zh-cn_16af6ef.pf_index", @@ -614,131 +612,135 @@ const SERVICE_WORK_CACHE_FILE_PATHS = [ "/ran/pagefind/index/en_396d347.pf_index", "/ran/pagefind/index/en_58c6189.pf_index", "/ran/pagefind/index/zh-cn_4f900ab.pf_index", +"/ran/pagefind/pagefind.en_5a3caae56f.pf_meta", +"/ran/pagefind/pagefind.zh-cn_1f13bfc2f3221.pf_meta", "/ran/pagefind/pagefind-entry.json", "/ran/pagefind/pagefind-modular-ui.css", "/ran/pagefind/pagefind-highlight.js", "/ran/pagefind/fragment/en_a116508.pf_fragment", "/ran/pagefind/fragment/en_422fcc1.pf_fragment", +"/ran/pagefind/fragment/en_af4a67a.pf_fragment", "/ran/pagefind/fragment/zh-cn_3fb29d3.pf_fragment", "/ran/pagefind/fragment/zh-cn_3e43b1f.pf_fragment", "/ran/pagefind/fragment/zh-cn_a1e1243.pf_fragment", -"/ran/pagefind/fragment/zh-cn_c11a8a7.pf_fragment", "/ran/pagefind/fragment/en_9755f3c.pf_fragment", "/ran/pagefind/fragment/en_b46590e.pf_fragment", "/ran/pagefind/fragment/zh-cn_544fd92.pf_fragment", "/ran/pagefind/fragment/zh-cn_0ef213d.pf_fragment", "/ran/pagefind/fragment/en_12451bd.pf_fragment", "/ran/pagefind/fragment/zh-cn_c82f3b2.pf_fragment", +"/ran/pagefind/fragment/zh-cn_99e62b8.pf_fragment", "/ran/pagefind/fragment/en_346b990.pf_fragment", "/ran/pagefind/fragment/zh-cn_542bc65.pf_fragment", "/ran/pagefind/fragment/zh-cn_58279de.pf_fragment", "/ran/pagefind/fragment/en_3bf4f84.pf_fragment", "/ran/pagefind/fragment/en_dd6246f.pf_fragment", -"/ran/pagefind/fragment/zh-cn_592cc95.pf_fragment", "/ran/pagefind/fragment/en_7a4eb73.pf_fragment", -"/ran/pagefind/fragment/zh-cn_2ab4b75.pf_fragment", "/ran/pagefind/fragment/en_7322c43.pf_fragment", "/ran/pagefind/fragment/en_f5a1553.pf_fragment", -"/ran/pagefind/fragment/en_2942c3c.pf_fragment", -"/ran/pagefind/fragment/en_c84c5e7.pf_fragment", +"/ran/pagefind/fragment/en_7fffa0e.pf_fragment", "/ran/pagefind/fragment/en_bc653ea.pf_fragment", "/ran/pagefind/fragment/en_6a66788.pf_fragment", +"/ran/pagefind/fragment/en_78f477e.pf_fragment", "/ran/pagefind/fragment/en_1f67d37.pf_fragment", -"/ran/pagefind/fragment/en_4cca5aa.pf_fragment", "/ran/pagefind/fragment/en_7b5a911.pf_fragment", +"/ran/pagefind/fragment/en_70bee3b.pf_fragment", "/ran/pagefind/fragment/zh-cn_51dafe6.pf_fragment", "/ran/pagefind/fragment/zh-cn_44fa7df.pf_fragment", +"/ran/pagefind/fragment/zh-cn_964a4fd.pf_fragment", "/ran/pagefind/fragment/en_222d98b.pf_fragment", +"/ran/pagefind/fragment/zh-cn_217f9f1.pf_fragment", "/ran/pagefind/fragment/en_3f75462.pf_fragment", +"/ran/pagefind/fragment/zh-cn_bc27649.pf_fragment", +"/ran/pagefind/fragment/zh-cn_5f3328b.pf_fragment", "/ran/pagefind/fragment/en_a3a3739.pf_fragment", "/ran/pagefind/fragment/zh-cn_5d1b782.pf_fragment", -"/ran/pagefind/fragment/zh-cn_e7c7085.pf_fragment", "/ran/pagefind/fragment/zh-cn_5f4f874.pf_fragment", +"/ran/pagefind/fragment/en_dccebd7.pf_fragment", +"/ran/pagefind/fragment/en_16d01f2.pf_fragment", "/ran/pagefind/fragment/zh-cn_95fa787.pf_fragment", "/ran/pagefind/fragment/zh-cn_a7edffe.pf_fragment", "/ran/pagefind/fragment/zh-cn_e64f93e.pf_fragment", "/ran/pagefind/fragment/zh-cn_5bb9206.pf_fragment", -"/ran/pagefind/fragment/zh-cn_8d53abb.pf_fragment", -"/ran/pagefind/fragment/zh-cn_8338621.pf_fragment", +"/ran/pagefind/fragment/en_324b2ed.pf_fragment", +"/ran/pagefind/fragment/en_63f4b5c.pf_fragment", "/ran/pagefind/fragment/zh-cn_c2e89f3.pf_fragment", -"/ran/pagefind/fragment/zh-cn_caddc62.pf_fragment", -"/ran/pagefind/fragment/zh-cn_ee19938.pf_fragment", "/ran/pagefind/fragment/en_2771bf1.pf_fragment", "/ran/pagefind/fragment/zh-cn_c551e89.pf_fragment", "/ran/pagefind/fragment/zh-cn_d32fcee.pf_fragment", +"/ran/pagefind/fragment/en_aab3547.pf_fragment", "/ran/pagefind/fragment/zh-cn_e88bc3f.pf_fragment", "/ran/pagefind/fragment/en_19ba7e6.pf_fragment", -"/ran/pagefind/fragment/en_4873c44.pf_fragment", "/ran/pagefind/fragment/zh-cn_5df12ef.pf_fragment", "/ran/pagefind/fragment/en_b2b1326.pf_fragment", "/ran/pagefind/fragment/zh-cn_f9c4333.pf_fragment", "/ran/pagefind/fragment/zh-cn_3de2e5c.pf_fragment", +"/ran/pagefind/fragment/zh-cn_2bc07af.pf_fragment", "/ran/pagefind/fragment/en_13157a1.pf_fragment", "/ran/pagefind/fragment/zh-cn_32113cf.pf_fragment", "/ran/pagefind/fragment/en_b1c2dff.pf_fragment", "/ran/pagefind/fragment/zh-cn_7d7b75a.pf_fragment", "/ran/pagefind/fragment/zh-cn_ac92f78.pf_fragment", -"/ran/pagefind/fragment/zh-cn_707d8fd.pf_fragment", +"/ran/pagefind/fragment/en_edda142.pf_fragment", "/ran/pagefind/fragment/zh-cn_c4a5919.pf_fragment", "/ran/pagefind/fragment/en_738928a.pf_fragment", -"/ran/pagefind/fragment/en_216410c.pf_fragment", -"/ran/pagefind/fragment/en_d792b8c.pf_fragment", "/ran/pagefind/fragment/zh-cn_8a3cd5f.pf_fragment", "/ran/pagefind/fragment/en_919ab78.pf_fragment", -"/ran/pagefind/fragment/zh-cn_a47bf58.pf_fragment", +"/ran/pagefind/fragment/en_1f28c1c.pf_fragment", "/ran/pagefind/fragment/zh-cn_715eacf.pf_fragment", "/ran/pagefind/fragment/zh-cn_e6b1657.pf_fragment", +"/ran/pagefind/fragment/zh-cn_8c8e8be.pf_fragment", "/ran/pagefind/fragment/zh-cn_677ff04.pf_fragment", "/ran/pagefind/fragment/en_b5741b3.pf_fragment", "/ran/pagefind/fragment/zh-cn_f379427.pf_fragment", -"/ran/pagefind/fragment/en_31bb7a6.pf_fragment", "/ran/pagefind/fragment/zh-cn_5042f4c.pf_fragment", "/ran/pagefind/fragment/zh-cn_5ca356d.pf_fragment", -"/ran/pagefind/fragment/en_901e811.pf_fragment", -"/ran/pagefind/fragment/zh-cn_3aa282b.pf_fragment", "/ran/pagefind/fragment/zh-cn_67d6c7a.pf_fragment", "/ran/pagefind/fragment/zh-cn_3ad6344.pf_fragment", "/ran/pagefind/fragment/en_27a0b4a.pf_fragment", +"/ran/pagefind/fragment/zh-cn_69610a7.pf_fragment", "/ran/pagefind/fragment/zh-cn_e347438.pf_fragment", -"/ran/pagefind/fragment/en_7a4ca4f.pf_fragment", -"/ran/pagefind/fragment/zh-cn_25694d5.pf_fragment", -"/ran/pagefind/fragment/zh-cn_5b71249.pf_fragment", +"/ran/pagefind/fragment/zh-cn_ec79f02.pf_fragment", +"/ran/pagefind/fragment/en_34b032a.pf_fragment", "/ran/pagefind/fragment/en_229996f.pf_fragment", "/ran/pagefind/fragment/zh-cn_66f42e8.pf_fragment", +"/ran/pagefind/fragment/zh-cn_af6e5c4.pf_fragment", "/ran/pagefind/fragment/en_1fd6515.pf_fragment", "/ran/pagefind/fragment/zh-cn_75a264c.pf_fragment", "/ran/pagefind/fragment/zh-cn_59bdbd3.pf_fragment", -"/ran/pagefind/fragment/en_c9c7c59.pf_fragment", -"/ran/pagefind/fragment/zh-cn_2e8f3b4.pf_fragment", +"/ran/pagefind/fragment/zh-cn_20933c3.pf_fragment", "/ran/pagefind/fragment/zh-cn_f7dcce8.pf_fragment", -"/ran/pagefind/fragment/en_51f248e.pf_fragment", -"/ran/pagefind/fragment/en_8e7817f.pf_fragment", "/ran/pagefind/fragment/en_106ee7d.pf_fragment", "/ran/pagefind/fragment/en_27ced55.pf_fragment", +"/ran/pagefind/fragment/zh-cn_b2e449c.pf_fragment", "/ran/pagefind/fragment/zh-cn_489c27d.pf_fragment", +"/ran/pagefind/fragment/zh-cn_88af4d0.pf_fragment", "/ran/pagefind/fragment/en_c8893d7.pf_fragment", "/ran/pagefind/fragment/en_fba3fcb.pf_fragment", "/ran/pagefind/fragment/en_39ca4e7.pf_fragment", +"/ran/pagefind/fragment/en_3541bef.pf_fragment", "/ran/pagefind/fragment/en_b5a7787.pf_fragment", +"/ran/pagefind/fragment/zh-cn_c999918.pf_fragment", "/ran/pagefind/fragment/zh-cn_61c329a.pf_fragment", "/ran/pagefind/fragment/en_e2846bf.pf_fragment", "/ran/pagefind/fragment/en_7755d1b.pf_fragment", +"/ran/pagefind/fragment/en_6b4c4a9.pf_fragment", "/ran/pagefind/fragment/en_a034a97.pf_fragment", "/ran/pagefind/fragment/zh-cn_5190b59.pf_fragment", +"/ran/pagefind/fragment/en_f575e71.pf_fragment", +"/ran/pagefind/fragment/en_6e7d47a.pf_fragment", "/ran/pagefind/fragment/en_55a7cf9.pf_fragment", -"/ran/pagefind/fragment/zh-cn_edddd73.pf_fragment", -"/ran/pagefind/fragment/zh-cn_aa1f32d.pf_fragment", -"/ran/pagefind/fragment/en_75d5dcb.pf_fragment", -"/ran/pagefind/fragment/en_1d2a8f7.pf_fragment", -"/ran/pagefind/fragment/zh-cn_61c34a2.pf_fragment", +"/ran/pagefind/fragment/zh-cn_f260254.pf_fragment", +"/ran/pagefind/fragment/zh-cn_82b59c2.pf_fragment", "/ran/pagefind/fragment/en_91e701d.pf_fragment", +"/ran/pagefind/fragment/zh-cn_ad77d75.pf_fragment", "/ran/pagefind/fragment/en_e8f3a9e.pf_fragment", "/ran/pagefind/fragment/en_c2a5686.pf_fragment", "/ran/pagefind/fragment/zh-cn_c1151c9.pf_fragment", "/ran/pagefind/fragment/zh-cn_4152685.pf_fragment", -"/ran/pagefind/fragment/zh-cn_d04ce0b.pf_fragment", "/ran/pagefind/fragment/en_1d9d6e5.pf_fragment", "/ran/pagefind/fragment/zh-cn_b7b2564.pf_fragment", +"/ran/pagefind/fragment/zh-cn_8dcd37a.pf_fragment", "/ran/pagefind/fragment/en_e34b39a.pf_fragment", "/ran/pagefind/fragment/zh-cn_50313a9.pf_fragment", "/ran/pagefind/fragment/en_b7a3e23.pf_fragment", @@ -747,11 +749,9 @@ const SERVICE_WORK_CACHE_FILE_PATHS = [ "/ran/pagefind/fragment/zh-cn_d98338a.pf_fragment", "/ran/pagefind/fragment/zh-cn_5bab657.pf_fragment", "/ran/pagefind/fragment/zh-cn_cfbcb39.pf_fragment", -"/ran/pagefind/fragment/en_5f9a7eb.pf_fragment", "/ran/pagefind/fragment/en_349bd7e.pf_fragment", "/ran/pagefind/fragment/zh-cn_c4f682e.pf_fragment", "/ran/pagefind/fragment/zh-cn_e1f4a79.pf_fragment", -"/ran/pagefind/fragment/en_a9c2374.pf_fragment", "/ran/pagefind/fragment/en_65ccfe9.pf_fragment", "/ran/404.html", "/ran/icon_72.png", @@ -763,7 +763,7 @@ const SERVICE_WORK_CACHE_FILE_PATHS = [ "/ran/icon_48.png", "/ran/screenshots_2560x1440.jpg", ]; -const VERSION = "1728828594"; +const VERSION = "1728921819"; const CACHE_NAME = 'chaxus_ran_' + VERSION const IGNORE_REQUEST_LIST = [