diff --git a/docs/.vitepress/theme/styles/overrides.css b/docs/.vitepress/theme/styles/overrides.css
index 67bfc5e9..6c2d128c 100644
--- a/docs/.vitepress/theme/styles/overrides.css
+++ b/docs/.vitepress/theme/styles/overrides.css
@@ -62,7 +62,7 @@
.container .VPFeature.link:hover {
border: 1px solid var(--vp-c-brand-light) !important;
}
-.container .VPFeature > article .details{
+.container .VPFeature > article .details {
line-height: 1em !important;
}
.container .VPFeature > article {
diff --git "a/docs/BackEnd/NodeJS/Node\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/docs/BackEnd/NodeJS/Node\345\255\246\344\271\240\347\254\224\350\256\260.md"
index ebb21ee5..cada58b4 100644
--- "a/docs/BackEnd/NodeJS/Node\345\255\246\344\271\240\347\254\224\350\256\260.md"
+++ "b/docs/BackEnd/NodeJS/Node\345\255\246\344\271\240\347\254\224\350\256\260.md"
@@ -255,9 +255,8 @@ console.log(m1.age) // 20
**前端两种服务器:**
- Web 网站服务器:专门对外提供 Web 网页资源服务器
-
- API 接口服务器:专门对外提供 API 接口服务器
+Web 网站服务器:专门对外提供 Web 网页资源服务器
+API 接口服务器:专门对外提供 API 接口服务器
### 1.Express 创建服务器
@@ -315,20 +314,19 @@ app.listen(80, () => {
- **局部中间件**
```js
-
-...
-const mw1 = (req,res,next) => {
- console.log('中间件mw1被执行了');
- req.age= 18
+// ...
+function mw1(req, res, next) {
+ console.log('中间件mw1被执行了')
+ req.age = 18
next()
}
-//在路由加一个参数,
-app.get('/mw1',mw1,(req,res)=>{
- console.log('req.age: ', req.age);
- console.log('mw1被访问');
+// 在路由加一个参数,
+app.get('/mw1', mw1, (req, res) => {
+ console.log('req.age: ', req.age)
+ console.log('mw1被访问')
res.send('mw1被访问哈哈哈')
})
-...
+// ...
```
- **多个局部中间件**
diff --git "a/docs/BackEnd/Server/Docker\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/docs/BackEnd/Server/Docker\345\255\246\344\271\240\347\254\224\350\256\260.md"
index cad1c572..022fc8da 100644
--- "a/docs/BackEnd/Server/Docker\345\255\246\344\271\240\347\254\224\350\256\260.md"
+++ "b/docs/BackEnd/Server/Docker\345\255\246\344\271\240\347\254\224\350\256\260.md"
@@ -27,7 +27,7 @@
## 五、CentOS安装Docker
-```bash
+```zsh
sudo yum install -y yum-utils
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
@@ -45,7 +45,7 @@ docker run hello-world #测试
### 1. Docker
-```bash
+```zsh
systemctl enable docker #开机启动
docker system df #负载查看
@@ -53,7 +53,7 @@ docker system df #负载查看
### 2. 镜像
-```bash
+```zsh
docker images #展示本地镜像 -a 所有,-q只显示ID
docker search mongo #搜索镜像
docker search redis --limit 5 #展示Stars排名前五条
@@ -67,7 +67,7 @@ docker rmi -f hello-world #强制删除镜像
**生成新镜像**
-```bash
+```zsh
agt-get update
apt-get -y install vim
docker commit -m="vim is ok" -a="fxj" 容器id myubt:1.1
@@ -75,7 +75,7 @@ docker commit -m="vim is ok" -a="fxj" 容器id myubt:1.1
**本地镜像推送到阿里云**
-```bash
+```zsh
#发布和拉取
docker login --username=yunzhishangfxj registry.cn-hangzhou.aliyuncs.com
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:[镜像版本号]
@@ -87,7 +87,7 @@ docker run -it registry.cn-hangzhou.aliyuncs.com/fanxj/mubt:1.1 /bin/bash #记
### 3. 容器
-```bash
+```zsh
docker ps #列出正在运行容器 -a -s
docker run -it --name="ub01" ubuntu /bin/bash
#-p: 外部主机端口:docker容器端口 -P:随机分配主机端口映射到内部容器端口
@@ -109,21 +109,21 @@ docker ps -a -q | xargs docker rm #一次性删除多个再运行的
#### 启动守护式
-```bash
+```zsh
docker run -it #前台交互启动
docker run -d #后台守护启动
```
#### 查看容器日志
-```bash
+```zsh
docker logs 容器id #查看容器日志
docker inspect 容器id #查看容器内部细节
```
#### 容器备份到主机
-```bash
+```zsh
docker cp 容器id:容器文件路径 目的主机路径 #备份文件
docker export 容器id > xxx.tar #备份整个容器
cat ub.tar | docker import - 恢复后的镜像名 #从tar包中恢复成镜像
@@ -194,7 +194,7 @@ USER
## 九、Docker网络
-```bash
+```zsh
docker network ls #查看网络
docker network inspect 网络名 #查看网络源数据
docker network rm 网络名 #删除网络
@@ -210,14 +210,14 @@ docker run -d --network none --name 容器名 镜像名 #只有lo网卡
#### 共用网卡
-```bash
+```zsh
docker run -d --network container:另一个容器名 --name 容器名 /bin/bash 镜像名
#共用的容器关闭,这个容器网卡也没有啦
```
#### 自定义网络
-```bash
+```zsh
#启动两个网桥模式容器
docker run -d -p 8081:8080 --name tomcat81 tomcat
docker run -d -p 8082:8080 --name tomcat82 tomcat
@@ -225,7 +225,7 @@ docker run -d -p 8082:8080 --name tomcat82 tomcat
#两个ip可以相互ping通,痛点:按域名ping不通
```
-```bash
+```zsh
docker run -d -p 8081:8080 --network my_network --name tomcat81 tomcat
docker run -d -p 8082:8080 --network my_network --name tomcat82 tomcat
#ip、域名互ping都能通(维护好主机和ip的关系)
@@ -237,7 +237,7 @@ docker run -d -p 8082:8080 --network my_network --name tomcat82 tomcat
#### 1. [安装Compose](https://docs.docker.com/compose/install/)
-```bash
+```zsh
curl -SL https://github.com/docker/compose/releases/download/v2.14.2/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
```
diff --git "a/docs/BackEnd/Server/Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md" "b/docs/BackEnd/Server/Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md"
index 8190d150..61ff7215 100644
--- "a/docs/BackEnd/Server/Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md"
+++ "b/docs/BackEnd/Server/Nginx\345\255\246\344\271\240\347\254\224\350\256\260.md"
@@ -26,7 +26,7 @@ kill -INT 进程号 | 快速停止 |
## 编写配置
-```bash
+```zsh
nginx -t #检查配置文件有没有问题
grep -Ei "\{|\}" nginx.conf #检查配置文件括号配对问题
nginx -s reload #重载配置
@@ -40,7 +40,7 @@ nginx -s reload #重载配置
## CentOS7联网
-```bash
+```zsh
ip a #查看网卡
cd /etc/sysconfig/network-scripts
vi ifcfg-ens160 #把ONBOOT=no ===> 改为yes
diff --git "a/docs/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md" "b/docs/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md"
deleted file mode 100644
index 21fbc9a7..00000000
--- "a/docs/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md"
+++ /dev/null
@@ -1,394 +0,0 @@
-# Angular基础总结一
-
-## 一、NgModule
-
-::: warning
-
-被@NgModule所装饰的类被称为angular module
-
-:::
-
-#### @NgModule元数据
-
-- **declarations** —— 该模块的依赖项(该模块用到的组件、指令、管道)。
-- **imports** —— 导入其他的ngModule。
-- **providers** —— 提供各种服务。
-- **bootstrap** —— 根组件,Angular 创建它并插入 index.html 宿主页面
-
-#### declarations 数组
-
-```js
-1.模块中使用的组件必须先在declarations 数组中声名
-2.一个组件只能被一个模块声名
-3.在declarations中的组件默认只能在当前模块中使用,在其他模块使用必须exports导出
-```
-
-#### imports 数组
-
-```js
-1.只会出现在@NgModule装饰器中。
-2.模块想要正常工作,除了本身的依赖项(declarations),还可能需要其他模块导出的依赖项。
-3.只要是angular module,都可以导入imports数组中,比如ng内置、第三方、自定义的模块。
-```
-
-#### providers 数组
-
-```js
-该数组为当前模块提供一系列服务
-```
-
-#### bootstrap 数组
-
-```js
-应用是通过引导根模块 AppModule 来启动的,引导过程还会创建 bootstrap 数组中列出的组件,并把它们逐个插入到浏览器的 DOM 中。
-该数组中的每个组件,都作为组件树的根(根组件),后续所有组件都是基于根组件的(如图)。
-虽然也可以在宿主页面中放多个组件,但是大多数应用只有一个组件树,并且只从一个根组件开始引导。
-这个根组件通常叫做 AppComponent,并且位于根模块的 bootstrap 数组中。
-```
-
-::: details 结构图
-
-
-
-:::
-
-## 二、模板基础语法
-
-#### 1. 模板表达式
-
-> **模版中还可以写些简单的逻辑,比如判断或运算**
-
-```typescript
-import { Component } from "@angular/core";
-@Component({
- selector: "app-root",
- template: `
{{ title }}
- sum : {{ 1 + 1 }}
- price: {{ price * 0.7 }}
- 与方法结合: {{ price * 0.7 + getVal() }}.
`, //内联模板
- styles: [
- `
- h1 {
- color: yellow;
- }
- `,
- ], //内联样式
-})
-export class AppComponent {
- title = "my-angular-title";
- price = 30;
- getVal(): number {
- return 33;
- }
-}
-```
-
-::: warning 模板表达式遵循原则:
-
-- 非常简单
-- 执行迅速
-- 没有可见的副作用(即模版中的逻辑不能改变组件的变量)
-
-:::
-
-#### 2. 模板来源
-
-```typescript
-import { Component } from "@angular/core";
-@Component({
- selector: "app-root",
- templateUrl: "./app.component.html",
- styleUrls: ["./app.component.scss"], //注意: styleUrls
-})
-export class AppComponent {}
-```
-
-#### 3. 属性绑定
-
-```html
-
-
-
-
-
-
-
-
-```
-
-#### 4. 自定义属性绑定
-
-```html
-一行文字
-测试自定义标题属性
-
-```
-
-#### 5. 插值表达式属性绑定
-
-```html
-
-
-
-```
-
-#### 6. 单个class样式绑定
-
-```typescript
-import { Component } from "@angular/core";
-@Component({
- selector: "app-root",
- template: `
-
-
-
-
-
-
- `,
- styles: [],
-})
-export class AppComponent {
- theme = "primary";
- isSuccess = true;
-}
-```
-
-#### 7. 绑定多个class
-
-```typescript
-import { Component } from "@angular/core";
-@Component({
- selector: "app-root",
- template: `
-
-
-
-
-
-
-
-
- `,
- styles: [],
-})
-export class AppComponent {
- btnCls = "btn btn-primary";
- btnCls2 = ["btn", "btn-success"];
- btnCls3 = {
- btn: true,
- "btn-info": true,
- };
-}
-```
-
-#### 8. 绑定单个style
-
-```typescript
-import { Component } from "@angular/core";
-@Component({
- selector: "app-root",
- template: `
- 一段文字
- 设置高度
- 设置高度
- `,
- styles: [],
-})
-export class AppComponent {}
-```
-
-#### 9. 绑定多个style
-
-```typescript
-import { Component } from '@angular/core';
-@Component({
- selector: 'app-root',
- template: `
- style1
- style2
- style3
-
-
-
-
-
-
- style3
- `,
- styles: []
-})
-export class AppComponent {
- style1 = 'width: 200px;height: 50px;text-align: center;border: 1px solid;';
- style2 = ['width', '200px', 'height', '50px', 'text-align', 'center', 'border', '1px solid']; // 有问题
- style3 = {
- width: '200px',
- height: '50px',
- 'text-align': 'center',
- border: '1px solid'
- };
-```
-
-::: warning 样式优先级
-
-1.某个类或样式绑定越具体,它的优先级就越高
-
-2.绑定总是优先于静态属性
-
-:::
-
-#### 10. 绑定事件
-
-```typescript
-import { Component } from "@angular/core";
-@Component({
- selector: "app-root",
- template: `
-
-
- `,
- styles: [],
-})
-export class AppComponent {
- onClick() {
- console.log("onClick");
- }
- onClick1(event: MouseEvent) {
- console.log("onClick1", event.target);
- }
-}
-```
-
-#### 11. 输入与输出属性
-
-> 输入属性:用于父组件传值给子组件(父传子)` @Input()`
->
-> 输出属性:用于子组件传值给父组件(子传父)`@Output()`
-
-#### 输入属性`@Input`
-
-:memo:父组件
-
-```typescript
-import { Component } from "@angular/core";
-@Component({
- selector: "app-root",
- template: `
-
-
-
- `,
-})
-export class AppComponent {
- currentItem = "Television";
-}
-```
-
-:memo:子组件
-
-```typescript
-import { Component, Input } from "@angular/core";
-@Component({
- selector: "app-mycpn",
- template: `Today's item: {{ item }}
`,
-})
-export class MycpnComponent {
- @Input() item: string;
- //@Input('aliasItem') item: string; 提供别名,item变量只可以在本组件使用
- //相当于对父组件传入的aliasItem变量进行重命名
-}
-```
-
-#### 输出属性`@Output()`
-
-:memo:父组件
-
-```typescript
-import { Component } from "@angular/core";
-@Component({
- selector: "app-root",
- template: ` `,
-})
-export class AppComponent {
- items = ["item1", "item2", "item3", "item4"];
- addItem(newItem: string) {
- this.items.push(newItem);
- }
-}
-```
-
-:memo:子组件
-
-```typescript
-import { Component, Input } from "@angular/core";
-@Component({
- selector: "app-mycpn",
- template: `
- `,
-})
-export class MycpnComponent {
- @Output() newItemEvent = new EventEmitter();
- // @Output('newItem') newItemEvent = new EventEmitter();
- addNewItem(value: string) {
- this.newItemEvent.emit(value);
- }
-}
-```
-
-> 还可以元数据中声名输入、输出属性。[(不推荐)](https://angular.cn/guide/styleguide##decorate-input-and-output-properties)
-
-## 三、组件样式
-
-#### 宿主选择器
-
-> `:host`选择是是把宿主元素作为目标的唯一方式
-
-```md
-它选中的是组件模板标签,比如,相当于在父组件的style中使用标签选择器选择 app-child {}
-```
-
-当宿主标签上有 `active` 类名时生效
-
-```css
-:host(.active) {
- border-width: 3px solid ##ccc;
-}
-
-```
-
-#### 祖先选择器
-
-> 当某个祖先元素有 CSS 类 light 时,才会把 background-color 样式应用到组件内部的所有 .title 元素中,找到根元素(html标签)为止
-
-```css
-:host-context(.light) .title {
- background-color: ##bfa;
-}
-
-```
-
-#### 样式模块化
-
-> 在 @Component 的元数据中指定的样式只会对该组件的模板生效
->
-> 组件的样式不会影响到子组件中的模板
->
-> 组件的样式不会影响到投影内容
-
-#### 视图封装模式
-
-> ShadowDom -- **不进不出**,没有样式能进来,组件样式出不去, 就自己玩
->
-> Emulated --**只进不出**, 默认选项,全局样式能进来,组件样式出不去
->
-> None -- **能进能出**,此时组件的样式是全局生效的,注意与其他组件发生样式冲突,(对父组件样式也能生效)
diff --git "a/docs/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md" "b/docs/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md"
deleted file mode 100644
index 8ba2cb8f..00000000
--- "a/docs/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\270\211.md"
+++ /dev/null
@@ -1,699 +0,0 @@
-## 组件投影
-
-:memo:shadow.component.html
-
-```html
-
- shadow works!
-
-
-
-
-
-```
-
-:memo:app.component.html
-
-```html
-
-
- 头部投影内容
-
- 自定义属性选择器投影内容
-
-
-```
-
-:medal_military:结果展示
-
-
-
-## ViewChild
-
-:memo:parent.component.ts
-
-```typescript
-import { AfterViewInit, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
-import { ChildComponent } from './child/child.component';
-
-@Component({
- selector: 'app-parent',
- templateUrl: './parent.component.html',
- styleUrls: ['./parent.component.css']
-})
- export class ParentComponent implements OnInit,AfterViewInit {
-
- // @ViewChild('box',{static:true}) private box:ElementRef //获取dom
- // @ViewChild(ChildComponent,{static:true}) private instance:ChildComponent //获取子组件方式一
- @ViewChild('childcomponent',{static:true}) private childInstance:ChildComponent //获取子组件实例方式二
-
- constructor() { //执行秩序(1)
- // console.log('constructor',this.box);
- // console.log('constructor',this.instance?.childdata);
- // console.log('constructor',this.childInstance?.childdata);
- console.log('constructor',this.childInstance);
-
- }
- ngOnInit(): void {//(2)
- // console.log('ngOnInit',this.box.nativeElement);
- // console.log('ngOnInit',this.instance.childdata);
- console.log('ngOnInit',this.childInstance);
- // console.log('ngOnInit',this.childInstance.childdata);
-
- }
- ngAfterViewInit(): void { //(3)在变更检测后执行,能保证获取到元素
- // console.log('ngAfterViewInit',this.box.nativeElement);
- // console.log('ngAfterViewInit',this.instance.childdata);
- console.log('ngAfterViewInit',this.childInstance.childdata);
-
- }
-```
-
-## ViewChildren
-
-:memo:parent.component.html
-
-```html
-
-mybox
-mybox
-mybox
-
-
-
-
-```
-
-:memo:parent.component.ts
-
-```typescript
-import { AfterViewInit, Component, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
-import { ChildComponent } from './child/child.component';
-
-@Component({
- selector: 'app-parent',
- templateUrl: './parent.component.html',
- styleUrls: ['./parent.component.css']
-})
-export class ParentComponent implements OnInit,AfterViewInit {
-
- // ViewChildren批量获取元素和组件
- @ViewChildren(ChildComponent) private childs:QueryList
- @ViewChildren('boxs') private childs1:QueryList
- constructor() {
- }
- ngOnInit(): void {
- }
- ngAfterViewInit(): void { //(3)
- console.log(this.childs);
- console.log(this.childs1); //输出QueryList数组
- //QueryList中监听子组件变化的回调函数
- this.childs1.changes.subscribe((changes)=>{
- console.log(changes);
-
- })
- }
-}
-```
-
-## ContentChild
-
-> 获取投影中的dom元素、指令、组件
-
-:memo:content-parent.html
-
-```html
-
- head
- main
-
-
-
-
-
-
-
-```
-
-📝content-child.html
-
-```html
-content-child works!
-
-
-```
-
-:memo:content-child.ts
-
-```typescript
-import { AfterViewInit, Component, ContentChild, ElementRef, OnInit } from '@angular/core';
-import { ContentBoxComponent } from '../content-box/content-box.component';
-
-@Component({
- selector: 'app-content-child',
- templateUrl: './content-child.component.html',
- styleUrls: ['./content-child.component.css']
-})
-export class ContentChildComponent implements OnInit,AfterViewInit {
- @ContentChild('head',{static:true}) private head:ElementRef //获取投影中的dom元素
- @ContentChild(ContentBoxComponent) private contentbox:ElementRef //获取组件
- @ContentChild('cbox',{static:true}) private cbox:ElementRef // 有多个只会获取第一个
- constructor() { }
-
- ngOnInit(): void {
- }
- ngAfterViewInit(): void {
- console.log(this.head);
- console.log(this.contentbox);
- console.log(this.cbox);
-
- }
-}
-```
-
-## ContentChildren
-
-> **用法类似ViewChildren, 批量获取投影中到组件或指令。**
->
-> **默认只批量获取直属组件,获取所有组件需开启:{ descendants: true }**
-
-:memo:content-parent.html
-
-```html
-content-parent works!
-
-
-
-
-
-
-
-
-```
-
-:memo:content-child.ts
-
-```typescript
-import { AfterViewInit, Component,ContentChildren,OnInit, QueryList } from '@angular/core';
-import { ContentBoxComponent } from '../content-box/content-box.component';
-
-@Component({
- selector: 'app-content-child',
- templateUrl: './content-child.component.html',
- styleUrls: ['./content-child.component.css']
-})
-export class ContentChildComponent implements OnInit,AfterViewInit {
- //ContentChildren没有{static:true}属性
- @ContentChildren(ContentBoxComponent) private cboxs:QueryList
- @ContentChildren('cbox',{descendants: true}) private cboxss:QueryList
- constructor() { }
-
- ngOnInit(): void {
- }
- ngAfterViewInit(): void {
- console.log(this.cboxs);//只获取直属投影组件
- console.log(this.cboxss);//获取全部投影组件
- }
-}
-```
-
-## 自定义管道
-
-```typescript
-import { Pipe, PipeTransform } from '@angular/core';
-
-@Pipe({
- name: 'pipepow'
-})
-export class PipepowPipe implements PipeTransform {
-
- transform(value: number, exponent?: number): number {
- //value:底数 exponent:指数
- return Math.pow(value,isNaN(exponent) ? 1: exponent);
- }
-}
-```
-
-> 在相应的Module中导入并使用
-
-```html
-{{8| pipepow}}
-{{8| pipepow:3}}
-{{value | pipepow:2}}
-Boost factor:
-Normal power:
-{{factor | pipepow:power}}
-
-```
-
-## 非纯管道
-
-> 默认的管道都是纯的,Angular 会忽略复合对象中的变化,即管道只会检查原始值或对象引用
-
-::: warning
-
-可如果数组中的元素变化,增删改,由于引用没有变化,不会执行变更检测,所以不会执行管道的逻辑
-
-:::
-
-::: details Pipe2Pipe
-
-```typescript
-import { Pipe, PipeTransform } from '@angular/core';
-
-@Pipe({
- name: 'pipe2',
- pure: false //非纯管道开启方式一
-})
-export class Pipe2Pipe implements PipeTransform {
-
- transform(allheros: any): any { //赛选会飞的英雄
- return allheros.filter((item) => item.canFly);
- }
-
-}
-```
-
-:::
-
-::: details AppComponent
-
-```typescript
-import { Component } from '@angular/core';
-interface Hero {
- id: string;
- name: string;
- canFly?: boolean;
-}
-
-const HEROES = [
- {
- id: 'hero_0',
- name: '盖伦',
- canFly: false
- },
- {
- id: 'hero_1',
- name: '赵信',
- canFly: false
- },
- {
- id: 'hero_2',
- name: '嘉文',
- canFly: false
- },
- {
- id: 'hero_3',
- name: '易大师',
- canFly: false
- },
- {
- id: 'hero_3',
- name: '泰达米尔',
- canFly: true
- }
- ];
-@Component({
- selector: 'app-root',
- template: `
-
-
-
- {{hero.name}}
-
- `,
-})
-export class AppComponent {
- heroes: Hero[] = [];
- canFly = true;
- constructor() {
- this.reset();
- }
-
- ngOnInit(): void {
- }
- addHero(name: string) {
- name = name.trim();
- if (name) {
- // 不改变引用没有用
- this.heroes.push({ id: 'flier_' + Date.now(), name, canFly: this.canFly });
- // 开启非纯管道方式二、改变引用,触发变更检测
- // this.heroes = [...this.heroes,{id:'flier'+Date.now(),name,canFly:this.canFly}]
- }
- }
-
- reset() { this.heroes = HEROES.slice(); }
-}
-```
-
-:::
-
-## 生命周期
-
-> 生命周期函数:组件创建、组件更新、组件销毁的时候会触发的一系列的方法。
->
-> 当 Angular 使用构造函数新建一个组件或指令后,就会按下面的顺序在特定时刻调用这些 生命周期钩子函数。
-
-
-
-::: details 所有生命周期钩子函数执行顺序
-
-```typescript
-import { AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component,
- DoCheck, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
-
-@Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.css']
-})
-export class AppComponent implements OnInit,OnChanges,DoCheck,AfterContentInit,
- AfterContentChecked,AfterViewInit,AfterViewChecked,OnDestroy{
- constructor(){} //组件初始化,写简单的逻辑和数据初始化操作,(获取不到最新输入属性值)
- ngOnChanges(changes: SimpleChanges): void {
- console.log('changes ', changes);
- //可最早获取到输入属性最新值,输入属性更新时触发,但组件内部改变输入属性是不会触发的
- }
- ngOnInit(): void {
- console.log('ngOnInit '); //适合请求数据初始化组件,只调用一次
- }
- ngDoCheck(): void {
- console.log('ngDoCheck ');
- }
-
- ngAfterContentInit(): void {
- //在组件内容初始化之后调用,只调用一次。
- console.log('ngAfterContentInit');
- }
-
- ngAfterContentChecked(): void {
- //组件每次检查内容时调用
- console.log('ngAfterContentChecked ');
- }
-
- ngAfterViewInit(): void {
- //组件相应的视图初始化之后调用,只调用一次。
- console.log('ngAfterViewInit ');
- }
-
- ngAfterViewChecked(): void {
- //组件每次检查视图时调用
- console.log('ngAfterViewChecked');
-
- }
-
- ngOnDestroy(): void {
- //指令销毁前调用,适合理一些残存的状态操作:
- //取消订阅可观察对象和 DOM 事件、停止 interval 计时器、
- //反注册该指令在全局或应用服务中注册过的所有回调
- console.log('ngOnDestroy');
- }
-
-}
-```
-
-:::
-
-
-
-> 当组件、父组件发生变更检测后都会调用这三个钩子:
->
-> 模板中的DOM事件触发就会进行变更检测(``)
->
-> ngDoCheck
-> ngAfterContentChecked
-> ngAfterViewChecked
-
-- **指令与组件共有的钩子**
- - ngOnChanges
- - ngOnInit
- - ngDoCheck
- - ngOnDestroy
-- **组件特有的钩子**
- - ngAfterContentInit
- - ngAfterContentChecked
- - ngAfterViewInit
- - ngAfterViewChecked
-
-## 变更检测
-
-## 默认策略下触发变更检测的时机
-
-```typescript
-changeDetection:ChangeDetectionStrategy.Default
-```
-
-- 事件:页面 click、submit、mouse down……
-- XHR:从后端服务器拿到数据
-- 定时器:setTimeout()、setInterval()
-
-> 只要某个组件触发了以上中的一个,就会从顶级组件从上至下开始进行变更检测,每个组件都会进行变更检测,
->
-> 检测组件中的值是否应该改变
-
-::: warning 注意
-
-已经检测完的组件,不允许在被子组件修改,(子组件不能修改检测完的父组件数据),这就是单向数据流
-
-:::
-
-
-
-## onPush下触发变更检测时机
-
-```typescript
-changeDetection:ChangeDetectionStrategy.OnPush
-```
-
-::: warning
-
-onPush策略会把组件从组件树中剥离出去,他和他的子组件都不会检测了;
-
-定时器会触发变更检测,但是依然会跳过onPush策略组件。
-
-:::
-
-::: tip
-
-- 组件的@Input引用发生变化。
-- 组件的 DOM 事件,包括它子组件的 DOM 事件,比如 click、submit、mouse down。
-- Observable 订阅事件,同时设置 Async pipe。
-- 手动调用:ChangeDetectorRef.detectChanges()、ChangeDetectorRef.markForCheck()、ApplicationRef.tick()方法
-
-```js
-markForCheck() // 把该视图显式标记为已更改(脏的),以便它下一轮再次进行检查。
-detectChanges() // 检查该视图及其子视图。与 detach 结合使用可以实现局部变更检测。(强行检测)
-```
-
-:::
-
-
-
-## 动态组件
-
-> 如果说,之前在模版中调用的组件为静态组件(比如:app-xxx)
->
-> 那么不用在模版里声明,而是通过ts动态插入到dom中到组件,可以视为动态组件
-
-:memo:alert.component.ts:
-
-```typescript
-import {Component, OnInit, ChangeDetectionStrategy, Output, EventEmitter} from '@angular/core';
-type AlertTheme = 'primary' | 'danger' | 'warning';
-
-export interface AlertOption {
- content: string;
- theme?: AlertTheme;
-}
-
-@Component({
- selector: 'app-alert',
- template: `
-
- {{ options.content }}
- ×
-
- `,
- styles: [`
- .close {
- display: block;
- width: 20px;
- height: 20px;
- position: absolute;
- right: 10px;
- top: 50%;
- margin-top: -10px;
- cursor: pointer;
- }
- `],
- changeDetection: ChangeDetectionStrategy.OnPush
-})
-export class AlertComponent implements OnInit {
- options: Required = {
- content: '',
- theme: 'primary'
- }
-
- @Output() closed = new EventEmitter();
- constructor() { }
-
- ngOnInit(): void {}
-
- get wrapCls(): string {
- return 'alert alert-' + this.options.theme + ' fixed-top';
- }
-
- setOptions(options: AlertOption) {
- this.options = { ...this.options, ...options };
- }
-}
-```
-
-> 调用 `alert.component`
-
-```typescript
-import {ApplicationRef, Component, ComponentFactoryResolver, ComponentRef, EmbeddedViewRef, Injector, OnInit} from '@angular/core';
-import {AlertComponent} from '../../components/alert/alert.component';
-
-@Component({
- selector: 'app-show-data',
- templateUrl: './show-data.component.html',
- styleUrls: ['./show-data.component.scss']
-})
-export class ShowDataComponent implements OnInit {
- private container: AlertComponent;
- private componentRef: ComponentRef;
- constructor(
- private cfr: ComponentFactoryResolver,
- private inject: Injector,
- private appRef: ApplicationRef
- ) {}
-
- ngOnInit(): void {
-
- }
-
- showAlert() {
- if (!this.container) {
- this.container = this.getContainer();
- }
-
- // 调用组件的某个方法执行逻辑,比如下面这个传参
- this.container.setOptions({ content: '一段提示', theme: 'warning' });
- }
-
- private getContainer(): AlertComponent {
- // 创建指定类型的组件工厂(生产指定类型的组件)
- const factory = this.cfr.resolveComponentFactory(AlertComponent);
-
- // 根据指定的类型,创建组件的示例
- this.componentRef = factory.create(this.inject);
-
- // 将组件试图添加到试图树中,以激活变更检测
- this.appRef.attachView(this.componentRef.hostView);
-
- // 将组件到模版(包括app-alert标签),添加到body最后
- document.body.appendChild((this.componentRef.hostView as EmbeddedViewRef<{}>).rootNodes[0] as HTMLElement);
-
- // 监听组件销毁事件
- this.componentRef.onDestroy(() => {
- console.log('componentRef destory');
- });
-
- // 获取组件实例,相当于用@ViewChild获取子组件一样
- const { instance } = this.componentRef;
-
- // 监听组件到output事件
- instance.closed.subscribe(() => {
- this.componentRef.destroy();
- this.container = null;
- });
-
- return instance;
- }
-}
-```
-
-> v9和v10,动态组件都不需要entryComponents了,当然写了也没有问题
-> 从v11开始,entryComponents可能被删除
-> v8及以前,动态组件一定要声明entryComponents
-
-## NgTemplateOutlet指令
-
-> NgTemplateOutlet是一个结构型指令
-
-:memo:app.component.html
-
-```html
-
-
- 一段父组件传入的内容
-
-
-
-
- 一段父组件传入的内容
- 使用outlet中的context:{{context}}
- 使用outlet中的value:{{val}}
-
-
-```
-
-:memo:tmp-outlet.component.html
-
-```html
-tmp-outlet works!
-
-
-
-
-
-
-
-
-
-
- 一段组价默认的内容
-
-
-
-
- 一段组价默认的内容
- context:{{context}}
- value:{{val}}
-
-
-```
-
-:memo:tmp-outlet.component.ts
-
-```typescript
-import { Component, Input, OnInit } from '@angular/core';
-
-@Component({
- selector: 'app-tmp-outlet',
- templateUrl: './tmp-outlet.component.html',
- styleUrls: ['./tmp-outlet.component.css']
-})
-export class TmpOutletComponent implements OnInit {
-
- @Input() render
- myContext = {$implicit: 'tmp-outlet组件里的context', value: 'tmp-outlet组件里的value'};
- constructor() { }
-
- ngOnInit(): void {
- }
-
-}
-```
diff --git "a/docs/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md" "b/docs/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md"
deleted file mode 100644
index c36650fd..00000000
--- "a/docs/Framework/Angular/Angular\345\237\272\347\241\200\346\200\273\347\273\223\344\272\214.md"
+++ /dev/null
@@ -1,739 +0,0 @@
-## 双向绑定
-
-### 1. 基本双向绑定
-
-**方法一:**
-
-:memo:父组件:
-
-```typescript
-import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-root',
- template: `
-
-
-APP 字体大小: {{fontSizePx}}px
-`,
- styleUrls: ['./app.component.css']
-})
-export class AppComponent {
- fontSizePx = 16
-}
-
-```
-
-:memo:子组件:
-
-```typescript
-import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
-
-@Component({
- selector: 'app-sbind',
- template: `
-
-
-
sbind 字体大小: {{size}}px
-
`,
- styleUrls: ['./sbind.component.css']
-})
-export class SbindComponent implements OnInit {
-
- //默认值
- @Input() size=16;
-
- @Output() change = new EventEmitter();
-
- dec() {
- this.change.emit(this.size-1)
- }
- inc() {
- this.change.emit(this.size+1)
- }
-
- constructor() { }
- ngOnInit(): void {
- }
-}
-
-```
-
-**方法二:**(联合写法)
-
-:memo:父组件:`app.component.html`
-
-```html
-
-APP 字体大小: {{fontSizePx}}px
-
-```
-
-:memo:父组件:`app.component.ts`
-
-```typescript
-import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-root',
- template: './app.component.html',
- styleUrls: ['./app.component.css']
-})
-export class AppComponent {
- fontSizePx = 16
-}
-```
-
-:memo:子组件:`sbind.component.html`
-
-```html
-
-
-
-
sbind 字体大小: {{size}}px
-
-
-```
-
-:memo:子组件:`sbind.component.ts`
-
-```typescript
-import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
-
-@Component({
- selector: 'app-sbind',
- templateUrl: './sbind.component.html',
- styleUrls: ['./sbind.component.css']
-})
-export class SbindComponent implements OnInit {
-
- //默认值
- @Input() size=16;
-
- // 双向绑定语法:output变量名=输入属性名+Change
- @Output() sizeChange = new EventEmitter();
- constructor() { }
-
- dec() {//减
- this.sizeChange.emit(this.size-1)
- }
- inc() {//加
- this.sizeChange.emit(this.size+1)
- }
- ngOnInit(): void {
- }
-}
-```
-
-### 2. input双向绑定
-
-**普通写法:**
-
-```typescript
-
-{{inputVal}}
//默认值 inputVal=''
-```
-
-**简写形式:**
-
-::: warning
-
-**ngMoel 指令来源于FormsModule模块**
-
-`[(ngMoel)]`可拆解为:
-
-1. 名为ngModel的输入属性
-
-2. 名为ngModelChange的输出属性
-
-:::
-
-```html
-
-{{inputVal}}
-//默认值 inputVal=''
-
-
-```
-
-### 3. 表单Form中双向绑定
-
-::: tip
-
-表单中使用[(ngModel)],满足下列两个条件之一:
-
-- 给控件加上name属性
-- 将ngModelOptions.standalone设为true
-
-:::
-
-```html
-
-
-```
-
-::: details ngModel拓展
-
-```typescript
-@ViewChild(NgModel) private ngModel : NgModel;
-getVal(){
- console.log(this.ngModel.viewModel)//获取[(ngModel)]所绑定input的值
-}
-setVal(){
- this.ngModel.viewToModelUpdate( 'newValue')//赋值(不太好使)
-}
-```
-
-:::
-
-## 属性型指令
-
-> 指令:**用于改变DOM元素的外观或行为的指令**(组件是一种特殊的指令)
-
-::: details 组件改为属性型指令
-
-:memo:AppComponent
-
-```html
-dasfsada
-```
-
-```typescript
-import {Component} from '@angular/core';
-@Component({
- selector: '[app-decr]',//属性选择器
- template: `
- `,
-})
-export class DecrComponent {
- constructor() {}
-}
-```
-
-:::
-
-## 结构型指令
-
-### `*ngIf`指令
-
-```html
-一段文字 {{ isShow }}
-
-isShow:true显示,反之(取决于绑定的值是否为真)
-
-```
-
-::: warning
-
-会改变DOM结构,原理:移除和插入DOM节点
-
-:::
-
-::: details \*ngIf 完整写法
-
-```html
-
- 一段文字 {{ isShow }} {{s}}
-
-
-```
-
-:::
-
-**ngIfElese**
-
-```typescript
-import {Component} from '@angular/core';
-@Component({
- selector: 'app-if',
- template: `
- condition为真时显示
-
-
- condition为假时显示
-
- `,
-}) // ##elseBlock:模板的引用
-export class IfComp {
- condition = true;
-}
-```
-
-**ngIfThen**
-
-```typescript
-import {Component} from '@angular/core';
-@Component({
- selector: 'app-if',
- template: `
-
- condition为true时显示
- condition为false时显示
- `,
-})//只会显示一个ng-template,第一个div只是用于承载,并不会显示
-export class IfComp {
- condition = true;
-}
-```
-
-::: details TemplateRef拓展
-
-```typescript
-import {Component, OnInit, ChangeDetectionStrategy, ViewChild, TemplateRef, AfterViewInit} from '@angular/core';
-@Component({
- selector: 'app-if',
- template: `
-
- {{ condition }} === true 时显示
-
-
- {{ condition }} === false 时显示
-
- `,
-})
-export class IfComponent implements OnInit, AfterViewInit {
- elseBlocks: TemplateRef = null; //获取组件的变量elseBlocks
- @ViewChild('firstTpl', {static: true}) primaryBlock: TemplateRef = null;
- condition = false;
- constructor() {
-
- }
- ngOnInit(): void {
- console.log('ngOnInit', this.primaryBlock);
- this.elseBlocks = this.primaryBlock;
- //获取到##firstTpl模板引用赋值给elseBlocks变量
- }
-}
-//运行效果和ngIfElese案例一样
-```
-
-:::
-
-### `*ngFor`指令
-
-```typescript
-import {Component} from '@angular/core';
-
-@Component({
- selector: 'app-for',
- template: `
-
- `,
-})
-export class ForComponent {
- Persons = [
- {
- id: 'p1',
- name: '张三'
- },
- {
- id: 'p2',
- name: '李四'
- },
- {
- id: 'p3',
- name: '王五'
- },
-
-];
-trackByPerson(index,item){
- return item.id //追踪id,id值不变不刷新(提升性能)
- }
-}
-```
-
-::: details ngFor局部变量
-
-```js
- index: number //可迭代对象中当前条目的索引。
- count: number //可迭代对象的长度。
- first: boolean //如果当前条目是可迭代对象中的第一个条目则为 true。
- last: boolean //如果当前条目是可迭代对象中的最后一个条目则为 true。
- even: boolean //如果当前条目在可迭代对象中的索引号为偶数则为 true。
- odd: boolean //如果当前条目在可迭代对象中的索引号为奇数则为 true。
- $implicit: T //迭代目标(绑定到ngForOf)中每个条目的值。
- ngForOf: NgIterable //迭代表达式的值。当表达式不局限于访问某个属性时,这会非常有用,比如在使用 async 管道时(userStreams | async)。
-```
-
-:::
-
-::: details \*ngFor展开写法
-
-```html
-
-
- -
-
index: {{ i }}
- count: {{ len }}
- name: {{ item.name }}
- first: {{ f }} -- last: {{ l }}
-
-
-
-
-
-```
-
-:::
-
-### `[ngSwitch]`指令
-
-::: warning
-
-`[ngSwitch]` 为属性型指令
-
-`*ngSwitchCase`为结构型指令
-
-:::
-
-```typescript
-import {Component} from '@angular/core';
-@Component({
- selector: 'app-switch',
- template: `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- selected fruit: {{ fruit }}
-
-
-
这是 苹果
-
这是 梨
-
这是 葡萄
-
啥都不是
-
- `,
-})
-export class SwitchComponent {
- fruit = '';
-}
-```
-
-::: details [ngSwitch]展开写法
-
-```typescript
-
-
- 这是苹果
-
-
- 这是梨
-
-
- 这是葡萄
-
-
- 啥都不是
-
-
-```
-
-:::
-
-## 自定义指令
-
-使用:
-
-```html
-
-
-
-
-
-```
-
-### 自定义高亮指令(属性型)
-
-```typescript
-import {Directive, ElementRef, EventEmitter, HostListener, Input, Output} from '@angular/core';
-
-@Directive({
- selector: '[appHighlight]'
-})
-export class HighlightDirective {
- @Input() highlightColor: string;
- // @Input('appHighlight') highlightColor: string;起别名
- @Output() colorChange = new EventEmitter();
- //1.获取dom
- constructor(private el: ElementRef) {
- console.log('appHighlight');
- }
-
- @HostListener('mouseenter') onMouseEnter() {
- this.highlight(this.highlightColor || 'yellow');
- }
- //内部事件监听
- @HostListener('mouseleave',['$event']) onMouseLeave() {
- this.highlight('');
- console.log(event) //传递事件对象
- }
-
- private highlight(color: string) {
- //2.操作dom (操作dom备用选择)
- this.el.nativeElement.style.backgroundColor = color;
- this.colorChange.emit(color);
- }
-}
-```
-
-::: tip 相对于原生事件监听 addEventListener() 的优点 :
-
-1. 会自动销毁,不会导致内存泄漏
-
-2. 不用必须确保每个DOM API都能用
-
-:::
-
-### 自定义unless指令(结构型)
-
-::: details 定义
-
-```typescript
-import {Directive, Input, OnChanges, SimpleChanges, TemplateRef, ViewContainerRef} from '@angular/core';
-export class UnlessContext {
- $implicit: T = null;
- appUnless: T = null;
- attr: T = null;
-}
-@Directive({
- selector: '[appUnless]'
-})
-export class UnlessDirective implements OnChanges {
- @Input('appUnless') unless: boolean;
- private hasView = false;//是否已显示
- private context = new UnlessContext();
-
- constructor(private templateRef: TemplateRef, private viewContainer: ViewContainerRef) {
- // console.log(this.templateRef);
- // console.log(this.viewContainer);
- }
- //监听输入属性变化
- ngOnChanges(changes: SimpleChanges): void {
- if (changes['unless']) {
- this.context.$implicit = this.context.appUnless = this.unless;
- this.context.attr = 'aaab';
- if (this.unless) {
- if (this.hasView) {
- this.viewContainer.clear();
- this.hasView = false;
- }
- } else {
- if (!this.hasView) {
- // 这里使用的构造提供的模版(this.templateRef)
- // 实战中可以通过一个input属性传入模版
- this.viewContainer.createEmbeddedView(this.templateRef, this.context);
- this.hasView = true;
- }
- }
- }
- }
-}
-```
-
-:::
-
-::: details 调用
-
-```typescript
-import { Component } from '@angular/core';
-@Component({
- selector: 'app-root',
- template: `
-
- unless
-
- 测试unless driective -- {{ showUnless }}
- 测试unless driective alias un -- {{ un }}
- 别名: {{ un }} attr: {{ attr }}
-
- `,
-})
-export class AppComponent {
- show = false; //false: 显示 true: 隐藏
-}
-```
-
-:::
-
-## 模板元素
-
-### `ng-template`
-
-```html
-是一个 Angular 元素,用来渲染 HTML。 它永远不会直接显示出来。
- 事实上,在渲染视图之前,Angular 会把
- 及其内容替换为一个注释。
-
-```
-
-::: warning
-
-没有使用结构型指令,ng-template中的元素是不可见的
-
-:::
-
-### `ng-container`
-
-```html
-Angular 的
-
- 是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM
- 中。
-
- 是一个由 Angular 解析器负责识别处理的语法元素。
- 它不是一个指令、组件、类或接口,更像是 JavaScript 中 if 块中的花括号。
-
-
-```
-
-```js
-if (someCondition) {
- statement1
- statement2
- statement3
-}
-```
-
-### 模板引用变量
-
-> 使用井号(##)声明模板引用变量,可以获取DOM 元素、指令、组件、TemplateRef 或 Web Component。
-
-```typescript
-import {Component} from '@angular/core';
-@Component({
- selector: 'app-tpl-var',
- template: `
-
-
-
- `,
-}) //两种写法
-export class TplVarComponent {
- constructor() { }
- callPhone(value: string) {
- console.log('callPhone', value);
- }
-}
-```
-
-> 在外部获取组件引用,绑定组件内方法
-
-```typescript
-import {Component} from '@angular/core';
-@Component({
- selector: 'app-root',
- template: `
-
-
-
- size: {{ size }}
-
- `,
-})
-export class AppComponent {
- size = 16;
- constructor() { }
-}
-```
-
-## 操作符
-
-### 管道 `|`
-
-::: warning
-
-模板变量可以通过一条或多条管道格式化数据,
-
-默认的管道都是纯的,Angular 会忽略复合对象中的变化,即管道只会检查原始值或对象引用,
-
-如果数组中的元素变化,增删改,引用没有变化,而不会执行管道的逻辑。
-
-:::
-
-| 管道名称 | 作用 |
-| :----------------------------------------------------------: | :---------------------------------: |
-| [DatePipe](https://angular.cn/api/common/DatePipe) | 格式化日期 |
-| [DecimalPipe](https://angular.cn/api/common/DecimalPipe) | 数字转字符串,并可以指定格式 |
-| [KeyValuePipe](https://angular.cn/api/common/KeyValuePipe) | 使ngFor可以循环Object或Map对象 |
-| [JsonPipe](https://angular.cn/api/common/JsonPipe) | 将值转成json格式 |
-| [TitleCasePipe](https://angular.cn/api/common/TitleCasePipe) | 把首字母大写,其它小写 |
-| [SlicePipe](https://angular.cn/api/common/SlicePipe) | 截取Array或String |
-| [PercentPipe](https://angular.cn/api/common/PercentPipe) | 数字转百分比 |
-| [LowerCasePipe](https://angular.cn/api/common/LowerCasePipe) | 转化为小写 |
-| [UpperCasePipe](https://angular.cn/api/common/UpperCasePipe) | 转化为大写 |
-| [AsyncPipe](https://angular.cn/api/common/AsyncPipe) | 自动订阅模板中的Observable或Promise |
-
-### 安全链`?`
-
-> 用于可能为空的引用需要使用时,对null、undefined进行保护,保证数据请求前能正常渲染模板
-
-```html
-{{person?.name}}
-```
-
-### 非空断言`!`
-
-::: danger
-
-在ts中,开启--strictNullChecks后,将一个可能是undefined或null的变量赋给一个有确切类型的变量时,会报错。在特定情况下,我们断定变量一定不是undefined或null,就可以使用非空断言操作符。
-
-:::
-
-> **使用非空断言的两个步骤:**
->
-> tsconfig.json中设置`"strictNullChecks": true`
->
-> tslint.json中设置` "no-non-null-assertion": false`
-
-### 类型转换函数`$any()`
-
-> 绑定的表达式不能或很难指定类型时使用
-
-假设无法确定item的类型,也就不能确定item是否有bestByDate,这时就会报错。
-
-可以用$any()把item视为any类型,避免其报错(也可以用这个函数绑定组件中不存在的变量)
-
-```typescript
- {{$any(item).bestByDate}}
-```
diff --git "a/docs/Framework/React/React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md" "b/docs/Framework/React/React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md"
index 76d6a57a..c21b9f0e 100644
--- "a/docs/Framework/React/React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md"
+++ "b/docs/Framework/React/React\345\237\272\347\241\200\346\200\273\347\273\223\344\270\200.md"
@@ -367,7 +367,6 @@ saveFormData = (dataType, event) => {
1. react/vue中的key有什么作用?(key的内部原理是什么?)
2. 为什么遍历列表时,key最好不要用index?
-
3. 虚拟DOM中key的作用:
1. 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
diff --git "a/docs/FrontEnd/Git/Git\345\270\270\347\224\250\346\223\215\344\275\234.md" "b/docs/FrontEnd/Git/Git\345\270\270\347\224\250\346\223\215\344\275\234.md"
index 7cf560de..2f17cbfd 100644
--- "a/docs/FrontEnd/Git/Git\345\270\270\347\224\250\346\223\215\344\275\234.md"
+++ "b/docs/FrontEnd/Git/Git\345\270\270\347\224\250\346\223\215\344\275\234.md"
@@ -42,6 +42,7 @@ git reset --hard HEAD^1 #回退到上一个版本:最新一次提交的所有
```
## 忽略文件并删除已经提交到远程仓库的文件
+
> `.gitignore` 只会影响未提交到远程仓库的文件,已经提交到远程仓库的文件不会受影响
```zsh
diff --git "a/docs/FrontEnd/Git/Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md" "b/docs/FrontEnd/Git/Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md"
index c2290bb4..8ba7e8f9 100644
--- "a/docs/FrontEnd/Git/Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md"
+++ "b/docs/FrontEnd/Git/Terminal\347\273\210\347\253\257\347\276\216\345\214\226.md"
@@ -2,7 +2,7 @@
> 可以先去Microsofe Store 安装winget,会比较方便
-```bash
+```zsh
winget install JanDeDobbeleer.OhMyPosh
```
@@ -12,7 +12,7 @@ winget install JanDeDobbeleer.OhMyPosh
## 预览所有主题命令
-```bash
+```zsh
Get-PoshThemes
```
@@ -20,7 +20,7 @@ Get-PoshThemes
## 初始化并应用主题
-```bash
+```zsh
oh-my-posh --init --shell pwsh --config "自己的安装目录\oh-my-posh\themes\schema.json" | Invoke-Expression
#schema.json ---- 选择themes目录下的一款主题文件
```
@@ -43,7 +43,7 @@ PS:刚开始以为没有我常用的`JetBrain Mono`字体,就没在意这种
- 获取到PowerShell配置文件绝对路径
-```bash
+```zsh
$PROFILE
```
@@ -51,7 +51,7 @@ $PROFILE
- 找到这个文件位置,打开并添加需要Power Shell启动时执行的脚本,保存文件重新打开Terminal看效果
-```bash
+```zsh
oh-my-posh --init --shell pwsh --config "自己的安装目录\oh-my-posh\themes\schema.json" | Invoke-Expression
```
@@ -59,7 +59,7 @@ oh-my-posh --init --shell pwsh --config "自己的安装目录\oh-my-posh\themes
> 如果安装了VS Code,如下命令可以直接打开Power Shell配置文件
-```bash
+```zsh
code $PROFILE
```
@@ -73,7 +73,7 @@ code $PROFILE
没有配置打开VS Code终端报错:
-```bash
+```zsh
The term 'oh-my-posh' is not recognized as a name of a cmdlet, function, script file, or executable program. Check the spelling of the name, or if a path was included, verify
| that the path is correct and try again.
```
diff --git "a/docs/FrontEnd/Git/\351\205\215\347\275\256 Ubuntu \346\234\215\345\212\241\345\231\250\345\205\215\345\257\206\347\231\273\345\275\225.md" "b/docs/FrontEnd/Git/\351\205\215\347\275\256 Ubuntu \346\234\215\345\212\241\345\231\250\345\205\215\345\257\206\347\231\273\345\275\225.md"
index ac70ea4b..dc1d060a 100644
--- "a/docs/FrontEnd/Git/\351\205\215\347\275\256 Ubuntu \346\234\215\345\212\241\345\231\250\345\205\215\345\257\206\347\231\273\345\275\225.md"
+++ "b/docs/FrontEnd/Git/\351\205\215\347\275\256 Ubuntu \346\234\215\345\212\241\345\231\250\345\205\215\345\257\206\347\231\273\345\275\225.md"
@@ -1,6 +1,6 @@
## 1.生成公钥和私钥
-```bash
+```zsh
cd ~/.ssh # 进入.ssh目录
ssh-keygen
# 第一步输入生成的公、私钥文件名,例如:aws-root
@@ -9,14 +9,14 @@ ssh-keygen
## 2.将公钥拷贝到服务器
-```bash
+```zsh
ssh-copy-id -i 公钥 服务器ip
# ssh-copy-id -i aws-root.pub 192.227.112.172
```
## 3.查看服务器是否配置成功
-```bash
+```zsh
ssh root@192.227.112.172
cd ~/.ssh
cat authorized_keys # 查看是否有上传的公钥
@@ -24,7 +24,7 @@ cat authorized_keys # 查看是否有上传的公钥
## 4.配置 ssh config文件
-```bash
+```zsh
vim /etc/ssh/sshd_config
PermitRootLogin yes # no改为yes # 允许root用户登录:解决root用户登录报错 Permission denied 问题
PubkeyAuthentication yes # no改为yes
@@ -36,7 +36,7 @@ systemctl restart sshd.service
## 5.测试连接、配置本地ssh config文件,使用 VSCODE插件 ([Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh)) 连接
-```bash
+```zsh
# 测试连接
ssh -i ~/.ssh/aws-root root@192.227.112.172
diff --git "a/docs/FrontEnd/Git/\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md" "b/docs/FrontEnd/Git/\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md"
index 8a4fadc4..47f72c4a 100644
--- "a/docs/FrontEnd/Git/\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md"
+++ "b/docs/FrontEnd/Git/\351\205\215\347\275\256\345\244\232\344\270\252\345\271\263\345\217\260SSH.md"
@@ -1,6 +1,6 @@
## 1.生成公钥和私钥
-```bash
+```zsh
ssh-keygen -t rsa -C '88888@qq.com' #换成自己邮箱,可以随便填,相当于一个标识
#密码不用填 直接回车
```
@@ -22,7 +22,7 @@ ssh-keygen -t rsa -C '88888@qq.com' #换成自己邮箱,可以随便填,相当
> 定义一系列 SSH 连接的配置信息,当你使用 SSH 连接到这些平台时,SSH 客户端会根据这个配置文件选择正确的私钥进行身份验证。
-```bash
+```zsh
Host github.com #Github主机地址
HostName github.com #Github主机名
PreferredAuthentications publickey
@@ -51,7 +51,7 @@ IdentityFile ~/.ssh/gitlab #私钥地址
`Hi CoderFXJ! You've successfully authenticated, but GitHub does not provide shell access.`
- ```bash
+ ```zsh
ssh -T git@gitee.com
ssh -T git@github.com
diff --git "a/docs/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md" "b/docs/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md"
index 4ef12fec..60663bdb 100644
--- "a/docs/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md"
+++ "b/docs/FrontEnd/JavaScript/\345\237\272\347\241\200\345\244\215\344\271\240\344\272\214.md"
@@ -51,9 +51,9 @@ fn.apply()
:::
```js
-fn2.call(obj, "hello", true)//会立即执行
-fn2.apply(obj, ["hello", true])//会立即执行
-let newfn = fn.bind(obj, 10, 20, 30)//不会立即执行, 返回一个新函数 newfn()
+fn2.call(obj, 'hello', true)// 会立即执行
+fn2.apply(obj, ['hello', true])// 会立即执行
+const newfn = fn.bind(obj, 10, 20, 30)// 不会立即执行, 返回一个新函数 newfn()
```
箭头函数没有自身的this,它的this由定义时外层作用域决定,
@@ -177,15 +177,15 @@ const map2 = new Map([
```js
// [0,1)
- Math.random()
-//生成 0-max之间的随机整数:
+Math.random()
+// 生成 0-max之间的随机整数:
Math.round(Math.random() * max)
Math.floor(Math.random() * (max + 1))
-//生成 x-y 之间的随机数
-Math.round(Math.random() * (y-x) + x)
+// 生成 x-y 之间的随机数
+Math.round(Math.random() * (y - x) + x)
-// (min,max)
+// (min,max)
// Math.round(Math.random()*(max-min-2)+min+1)
// [min,max]
@@ -199,17 +199,22 @@ Math.round(Math.random() * (y-x) + x)
```
### 打印 0-max 以内的质数
+
```js
function isPrime(num) {
- if (num <= 1) return false; // 质数必须大于1
- if (num <= 3) return true; // 2和3是质数
- if (num % 2 === 0 || num % 3 === 0) return false; // 排除能被2和3整除的数
+ if (num <= 1)
+ return false // 质数必须大于1
+ if (num <= 3)
+ return true // 2和3是质数
+ if (num % 2 === 0 || num % 3 === 0)
+ return false // 排除能被2和3整除的数
// 只检查到sqrt(num),因为如果一个数不是质数,它必有一个因子小于或等于它的平方根
for (let i = 5; i * i <= num; i += 6) {
- if (num % i === 0 || num % (i + 2) === 0) return false;
+ if (num % i === 0 || num % (i + 2) === 0)
+ return false
}
- return true;
+ return true
}
function printPrimes(max) {
@@ -223,8 +228,8 @@ function printPrimes(max) {
}
// 假设max是一个正整数
-let max = 100; // 你可以将100替换为任何你想要检查的上限
-printPrimes(max);
+const max = 100 // 你可以将100替换为任何你想要检查的上限
+printPrimes(max)
```
### 时间格式化
@@ -510,10 +515,11 @@ function MyClass() {
3. **自定义对象**: 由开发人员自己创建的对象(Vue, React)
### 提取URL参数
+
```js
const url = 'https://www.baidu.com?a=1&b=2#hash'
-function getURLParams(url){
- let params = url.split('?')[1].split('#')[0]
+function getURLParams(url) {
+ const params = url.split('?')[1].split('#')[0]
const usp = new URLSearchParams(params)
return Object.fromEntries(usp.entries())
}
diff --git "a/docs/FrontEnd/JavaScript/\346\225\260\346\215\256\345\216\273\351\207\215.md" "b/docs/FrontEnd/JavaScript/\346\225\260\346\215\256\345\216\273\351\207\215.md"
index 0a2e750b..090532fd 100644
--- "a/docs/FrontEnd/JavaScript/\346\225\260\346\215\256\345\216\273\351\207\215.md"
+++ "b/docs/FrontEnd/JavaScript/\346\225\260\346\215\256\345\216\273\351\207\215.md"
@@ -73,7 +73,7 @@ uniqueArr(arr) // ['a', 'b', 1, '/abc/', 1678519417983]
3. 处理数组类型,对比项的数量,再递归对比每个项是否相等;
4. 处理朴素对象,对比键的数量,相等则再递归对比值是否相等。
-```javascript
+```js
function isEqual(obj1, obj2) {
const equalType = (val1, val2) => Object.prototype.toString.call(val1) !== Object.prototype.toString.call(val2)
// 判断类型是否一致
diff --git "a/docs/FrontEnd/JavaScript/\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md" "b/docs/FrontEnd/JavaScript/\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md"
index f456fc40..789ce4d1 100644
--- "a/docs/FrontEnd/JavaScript/\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md"
+++ "b/docs/FrontEnd/JavaScript/\346\225\260\347\273\204\346\261\202\351\233\206\345\220\210.md"
@@ -12,20 +12,20 @@ const b = [4, 3, 2]
### 一、并集(A∪B)
```js
-//方法一:
+// 方法一:
;
// 虽然 NaN 和 NaN 不相等,但是在 Set 集合里面只会存在一个
// undefined 和 Infinity 在 Set 集合里面也只会存在一个
-let a = [1, 2, 3, NaN];
-let b = [2, 4, 5, NaN];
-const union = (arr1,arr2) => [...new Set([...arr1, ...arr2])]// [1, 2, 3, NaN, 4, 5]
+const a = [1, 2, 3, Number.NaN]
+const b = [2, 4, 5, Number.NaN]
+const union = (arr1, arr2) => [...new Set([...arr1, ...arr2])]// [1, 2, 3, NaN, 4, 5]
-//方法二:
-const union = (arr1,arr2) => Array.from(new Set(arr1.concat(arr2)))
+// 方法二:
+const union1 = (arr1, arr2) => Array.from(new Set(arr1.concat(arr2)))
-//先b筛选a中没有的,再连接数组
-const union = (arr1,arr2) => arr1.concat(arr2.filter(val => !arr1.includes(val)))
-const union = (arr1,arr2) => arr1.concat(arr2.filter(val=> arr2.indexOf(val) === -1));
+// 先b筛选a中没有的,再连接数组
+const union2 = (arr1, arr2) => arr1.concat(arr2.filter(val => !arr1.includes(val)))
+const union3 = (arr1, arr2) => arr1.concat(arr2.filter(val => !arr2.includes(val)))
```
### 二、交集(*A*∩B)
@@ -82,47 +82,47 @@ const b = [
```js
// 用额外对象记录当前项 id 相同的是否收集,此 id 未收集,则进行收集
-//写法一:
-const union = (arr1,arr2) =>{
- let obj = {};
- let arr = arr1.concat(arr2);
- return arr.reduce( (pre,cur) => {
- if(!obj[cur.id]){
- pre.push(cur)
- obj[cur.id] = true
- }
- return pre
- },[])
+// 写法一:
+function union(arr1, arr2) {
+ const obj = {}
+ const arr = arr1.concat(arr2)
+ return arr.reduce((pre, cur) => {
+ if (!obj[cur.id]) {
+ pre.push(cur)
+ obj[cur.id] = true
+ }
+ return pre
+ }, [])
}
-//写法二:
-const union = (arr1,arr2)=>{
- let arr = arr1.concat(arr2)
- let res = []
- for(let i = 0; i < arr.length; i++){
- if(res.findIndex(item => item.id === arr[i].id)===-1){
+// 写法二:
+function union2(arr1, arr2) {
+ const arr = arr1.concat(arr2)
+ const res = []
+ for (let i = 0; i < arr.length; i++) {
+ if (res.findIndex(item => item.id === arr[i].id) === -1) {
res.push(c[i])
}
}
return res
}
- //简化
- //判断目标在数组中相同的 id 是否存在
-const isExist = (arr,target,attr) => arr.findIndex(item => item[attr] == target[attr]) != -1
-//合并数组并遍历,判断新数组不存在当前项,则收集
-const union = (arr1,arr2) => arr1.concat(arr2).reduce((pre,cur) => isExist(pre,cur,'id') ? pre : [...pre,cur],[])
+// 简化
+// 判断目标在数组中相同的 id 是否存在
+const isExist = (arr, target, attr) => arr.findIndex(item => item[attr] == target[attr]) != -1
+// 合并数组并遍历,判断新数组不存在当前项,则收集
+const union3 = (arr1, arr2) => arr1.concat(arr2).reduce((pre, cur) => isExist(pre, cur, 'id') ? pre : [...pre, cur], [])
```
### 二、交集(*A*∩B)
```js
-//方法一:
-const intersection = (arr1,arr2) => {
- const aids = a.map(item => item.id)
- return arr2.filter(item => aids.includes(item.id))
+// 方法一:
+function intersection(arr1, arr2) {
+ const aids = a.map(item => item.id)
+ return arr2.filter(item => aids.includes(item.id))
}
-//方法二:
-const intersection = (arr1,arr2) => arr1.reduce((pre,cur) => arr2.findIndex(item => item.id == cur.id) != -1 ? [...pre,cur] : pre,[])
+// 方法二:
+const intersection1 = (arr1, arr2) => arr1.reduce((pre, cur) => arr2.findIndex(item => item.id == cur.id) != -1 ? [...pre, cur] : pre, [])
```
### 三、差集(A-B)
diff --git "a/docs/FrontEnd/JavaScript/\346\226\207\344\273\266\347\263\273\347\273\237.md" "b/docs/FrontEnd/JavaScript/\346\226\207\344\273\266\347\263\273\347\273\237.md"
index f87a4d63..67e44e4e 100644
--- "a/docs/FrontEnd/JavaScript/\346\226\207\344\273\266\347\263\273\347\273\237.md"
+++ "b/docs/FrontEnd/JavaScript/\346\226\207\344\273\266\347\263\273\347\273\237.md"
@@ -57,20 +57,20 @@ console.log('[ dataView.getUint8(0) ]-20', dataView.getUint8(0))
## FilePicker
```js
-const openFilePicker = async (e: any) => {
- const option = {
- title: 'Open File',
- accept: {
+async function openFilePicker(e) {
+ const option = {
+ title: 'Open File',
+ accept: {
'image/*': ['.png', '.jpg', '.jpeg'],
- },
- }
- const [fileHandle] = await (window as any).showOpenFilePicker(option)
- const file = await fileHandle.getFile()
- const fileReader = new FileReader()
- fileReader.readAsArrayBuffer(file)
- fileReader.onload = (e) => {
- console.log('[ e ]-11', e.target?.result)
- }
+ },
+ }
+ const [fileHandle] = await (window).showOpenFilePicker(option)
+ const file = await fileHandle.getFile()
+ const fileReader = new FileReader()
+ fileReader.readAsArrayBuffer(file)
+ fileReader.onload = (e) => {
+ console.log('[ e ]-11', e.target?.result)
+ }
}
```
diff --git "a/docs/FrontEnd/JavaScript/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" "b/docs/FrontEnd/JavaScript/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md"
index 6f43aef3..90d9f32e 100644
--- "a/docs/FrontEnd/JavaScript/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md"
+++ "b/docs/FrontEnd/JavaScript/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md"
@@ -12,14 +12,14 @@
## 1. 或者 `|`
-```javascript
+```js
const tel = '020-99999999'
console.log(/(010|020)-\d{8}/.test(tel))// true
```
## 2. 原子表`[]`、原子组`()`
-```javascript
+```js
//原子表
let reg = /[123456]/ //出现在其中就匹配成功
console.log(reg.test("2")) //true
@@ -37,7 +37,7 @@ console.log(reg.test("hdjfaks35fjj")) //false
## 3. 边界符`^`、`$`
-```javascript
+```js
let tel = "12020-99999999"
console.log(/^(010|020)\-\d{8}/.test(tel));//false 以010开头
@@ -51,14 +51,14 @@ console.log(/^(010|020)\-\d{8}$/.test(tel));//false 以8位数结尾
## 5. 匹配所有字符
-```javascript
+```js
/[\s\S]/
/[\d\D]/
```
## 6. 模式修正符号`i`、`g`
-```javascript
+```js
const hd = 'djfkdjakDJFKJD'
hd.match(/[a-z]/gi)
// i 不区分大小写
@@ -75,7 +75,7 @@ hdstr.match(/\p{L}/gu) // 匹配所有字母
## 7. 原子组中的原子表`([-\/])`
-```javascript
+```js
let dateStr = '2022-08-30' 或 '2022/08/30'//true
let reg = /^\d{4}([-\/])\d{2}\1\d{2}/
console.log(reg.test('2022-08/30') //false
@@ -113,7 +113,7 @@ let mailReg = /^\w[\w-]+@[\w]([\w-]+.)+(com|cn|cc|net|org)/
## 8.贪婪匹配`+`、`*`、`?`
-```javascript
+```js
+ //一个或多个
* //0个或多个
? //0个或1个
@@ -137,7 +137,7 @@ let newhtml= html.replace(regbaidu1,(v,p1)=> `${p1}
`)
### 批量验证密码
-```javascript
+```js
let psdRegs = [/^[0-9a-z]{6,10}$/i,/[A-Z]/,/[0-9]/]
let result = psdRegs.every(reg => reg.test('fdkafad')) //false
let result = psdRegs.every(reg => reg.test('1f12aA')) //true
@@ -145,14 +145,14 @@ let result = psdRegs.every(reg => reg.test('1f12aA')) //true
## 9. matchAll
-```javascript
+```js
const hstr = `www.baidu.com
www.map.baidu.com
百度一下
`
const breg = /<(h[1-6])>([\s\S]+)<\/\1>/gi
hstr.match(breg) // 全局匹配拿不到它每个原子组
- ['www.baidu.com
', 'www.map.baidu.com
', '百度一下
']
+// ['www.baidu.com
', 'www.map.baidu.com
', '百度一下
']
// 解决方法:使用matchAll
for (it of hstr.matchAll(breg)) {
@@ -171,8 +171,8 @@ for (it of hstr.matchAll(breg)) {
## 10. 断言匹配``
-```javascript
-let reg = /百度(?=地图)/g
+```js
+/* let reg = /百度(?=地图)/g
// 只有百度后面有地图两字的才满足要求
let htm = 百度一下,百度地图
p.innerHTML.replace(reg,`$&`)
@@ -190,7 +190,7 @@ let reg = /^(?!.*百度.*)[a-z]{4,5}$/i
? {
return n < 100
@@ -183,7 +183,7 @@ Vue.component('ele', {
render(createElement) {
return createElement(
'div',
- Array.apply(null, { length: 5 }).map(() => createElement(Child))
+ Array.prototype.apply(null, { length: 5 }).map(() => createElement(Child))
)
},
})
diff --git "a/docs/FrontEnd/Shell/\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md" "b/docs/FrontEnd/Shell/\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md"
index 4c65953d..0497361c 100644
--- "a/docs/FrontEnd/Shell/\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md"
+++ "b/docs/FrontEnd/Shell/\350\207\252\345\212\250\351\203\250\347\275\262\350\204\232\346\234\254.md"
@@ -102,5 +102,4 @@ jobs:
gitee-repo: ${{ env.REPO_NAME }}
# 要部署的分支,默认是 master,若是其他分支,则需要指定(指定的分支必须存在)
branch: gh-pages
-
```
diff --git "a/docs/FrontEnd/Shell/\350\216\267\345\217\226\351\241\265\351\235\242\346\211\200\346\234\211\345\237\237\345\220\215\345\271\266\345\216\273\351\207\215.md" "b/docs/FrontEnd/Shell/\350\216\267\345\217\226\351\241\265\351\235\242\346\211\200\346\234\211\345\237\237\345\220\215\345\271\266\345\216\273\351\207\215.md"
index 5ed66cde..476d68b0 100644
--- "a/docs/FrontEnd/Shell/\350\216\267\345\217\226\351\241\265\351\235\242\346\211\200\346\234\211\345\237\237\345\220\215\345\271\266\345\216\273\351\207\215.md"
+++ "b/docs/FrontEnd/Shell/\350\216\267\345\217\226\351\241\265\351\235\242\346\211\200\346\234\211\345\237\237\345\220\215\345\271\266\345\216\273\351\207\215.md"
@@ -1,6 +1,7 @@
-
## 获取当前页所有域名并写入剪切板
+
> 快捷使用:新建浏览器书签,写入脚本
+
```js
javascript:(async function () {
const domains = new Set()
diff --git "a/docs/FrontEnd/TypeScript/\345\210\235\345\255\246\347\254\224\350\256\260.md" "b/docs/FrontEnd/TypeScript/\345\210\235\345\255\246\347\254\224\350\256\260.md"
index f4582288..06c2c5c9 100644
--- "a/docs/FrontEnd/TypeScript/\345\210\235\345\255\246\347\254\224\350\256\260.md"
+++ "b/docs/FrontEnd/TypeScript/\345\210\235\345\255\246\347\254\224\350\256\260.md"
@@ -17,25 +17,25 @@ undefined // 默认情况下null和undefined是所有类型的子类型。可以
::: warning **object 类型常见用法**
:::
-```typescript
+```ts twoslash
//1.严格要求
let b :{name: string ,age: number}
b = { name:'zhangsan ',age :18}
```
-```typescript
+```ts
//2.可选
let b :{name: string ,age?: number}
b = { name:'zhangsna '}
```
-```typescript
+```ts
//3.多个可选
let b :{name: string ,[porname:string]:string}
b = { name:'zhangsna ',address:'上海',gender:'男'}
```
-```typescript
+```ts
//4.箭头函数设置函数结构
let d: (c:number,d:number)=>number
d = function(n1,n2){
@@ -46,7 +46,7 @@ d = function(n1,n2){
::: warning **数组**
:::
-```typescript
+```ts
let arr: string[] //字符串数组 arr = ['zhansan','lisi']
let arr1:Array //数值数组 arr1 = [1,2,3,4,5]
```
@@ -54,7 +54,7 @@ let arr1:Array //数值数组 arr1 = [1,2,3,4,5]
::: warning **元组**
:::
-```typescript
+```ts
let h: [string ,number]
h = ['hello', 123]
```
@@ -62,7 +62,7 @@ h = ['hello', 123]
::: warning **枚举**
:::
-```typescript
+```ts
enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green; //c为2
Color[2] // Green 枚举的值得到它的名字
@@ -70,7 +70,7 @@ Color[2] // Green 枚举的值得到它的名字
#### TS新增类型
-```typescript
+```ts
字面量 //限制类型在几个值之间(联合类型)例:let b : 'male'|'amale' 、
enum //枚举类型
tuple //元组 [string, number];
@@ -84,13 +84,13 @@ never //永远不返回结果,没有类型是never的子类型、没有类型
::: warning `unknown`与`any`区别
:::
-```typescript
+```ts
let a: any
let b: string
b = a // OK any类型可以赋值任意类型
```
-```typescript
+```ts
let e: unknown
e = 'TypeScript'
let f: string
@@ -108,7 +108,7 @@ f = e
::: warning `|`和`&` :表示或,&:表示且
:::
-```typescript
+```ts
let g: string | boolean
g = 'sdfj'
g = true
@@ -123,14 +123,14 @@ f = {
### 二、类型声名
-```typescript
+```ts
let name:string //声名string类型变量
let age = 19 //类型声名可省略,会自动类型推断,age推断为number
```
### 三、as const 断言
-```typescript
+```ts
let a = 99 as const //a值只能为99,指定明确的值、类型
let b:string = 'asfghj'
let obj = {
@@ -138,7 +138,7 @@ let obj = {
} as const
```
-```typescript
+```ts
let x = 1024
let y = '2048'
@@ -151,7 +151,7 @@ let arr = [x,y] as const // 指定为元组,arr[1]类型只能为 number
### 一、类
-```typescript
+```ts
class 类名 {
属性名: 类型;
@@ -169,7 +169,7 @@ class 类名 {
**栗子:**
-```typescript
+```ts
class Person{
name: string;
age: number;
@@ -189,7 +189,7 @@ class 类名 {
> **注1:在TS中只能有一个构造器方法!**
-```typescript
+```ts
class Person{
name: string;
age: number
@@ -204,7 +204,7 @@ class Person{
> **注2:子类继承父类时,必须调用父类的构造方法(如果子类中也定义了构造方法)!**
-```typescript
+```ts
class A {
protected num: number;
constructor(num: number) {
@@ -240,7 +240,7 @@ class X extends A {
::: details public
-```typescript
+```ts
class Person{
public name: string; // 写或什么都不写都是public
public age: number;
@@ -271,7 +271,7 @@ p.name = '猪八戒';// 可以通过对象修改
::: details protected
-```typescript
+```ts
class Person{
protected name: string;
protected age: number;
@@ -303,7 +303,7 @@ p.name = '猪八戒';// 不能修改
::: details private
-```typescript
+```ts
class Person{
private name: string;
private age: number;
@@ -345,7 +345,7 @@ p.name = '猪八戒';// 不能修改
::: details 示例
-```typescript
+```ts
class Person{
private _name: string;
@@ -379,7 +379,7 @@ p1.name = '猪八戒';
>
> 静态属性(方法)使用static开头
-```typescript
+```ts
class Tools{
static PI = 3.1415926;
@@ -397,7 +397,7 @@ console.log(Tools.sum(123, 456));
> 通过继承可以将其他类中的属性和方法引入到当前类中,通过继承可以在不修改类的情况下完成对类的扩展
-```typescript
+```ts
class Animal{
name: string;
age: number;
@@ -424,7 +424,7 @@ dog.bark();
> 发生继承时,如果子类中的方法会替换掉父类中的同名方法,这就称为方法的重写
-```typescript
+```ts
class Animal{
name: string;
age: number;
@@ -461,7 +461,7 @@ dog.bark();
>
> 使用abstract开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,继承抽象类时抽象方法必须要实现;
-```typescript
+```ts
abstract class Animal{
abstract run(): void;
bark(){
@@ -479,7 +479,7 @@ class Dog extends Animals{
### 六、接口
-```typescript
+```ts
//用于类型检查
interface Person {
firstName: string;
@@ -602,7 +602,7 @@ function greeter(person: Person) {
#### 2. 下载构建工具
-```bash
+```zsh
npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin
```
@@ -724,7 +724,7 @@ module.exports = {
#### 5 .修改package.json配置
-```typescript {6}
+```ts {6}
{
...
"scripts": {
@@ -767,40 +767,39 @@ module.exports = {
#### 7.2 修改webpack.config.js配置文件
```js
-...
+// ...
module: {
- rules: [
+ rules: [
+ {
+ test: /\.ts$/,
+ use: [
{
- test: /\.ts$/,
- use: [
- {
- loader: "babel-loader",
- options:{
- presets: [
- [
- "@babel/preset-env",
- { //支持的目标版本
- "targets":{
- "chrome": "58",
- "ie": "11"
- },
- //corejs版本
- "corejs":"3",
- "useBuiltIns": "usage"
- }
- ]
- ]
- }
- },
- {
- loader: "ts-loader",
-
+ loader: 'babel-loader',
+ options: {
+ presets: [
+ [
+ '@babel/preset-env',
+ { // 支持的目标版本
+ targets: {
+ chrome: '58',
+ ie: '11'
+ },
+ // corejs版本
+ corejs: '3',
+ useBuiltIns: 'usage'
}
- ],
- exclude: /node_modules/
+ ]
+ ]
+ }
+ },
+ {
+ loader: 'ts-loader',
+
}
- ]
+ ],
+ exclude: /node_modules/
+ }
+ ]
}
-...
-
+// ...
```
diff --git "a/docs/FrontEnd/TypeScript/\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md" "b/docs/FrontEnd/TypeScript/\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md"
index 3d8c12af..7ca688d0 100644
--- "a/docs/FrontEnd/TypeScript/\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md"
+++ "b/docs/FrontEnd/TypeScript/\351\205\215\347\275\256\346\226\207\344\273\266\350\257\246\350\247\243.md"
@@ -111,23 +111,22 @@ TypeScript是ES6的超集,所以你可以使用ES6来编写ts代码(通常
这是一个非常有用的选项,比如我们经常使用'@/util/help'来代替'./src/util/help',省的每次在不同层级文件import模块时,都纠结于是'./'还是'../'。该选项告诉编译器遇到匹配的值时,去映射的路径下加载模块。
```ts
-{
- "baseUrl": ".", // 注意:baseUrl不可少
- "paths": {
- // 映射列表
- "@/*": [
- "src/*"
- ],
- "moduleA": [
- "src/libs/moduleA"
- ]
- }
-}
-
// in ts code
+import TestModule from 'moduleA/index.js'
import Setting from '@/components/Setting.vue' // 模块实际位置: src/components/Setting.vue
-import TestModule from 'moduleA/index.js' // 模块实际位置: src/libs/moduleA/index.js
+export default {
+ baseUrl: '.', // 注意:baseUrl不可少
+ paths: {
+ // 映射列表
+ '@/*': [
+ 'src/*'
+ ],
+ 'moduleA': [
+ 'src/libs/moduleA'
+ ]
+ }
+} // 模块实际位置: src/libs/moduleA/index.js
```
## 9. strictNullChecks
@@ -181,18 +180,17 @@ foo && foo.push('1') // okay
未设置include时,编译器默认包含当前目录和子目录下所有的TypeScript文件(.ts, .d.ts 和 .tsx)。如果allowJs被设置成true,JS文件(.js和.jsx)也被包含进来。exclude排除那些不需要编译的文件或文件夹。
-```ts
+```json
{
- "compilerOptions": {},
- "include": [
- "src/**/*"
- ],
- "exclude": [
- "node_modules",
- "**/*.spec.ts"
- ]
+ "compilerOptions": {},
+ "include": [
+ "src/**/*"
+ ],
+ "exclude": [
+ "node_modules",
+ "**/*.spec.ts"
+ ]
}
-
```
## tsconfig.json全解析
diff --git "a/docs/Interview/ALGO/\345\270\270\350\247\201\347\256\227\346\263\225.md" "b/docs/Interview/ALGO/\345\270\270\350\247\201\347\256\227\346\263\225.md"
index b79e066a..47e6fa7b 100644
--- "a/docs/Interview/ALGO/\345\270\270\350\247\201\347\256\227\346\263\225.md"
+++ "b/docs/Interview/ALGO/\345\270\270\350\247\201\347\256\227\346\263\225.md"
@@ -2,7 +2,7 @@
```js
const str1 = '{[]}' // true
-const str2 = '{(?:\.\d+)/ false
+const str2 = '{(?:\.\d+)' // false
const str3 = '{[]}[' // false
const str4 = '{[()]}' // true
```
@@ -116,7 +116,6 @@ function flat(arr) {
}
const array1 = [2, 3, 4, [4, 6, 5, 8]]
flat(array1)[(2, 3, 4, 4, 6, 5, 8)]
-
```
```js
@@ -445,7 +444,6 @@ function findMedianSortedArrays(nums1, nums2) {
}
```
-
## [生成随机十六进制颜色](https://css-tricks.com/snippets/javascript/random-hex-color/)
方案一:
@@ -690,7 +688,7 @@ function printLinkedList(head) {
- 中序遍历:先访问左子树,然后访问节点,最后访问右子树。
- 后序遍历:先访问左子树,然后访问右子树,最后访问节点。
-```javascript
+```js
// 定义二叉树节点类
class TreeNode {
constructor(val) {
@@ -878,7 +876,7 @@ BST.prototype.search = function (value) {
## 字符串搜索算法
-```javascript
+```js
// KMP算法是一种高效的字符串搜索算法,在对文本串和模式串进行匹配时,通过利用前缀表来避免不必要的比较,从而实现快速匹配。
function kmp(text, pattern) {
const n = text.length
@@ -919,7 +917,7 @@ function kmp(text, pattern) {
接下来,我们可以使用这个函数来测试一下:
-```javascript
+```js
const text = 'hello world'
const pattern = 'world'
const index = kmp(text, pattern)
@@ -930,7 +928,7 @@ console.log(index) // 输出5
这里还可以尝试一些其他的测试用例,例如:
-```javascript
+```js
const text = 'abababaababacb'
const pattern = 'ababacb'
const index = kmp(text, pattern)
@@ -947,7 +945,7 @@ console.log(index) // 输出7
```js
function numberToChinese(num, upper = false) {
- if (!/^-?\d+(\.\d+)?$/.test(num))
+ if (!/^-?\d+\.\d+$/.test(num))
return '不是一个合法的数字!'
const digitMap = {
@@ -1012,7 +1010,7 @@ function numberToChinese(num) {
.split('')
.reverse()
.join('')
- .match(/(\d{1,4})/g)
+ .match(/\d{1,4}/g)
.join(',')
.split('')
.reverse()
@@ -1081,7 +1079,6 @@ const n = bigChinese(1000100001) // 拾億零壹拾萬零壹
console.log('[ n ]-66', n)
```
-
## 深度优先和广度优先
```js
@@ -1177,23 +1174,25 @@ JavaScript 中 BFS 的时间复杂度为 O(n),其中 n 是节点数。空间
```js
function bfs(root) {
- let nodes = []
- const queue = [root];
+ const nodes = []
+ const queue = [root]
while (queue.length > 0) {
- const node = queue.shift();
+ const node = queue.shift()
nodes.push(node.id)
- node.children?.forEach(child => {
- queue.push(child);
- });
+ node.children?.forEach((child) => {
+ queue.push(child)
+ })
}
return nodes
}
-//简化后
-function bfs(root){
- let nodes = []
- let node,queue = [root]
- while(node = queue.shift()){
+// 简化后
+function bfs1(root) {
+ const nodes = []
+ let node
+ const queue = [root]
+ // eslint-disable-next-line no-cond-assign
+ while (node = queue.shift()) {
nodes.push(node.id)
node.children && queue.push(...node.children)
}
@@ -1202,19 +1201,6 @@ function bfs(root){
```
-```js
-function bfs(node) {
- const nodes = []
- if (node !== null) {
- nodes.push(node)
- let i = 0
- while (node = nodes[i++])
- node.children && nodes.push(...node.children)
- }
- return nodes
-}
-```
-
### 两者的区别
- 广度优先遍历需要使用队列逐层扫描节点,而深度优先遍历需要使用递归或栈来遍历节点。
diff --git "a/docs/Interview/Brower/\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md" "b/docs/Interview/Brower/\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md"
index ede52201..3b85929f 100644
--- "a/docs/Interview/Brower/\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md"
+++ "b/docs/Interview/Brower/\346\265\217\350\247\210\345\231\250\347\275\221\351\241\265\350\257\267\346\261\202\350\277\207\347\250\213.md"
@@ -158,20 +158,17 @@ reflow 的本质就是重新计算 layout 树。
### 重绘repaint
repaint 的本质就是重新根据分层信息计算了绘制指令。
-
当改动了可见样式后,就需要重新计算,会引发 repaint。
-
由于元素的布局信息也属于可见样式,所以reflow 一定会引起 repaint。
-
+需要更新属性,只是影响元素的外观、风格,不影响布局。(不影响布局的属性,如:color、background-color、visibility 等)
![2023-03-06-22-20-02](https://zerdocs.oss-cn-shanghai.aliyuncs.com/febasis/2023-03-06-22-20-02.png){data-zoomable}
:::details 为什么 transform 的效率高?
因为 transform 既不会影响布局也不会影响绘制指令,它影响的只是渲染流程的最后一个「draw」 阶段由于 draw 阶段在合成线程中;
所以 transform 的变化几乎不会影响渲染主线程。反之,渲染主线程无论如何忙碌.也不会影响 transform 的变化。
-:::
-> 需要更新属性,只是影响元素的外观、风格,不影响布局。改变 `color, background-color, visibility` 等属性
+:::
[参考链接](https://blog.51cto.com/u_15499114/4971560)
diff --git "a/docs/Interview/CSS/\351\235\242\350\257\225\351\242\230\344\270\200.md" "b/docs/Interview/CSS/\351\235\242\350\257\225\351\242\230\344\270\200.md"
index f6295eb9..e83d31e1 100644
--- "a/docs/Interview/CSS/\351\235\242\350\257\225\351\242\230\344\270\200.md"
+++ "b/docs/Interview/CSS/\351\235\242\350\257\225\351\242\230\344\270\200.md"
@@ -177,6 +177,7 @@
**黏性定位**`sticky`:相对于*最近滚动祖先*定位,滚动到元素top小于设定值(top:20px;)则转为固定定位。(relative+fixed)
## `z-index` 不生效
+
1. 父元素没有定位(position: static)时
2. `z-index` 同时设置了 `float`时
@@ -332,8 +333,8 @@ Canvas是一种基于位图的绘图技术,它使用JavaScript在HTML5画布
| `xl` | 1280px | `@media (min-width: 1280px) { ... }` | 小型笔记本 |
| `2xl` | 1536px | `@media (min-width: 1536px) { ... }` | 电脑显示器 |
-
## CSS 工程化
+
1. 预处理器(Sass/Less/Stylus)
2. 模块化(CSS Modules/CSS in JS)
3. 规范化(BEM/OOCSS/SMACSS)
@@ -343,12 +344,14 @@ Canvas是一种基于位图的绘图技术,它使用JavaScript在HTML5画布
7. 代码规范(ESLint/Prettier)
## JS 动画 与 CSS 动画
+
JS动画:
+
1. 优点:兼容性强,写得好可以兼容IE6,控制能力强,可以实现复杂动画。
2. 缺点:性能没有CSS好。
-CSS动画:
- 1. 优点:CSS性能更好,因为CSS动画是通过浏览器渲染引擎来实现的,对CSS3 做了性能优化。
- 2. 缺点: 不能精细化控制,不够灵活,兼容性不好。
+ CSS动画:
+3. 优点:CSS性能更好,因为CSS动画是通过浏览器渲染引擎来实现的,对CSS3 做了性能优化。
+4. 缺点: 不能精细化控制,不够灵活,兼容性不好。
## 实现一个元素的宽高比
diff --git "a/docs/Interview/JavaScript/Promise\347\233\270\345\205\263.md" "b/docs/Interview/JavaScript/Promise\347\233\270\345\205\263.md"
index 29570a47..d930eb41 100644
--- "a/docs/Interview/JavaScript/Promise\347\233\270\345\205\263.md"
+++ "b/docs/Interview/JavaScript/Promise\347\233\270\345\205\263.md"
@@ -60,7 +60,7 @@ function createTask(delay) {
})
}
}
-const task = new taskQueue()
+const task = new TaskQueue()
const times = [100, 2600, 400, 300, 500, 600, 900, 800, 700, 1000]
times.forEach((item) => {
task.addTask(createTask(item))
@@ -156,7 +156,7 @@ worker.terminate()
```js
// 写法 1
-self.addEventListener('message', (e) => {
+globalThis.addEventListener('message', (e) => {
// ...
})
diff --git "a/docs/Interview/JavaScript/\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md" "b/docs/Interview/JavaScript/\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md"
index 020ff492..2a002d24 100644
--- "a/docs/Interview/JavaScript/\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md"
+++ "b/docs/Interview/JavaScript/\345\216\237\345\236\213\344\270\216\345\216\237\345\236\213\351\223\276.md"
@@ -30,9 +30,9 @@ function Star() {
}
const star1 = new Star()
-star1.__proto__ === star1.constructor.prototype
+// star1.__proto__ === star1.constructor.prototype
Star === Start.prototype.constructor
-Object.prototype.__proto__ // null
+// Object.prototype.__proto__ // null
Object instanceof Function // Object顶级对象是 顶级构造器 Fcuntion 的实例
```
@@ -44,7 +44,7 @@ Object instanceof Function // Object顶级对象是 顶级构造器 Fcuntion 的
```js
function test() {}
-test.__proto__ == Function.prototype // ture
+// test.__proto__ == Function.prototype // ture
```
本身 ---> 构造函数.prototype(本身`.__proto__`) ---> 构造函数原型对象的原型`.prototype.__proto__`...--->Object.prototype ---> null
@@ -87,14 +87,14 @@ console.log(o2, o2.name, o2.age)
### 方式三:借用构造函数继承
-```
-function Parent(){
- this.age = 22;
+```js
+function Parent() {
+ this.age = 22
}
-function Child(){
- this.name = '张三'
- Parent.call(this);
+function Child() {
+ this.name = '张三'
+ Parent.call(this)
}
-let o3 = new Child();
-console.log( o3,o3.name,o3.age );
+const o3 = new Child()
+console.log(o3, o3.name, o3.age)
```
diff --git "a/docs/Interview/JavaScript/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md" "b/docs/Interview/JavaScript/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md"
index 90ddfb3e..fe1374ed 100644
--- "a/docs/Interview/JavaScript/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md"
+++ "b/docs/Interview/JavaScript/\345\237\272\347\241\200\351\235\242\350\257\225\351\242\230.md"
@@ -56,8 +56,10 @@ const isObj = option => option !== null && (typeof option === 'object' || typeof
- 最后再把宇符串基于Number方法转换为数字
```js
-parseInt(val,radix) parseFloat(val)
-parseInt(null) 和 parseInt(undefined) -> NaN
+Number.parseInt(val, radix)
+Number.parseFloat(val)
+Number.parseInt(null)
+Number.parseInt(undefined) // -> NaN
/* 规则:val 必须是字符串,不是则自动转为字符串;
然后再 从左往右 找符合 radix(进制)有效数字,一个没找到则返回 NaN,
遇到一个非有效数字字符,则停止查找,并 parseInt(之前符合的字符串) parseInt('12px') -> 12
@@ -102,8 +104,8 @@ const n = a++ // 10(数字) ++a / a++ 一定是数字运算
```js
//题1:
-[] == false -> 0 == 0 -> false
-![] == false -> false == false -> true
+[] == false // -> 0 == 0 -> false
+![] == false // -> false == false -> true
//题2:
var a = ?;
@@ -212,30 +214,36 @@ function debounce(func, delay = 500) {
::: details 防抖拓展写法
```js
-function debounce(func,delay = 500,immediate=false){
- //参数判断处理
- if(typeof func !== 'function') throw new TypeError('func is not a funciton')
- //debounce(func,true)
- if(typeof delay === 'boolean'){
- immediate = delay
- delay = undefined
+function debounce(func, delay = 500, immediate = false) {
+ // 参数判断处理
+ if (typeof func !== 'function')
+ throw new TypeError('func is not a funciton')
+ // debounce(func,true)
+ if (typeof delay === 'boolean') {
+ immediate = delay
+ delay = undefined
}
- isNaN(delay = +delay) ? 500 : delay //若不是数字则默认 500
- if(typeof immediate !== 'boolean') immediate = false
+ delay = +delay
+ Number.isNaN(delay) ? 500 : delay // 若不是数字则默认 500
+ if (typeof immediate !== 'boolean')
+ immediate = false
let timer = null
- return function(...args){
- //第一次自执行完,timer 已经有值,
- let now = !timer && immediate
- if(timer) clearTimeout(timer) //清除上一次
- timer = setTimeout(() =>{
- //结束边界触发
- if(!immediate) func.apply(this,args)
- //清除最后一个定时器
+ return function (...args) {
+ // 第一次自执行完,timer 已经有值,
+ const now = !timer && immediate
+ if (timer)
+ clearTimeout(timer) // 清除上一次
+ timer = setTimeout(() => {
+ // 结束边界触发
+ if (!immediate)
+ func.apply(this, args)
+ // 清除最后一个定时器
timer = clearTimeout(timer)
- },delay)
- //若为立即执行,则第一次,开启边界触发
- if(now) func.apply(this,args)
+ }, delay)
+ // 若为立即执行,则第一次,开启边界触发
+ if (now)
+ func.apply(this, args)
}
}
```
@@ -245,38 +253,40 @@ function debounce(func,delay = 500,immediate=false){
### 节流
```js
-//实现原理:每次触发事件时,判断当前是否存在等待执行的延时函数
-//方法一:定时器存在则什么都不做
-function throttle(func,delay){
+// 实现原理:每次触发事件时,判断当前是否存在等待执行的延时函数
+// 方法一:定时器存在则什么都不做
+function throttle1(func, delay) {
let timer = null
- return function(...args){
- if(timer) return
- timer = setTimeout(()=>{
- func.apply(this,...args)
+ return function (...args) {
+ if (timer)
+ return
+ timer = setTimeout(() => {
+ func.apply(this, ...args)
timer = null
}, delay)
}
}
-//方法二:
-function throttle(func,delay){
- let flag = true //节流阀:开启状态
- return function(...args){
- if(!flag) return
- flag = false //已经在处理:关闭
- setTimeout(() =>{
- func.apply(this,args)
- flag = true //处理完:重新打开
- },delay)
- }
+// 方法二:
+function throttle2(func, delay) {
+ let flag = true // 节流阀:开启状态
+ return function (...args) {
+ if (!flag)
+ return
+ flag = false // 已经在处理:关闭
+ setTimeout(() => {
+ func.apply(this, args)
+ flag = true // 处理完:重新打开
+ }, delay)
}
-//实现三:当前时间-上次执行时间 > 设定时间,才执行
-funtion throttle(func,delay){
+}
+// 实现三:当前时间-上次执行时间 > 设定时间,才执行
+function throttle3(func, delay) {
let start = 0
- return function(...args){
- let now = Data.now()
- if(now - start > delay){
- func.apply(this,args)
- start = now
+ return function (...args) {
+ const now = Data.now()
+ if (now - start > delay) {
+ func.apply(this, args)
+ start = now
}
}
}
@@ -284,9 +294,8 @@ funtion throttle(func,delay){
::: tip 应用
- 防抖:输入框搜索、编辑框实时保存,(手机息屏策略,王者荣耀回城操作)
-
- 节流:滚动到底部加载更多、图标跟随鼠标(地铁发车时间,王者荣耀技能冷却)
+防抖:输入框搜索、编辑框实时保存,(手机息屏策略,王者荣耀回城操作)
+节流:滚动到底部加载更多、图标跟随鼠标(地铁发车时间,王者荣耀技能冷却)
:::
@@ -355,42 +364,39 @@ hw.next(123) // a = 123
### 异步流程同步化
```js
-function* test(){
- let res1 = yield new Promise((resolve) =>{
- setTimeout(function(){
+function* test() {
+ const res1 = yield new Promise((resolve) => {
+ setTimeout(() => {
resolve('第一秒执行')
- },1000)
+ }, 1000)
})
- console.log(res1) //第一秒执行
+ console.log(res1) // 第一秒执行
- let res2 = yield new Promise((resolve) =>{
- setTimeout(function(){
+ const res2 = yield new Promise((resolve) => {
+ setTimeout(() => {
resolve('第二秒执行')
- },1000)
+ }, 1000)
})
}
-function generatorRunner(fn){
- let generator = fn()
- let step = generator.next()
- //定义递归函数
- function loop(stepArg,generator){
- //获取本次 yield 右侧的结果
- let value = stepArg.value
- if(value instanceof Promise){
- //如果是 Promise 对象就在 then 函数的回调中获取本次程序结果
- //并且等待回调执行的时候进入下一次递归
- value.then((function(promiseValue){
- if(!stepArg.done){
- loop(generator.next(promiseValue),generator)
+function generatorRunner(fn) {
+ const generator = fn()
+ const step = generator.next()
+ // 定义递归函数
+ function loop(stepArg, generator) {
+ // 获取本次 yield 右侧的结果
+ const value = stepArg.value
+ if (value instanceof Promise) {
+ // 如果是 Promise 对象就在 then 函数的回调中获取本次程序结果
+ // 并且等待回调执行的时候进入下一次递归
+ value.then((promiseValue) => {
+ if (!stepArg.done) {
+ loop(generator.next(promiseValue), generator)
}
- }
- }else{
- //判断程序没有执行完就将本次结果传入下一步进入下一次递归
- if(!stepArg.done) loop(generator.next(stepArg.value),generator)
- }
+ })
+ }
}
- loop(step,generator)
+ loop(step, generator)
}
```
@@ -419,24 +425,24 @@ function generatorRunner(fn){
浅拷贝
```js
-let newObj = Object.assign({},obj) //只拷贝对象自身的可枚举的属性
-let newObj = [...obj]
+const newObj = Object.assign({}, obj) // 只拷贝对象自身的可枚举的属性
+const newObj1 = [...obj]
-//数组
+// 数组
Array.prototype.slice()
Array.prototype.concat()
-let arr = [
+const arr = [
{
- name:'zhan',
- age:23
+ name: 'zhan',
+ age: 23
},
123,
456
]
-let newArr1 = arr.slice()
-let newArr2 = arr.concat()
-//改变内部的引用类型两者都会有影响
+const newArr1 = arr.slice()
+const newArr2 = arr.concat()
+// 改变内部的引用类型两者都会有影响
```
```js
@@ -454,7 +460,7 @@ function deepClone(obj) {
return new RegExp(obj)
const newObj = Array.isArray(obj) ? [] : {}
for (const key in obj) {
- if (obj.hasOwnProperty(key))
+ if (Object.prototype.hasOwnProperty.call(obj, key))
newObj[key] = deepClone(obj[key])
}
return newObj
diff --git "a/docs/Interview/JavaScript/\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md" "b/docs/Interview/JavaScript/\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md"
index cdf0340c..dafe9401 100644
--- "a/docs/Interview/JavaScript/\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md"
+++ "b/docs/Interview/JavaScript/\345\255\227\347\254\246\344\270\262\345\270\270\347\224\250\346\226\271\346\263\225.md"
@@ -1,6 +1,6 @@
## 字符串常用方法
- **都不会影响原字符串:因为字符串是不可变的!**
+**都不会影响原字符串:因为字符串是不可变的!**
1. 增删改:`replace,replaceAll`
@@ -9,10 +9,10 @@
3. 删:`substr,substring,slice,trim,trimStart,trimEnd`
4. 改:`split,toLowerCase,toUpperCase,toLocaleLowerCase,`
- `toLocaleUpperCase,` `String.fromCharCode()`
+ `toLocaleUpperCase,` `String.fromCharCode()`
5. 查:`valueOf,at,charAt,charCodeAt,indexOf,lastIndexOf,`
- `search,includes,match,startsWith,endsWith`
+ `search,includes,match,startsWith,endsWith`
### charCodeAt与fromCharCode
@@ -32,19 +32,18 @@ String.fromCharCode(65, 66, 67) // 'ABC' 返回 ASCII 码对应的字符
:::
```js {3,4}
-let y = "www.map.baidu.com";
-console.log(y.slice(4,11)); //map.bai
-console.log(y.slice(11,4)); //''
-console.log(y.slice(3,-4)); //.map.baidu
-console.log(y.slice(3,0)); //''
-console.log(y.slice(4)); //map.baidu.com
-
-let y = "www.map.baidu.com";
-console.log(y.substring(4,11)); //map.bai
-console.log(y.substring(11,4)); //map.bai
-console.log(y.substring(3,-4)); //www
-console.log(y.substring(3,0)); //www
-console.log(y.substring(4)); //map.baidu.com
+const y = 'www.map.baidu.com'
+console.log(y.slice(4, 11)) // map.bai
+console.log(y.slice(11, 4)) // ''
+console.log(y.slice(3, -4)) // .map.baidu
+console.log(y.slice(3, 0)) // ''
+console.log(y.slice(4)) // map.baidu.com
+
+console.log(y.substring(4, 11)) // map.bai
+console.log(y.substring(11, 4)) // map.bai
+console.log(y.substring(3, -4)) // www
+console.log(y.substring(3, 0)) // www
+console.log(y.substring(4)) // map.baidu.com
```
### valueOf 与 toString 的异同
diff --git "a/docs/Interview/JavaScript/\347\246\201\346\255\242\344\270\213\350\275\275\345\233\276\347\211\207.md" "b/docs/Interview/JavaScript/\347\246\201\346\255\242\344\270\213\350\275\275\345\233\276\347\211\207.md"
index 6104d2be..c2cefbd1 100644
--- "a/docs/Interview/JavaScript/\347\246\201\346\255\242\344\270\213\350\275\275\345\233\276\347\211\207.md"
+++ "b/docs/Interview/JavaScript/\347\246\201\346\255\242\344\270\213\350\275\275\345\233\276\347\211\207.md"
@@ -1,5 +1,4 @@
-
->怎么禁止下载图片(midjourney实现)
+> 怎么禁止下载图片(midjourney实现)
**方案一:禁止右键**
@@ -43,21 +42,21 @@ window.onload = function () {
**方案四:转换为 canvas**
-```js
-export async function imageToCanvas(url: string, canvas: HTMLCanvasElement) {
+```ts
+export async function imageToCanvas(url, canvas) {
return new Promise((resolve, reject) => {
- //新建Image对象,引入当前目录下的图片
+ // 新建Image对象,引入当前目录下的图片
const img = new Image()
img.src = url
- const c = canvas.getContext('2d')!
+ const c = canvas.getContext('2d')
- //图片初始化完成后调用
+ // 图片初始化完成后调用
img.onload = function () {
- //将canvas的宽高设置为图像的宽高
+ // 将canvas的宽高设置为图像的宽高
canvas.width = img.width
canvas.height = img.height
- //canvas画图片
+ // canvas画图片
c.drawImage(img, 0, 0, img.width, img.height)
resolve()
}
@@ -68,26 +67,24 @@ export async function imageToCanvas(url: string, canvas: HTMLCanvasElement) {
}
```
-```ts
-const throwFn = () => {
+```js
+function throwFn() {
throw new Error(
- "Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.",
+ 'Uncaught DOMException: Failed to execute \'toDataURL\' on \'HTMLCanvasElement\': Tainted canvases may not be exported.',
)
}
-const $canvasRef = useRef(null)
- useEffect(() => {
- ;(async () => {
- await imageToCanvas(props.url, $canvasRef.current!)
- $canvasRef.current!.toBlob = throwFn
- $canvasRef.current!.toDataURL = throwFn
- })()
- }, [])
- return (
-