├── docs
├── js
│ ├── func
│ │ ├── call
│ │ │ ├── index.js
│ │ │ └── index.md
│ │ └── apply
│ │ │ └── index.md
│ ├── node
│ │ └── eventemitter
│ │ │ └── index.md
│ ├── browser
│ │ └── getURLParameters
│ │ │ └── index.md
│ ├── utils
│ │ ├── sleep
│ │ │ ├── index.js
│ │ │ └── index.md
│ │ └── curry
│ │ │ ├── index.js
│ │ │ └── index.md
│ └── array
│ │ ├── forEach
│ │ ├── index.js
│ │ ├── index.test.js
│ │ └── index.md
│ │ ├── map
│ │ ├── index.test.js
│ │ ├── index.js
│ │ └── index.md
│ │ ├── filter
│ │ ├── index.js
│ │ └── index.md
│ │ └── reduce
│ │ ├── index.js
│ │ ├── index.test.js
│ │ └── index.md
├── public
│ ├── CNAME
│ ├── robots.txt
│ ├── logo.png
│ ├── ios-180x180.png
│ ├── pwa-128x128.png
│ ├── pwa-144x144.png
│ ├── pwa-192x192.png
│ ├── pwa-256x256.png
│ ├── pwa-512x512.png
│ └── logo.svg
├── posts
│ ├── this
│ │ └── index.md
│ └── guide
│ │ └── index.md
├── code.png
├── .vitepress
│ ├── theme
│ │ ├── main.scss
│ │ ├── index.js
│ │ └── Layout.vue
│ ├── components
│ │ └── ScrollProgress.vue
│ └── config.js
├── index.md
├── scss
│ └── mixin
│ │ └── index.md
├── vite.config.ts
├── react
│ └── send_code
│ │ └── index.md
└── vue
│ └── scroll_progress_bar
│ └── index.md
├── .gitignore
├── README.md
├── .github
└── workflows
│ └── deploy.yml
├── scripts
└── pwa.ts
├── package.json
├── logo.svg
└── LICENSE
/docs/js/func/call/index.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/public/CNAME:
--------------------------------------------------------------------------------
1 | code.lencx.tech
--------------------------------------------------------------------------------
/docs/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Allow: /
--------------------------------------------------------------------------------
/docs/posts/this/index.md:
--------------------------------------------------------------------------------
1 | # This 关键字详解
2 |
3 | > TODO
4 |
--------------------------------------------------------------------------------
/docs/js/func/apply/index.md:
--------------------------------------------------------------------------------
1 |
2 | # 👉 apply
3 |
4 | > TODO
5 |
--------------------------------------------------------------------------------
/docs/js/node/eventemitter/index.md:
--------------------------------------------------------------------------------
1 | ## 👉 EventEmitter
2 |
3 | > TODO
4 |
--------------------------------------------------------------------------------
/docs/code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencx/code-snippets/HEAD/docs/code.png
--------------------------------------------------------------------------------
/docs/js/browser/getURLParameters/index.md:
--------------------------------------------------------------------------------
1 | # 👉 getURLParameters
2 |
3 | > TODO
4 |
--------------------------------------------------------------------------------
/docs/public/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencx/code-snippets/HEAD/docs/public/logo.png
--------------------------------------------------------------------------------
/docs/public/ios-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencx/code-snippets/HEAD/docs/public/ios-180x180.png
--------------------------------------------------------------------------------
/docs/public/pwa-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencx/code-snippets/HEAD/docs/public/pwa-128x128.png
--------------------------------------------------------------------------------
/docs/public/pwa-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencx/code-snippets/HEAD/docs/public/pwa-144x144.png
--------------------------------------------------------------------------------
/docs/public/pwa-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencx/code-snippets/HEAD/docs/public/pwa-192x192.png
--------------------------------------------------------------------------------
/docs/public/pwa-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencx/code-snippets/HEAD/docs/public/pwa-256x256.png
--------------------------------------------------------------------------------
/docs/public/pwa-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lencx/code-snippets/HEAD/docs/public/pwa-512x512.png
--------------------------------------------------------------------------------
/docs/js/utils/sleep/index.js:
--------------------------------------------------------------------------------
1 | function sleep(ms) {
2 | return new Promise(resolve => setTimeout(resolve, ms));
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
3 | .history
4 |
5 | node_modules
6 | yarn.lock
7 | package-lock.json
8 |
9 | # build
10 | docs/.vitepress/dist
11 |
12 | draft/
13 |
--------------------------------------------------------------------------------
/docs/js/array/forEach/index.js:
--------------------------------------------------------------------------------
1 | Array.prototype.myEach = function(callback) {
2 | for (var i = 0; i < this.length; i++) {
3 | callback(this[i], i, this);
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/docs/js/array/map/index.test.js:
--------------------------------------------------------------------------------
1 | require('./index');
2 |
3 | test('map', () => {
4 | const newData = [1, 2, 3, 4].myMap((item) => item * 2);
5 | expect(newData).toStrictEqual([2, 4, 6, 8]);
6 | })
7 |
--------------------------------------------------------------------------------
/docs/js/array/map/index.js:
--------------------------------------------------------------------------------
1 | Array.prototype.myMap = function(callback) {
2 | arr = [];
3 | for (var i = 0; i < this.length; i++) {
4 | arr[i] = callback(this[i], i, this);
5 | }
6 | return arr;
7 | }
8 |
--------------------------------------------------------------------------------
/docs/js/array/filter/index.js:
--------------------------------------------------------------------------------
1 | Array.prototype.myFilter = function (callback, context) {
2 | var arr = [];
3 | for (var i = 0; i < this.length; i++) {
4 | if (callback.call(context, this[i], i, this)) {
5 | arr.push(this[i]);
6 | }
7 | }
8 | return arr;
9 | };
--------------------------------------------------------------------------------
/docs/js/array/forEach/index.test.js:
--------------------------------------------------------------------------------
1 | require('./index');
2 |
3 | const testData = [1, 2, 3, 4];
4 |
5 | test('forEach', () => {
6 | testData.myEach((item, index, self) => {
7 | expect(item).toBe(testData[index]);
8 | expect(self).toBe(testData);
9 | })
10 | })
11 |
--------------------------------------------------------------------------------
/docs/js/utils/curry/index.js:
--------------------------------------------------------------------------------
1 | function curry(func) {
2 | return function curried(...args) {
3 | if (args.length >= func.length) {
4 | return func.apply(this, args);
5 | }
6 | return function(...args2) {
7 | return curried.apply(this, args.concat(args2));
8 | };
9 | };
10 | }
--------------------------------------------------------------------------------
/docs/posts/guide/index.md:
--------------------------------------------------------------------------------
1 | # 🪧 指南
2 |
3 | ## 类别
4 |
5 | - [Article](../../posts/this/) - 瞎折腾 / 笔记
6 | - [JavaScript](../../js/array/forEach/) - JS 实现系列
7 | - [CSS](../../scss/mixin/) - CSS 实现系列
8 |
9 | ## 参考
10 |
11 | - [[MDN] JavaScript](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript)
12 | - [The Modern JavaScript Tutorial](https://javascript.info)
13 | - [You Don't Know JS Yet (book series) - 2nd Edition](https://github.com/getify/You-Dont-Know-JS)
14 | - [Node.js Docs](https://nodejs.org/zh-cn/docs/)
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [“What I Cannot create, I do not understand”](https://www.quora.com/What-did-Richard-Feynman-mean-when-he-said-What-I-cannot-create-I-do-not-understand) — Richard Feynman
6 |
7 | ---
8 |
9 | ## Features
10 |
11 | - JavaScript
12 | - array
13 | - browser
14 | - function
15 | - node
16 | - object
17 | - utils
18 | - CSS
19 | - mixin
20 | - function
21 |
22 | ## License
23 |
24 | CC0 1.0 License © 2021 [lencx](https://github.com/lencx)
25 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: github pages
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | deploy:
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v2
14 | - uses: actions/setup-node@v2
15 | with:
16 | node-version: '14'
17 | - run: yarn
18 | - run: yarn build
19 |
20 | - name: Deploy
21 | uses: peaceiris/actions-gh-pages@v3
22 | with:
23 | github_token: ${{ secrets.GH_TOKEN }}
24 | publish_dir: ./docs/.vitepress/dist
25 | force_orphan: true
--------------------------------------------------------------------------------
/docs/js/array/reduce/index.js:
--------------------------------------------------------------------------------
1 | Array.prototype.myReduce = function(callback, initialVal) {
2 | // 初始值是一个可选参数
3 | var accumulator = initialVal || undefined;
4 | // TODO: 未处理边界情况,详情可查看 MDN 文档
5 | // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#polyfill
6 | // 1. 如果 callback 为 null 或非 function,则报错
7 | // 2. 如果数组为空,并且不存在初始值,则报错
8 | for (var i = 0; i < this.length; i++) {
9 | if (accumulator) {
10 | accumulator = callback.call(accumulator, accumulator, this[i], i, this);
11 | } else {
12 | accumulator = this[i];
13 | }
14 | }
15 | return accumulator;
16 | }
--------------------------------------------------------------------------------
/docs/.vitepress/theme/main.scss:
--------------------------------------------------------------------------------
1 | :root {
2 | --font-family-base: -apple-system, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
3 | }
4 |
5 | .home-hero {
6 | img {
7 | width: 160px !important;
8 | }
9 | }
10 |
11 | .home-content {
12 | padding: 0 20px !important;
13 | text-align: center;
14 | }
15 |
16 | hr {
17 | margin: 40px 0;
18 | border: none;
19 | border-top: 2px dashed #d8d8d8;
20 | }
21 |
22 | .giscus {
23 | background-color: #f8f8f8;
24 | padding: 20px;
25 | margin-top: 50px;
26 | border-radius: 8px;
27 | border: solid 3px rgba(#000, 0.03);
28 | }
29 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | heroImage: /logo.svg
4 | heroAlt: JS
5 | actionText: 👉 开始探索
6 | tagline: 手写 Code Snippets 系列
7 | # actionText: Get Started
8 | actionLink: /posts/guide/
9 | features:
10 | - title: 瞎折腾 / 笔记
11 | details: 在折腾中学习,在记录中成长
12 | - title: JS 实现系列
13 | details: 包含 Array,Browser,Node.js 等
14 | - title: CSS 实现系列
15 | details: 包含 Animation,Layout,Mixin 等
16 | footer: CC0 1.0 Licensed | Copyright © 2021-present lencx
17 | ---
18 |
19 | [“What I Cannot create, I do not understand”](https://www.quora.com/What-did-Richard-Feynman-mean-when-he-said-What-I-cannot-create-I-do-not-understand) — Richard Feynman
20 |
--------------------------------------------------------------------------------
/docs/js/array/reduce/index.test.js:
--------------------------------------------------------------------------------
1 | require('./index');
2 |
3 | test('reduce', () => {
4 | const indexArr = [];
5 | const newData = [1, 2, 3, 4].myReduce((acc, cur, index) => {
6 | indexArr.push(index);
7 | return acc + cur;
8 | });
9 | expect(newData).toStrictEqual(10);
10 | expect(indexArr).toStrictEqual([1, 2, 3]);
11 | })
12 |
13 | test('reduce initialValue', () => {
14 | const indexArr = [];
15 | const newData = [1, 2, 3, 4].myReduce((acc, cur, index) => {
16 | indexArr.push(index);
17 | return acc + cur;
18 | }, 2);
19 | expect(newData).toStrictEqual(12);
20 | expect(indexArr).toStrictEqual([0, 1, 2, 3]);
21 | })
22 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.js:
--------------------------------------------------------------------------------
1 | import DefaultTheme from "vitepress/theme";
2 | import { watch } from "vue";
3 | import Layout from "./Layout.vue";
4 | import "./main.scss";
5 |
6 | export default {
7 | ...DefaultTheme,
8 | Layout,
9 | enhanceApp({ router }) {
10 | watch(
11 | () => router.route.path,
12 | (path) => {
13 | if (typeof window !== 'undefined') {
14 | const _path = localStorage.getItem("URL_PATH", path);
15 | if (_path !== path) {
16 | localStorage.setItem("URL_PATH", path);
17 | window.location.reload();
18 | }
19 | }
20 | }
21 | );
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/Layout.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/docs/scss/mixin/index.md:
--------------------------------------------------------------------------------
1 | # Mixin
2 |
3 | ## 清除浮动
4 |
5 | ```scss
6 | @mixin clearfix {
7 | &::after {
8 | content: '';
9 | display: table;
10 | clear: both;
11 | }
12 | }
13 | ```
14 |
15 | ## 文本省略
16 |
17 | ```scss
18 | // 单行文本省略
19 | @mixin single-text($width) {
20 | -o-text-overflow: ellipsis;
21 | text-overflow: ellipsis;
22 | overflow: hidden;
23 | white-space: nowrap;
24 | max-width: $width;
25 | }
26 |
27 | // 多行文本省略
28 | @mixin multi-text($width, $row) {
29 | max-width: $width;
30 | overflow: hidden;
31 | text-overflow: ellipsis;
32 | display: -webkit-box;
33 | -webkit-line-clamp: $row;
34 | /*! autoprefixer: off */
35 | -webkit-box-orient: vertical;
36 | }
37 | ```
38 |
--------------------------------------------------------------------------------
/scripts/pwa.ts:
--------------------------------------------------------------------------------
1 | import fg from 'fast-glob'
2 | import fs from 'fs-extra'
3 |
4 | export async function fix() {
5 | const names = await fg('docs/.vitepress/dist/**/*.html', { onlyFiles: true })
6 |
7 | await Promise.all(names.map(async(i) => {
8 | let html = await fs.readFile(i, 'utf-8')
9 |
10 | html = html.replace('',
11 | `
12 |
19 | `).trim()
20 |
21 | await fs.writeFile(i, html, 'utf-8')
22 | }))
23 | }
24 |
25 | fix()
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "code-snippets",
3 | "version": "1.0.0",
4 | "description": "✍️ code snippets - 手写系列",
5 | "author": "lencx ",
6 | "license": "CC0 1.0",
7 | "scripts": {
8 | "dev": "vitepress dev docs",
9 | "build": "vitepress build docs && yarn pwa",
10 | "pwa": "esno scripts/pwa.ts",
11 | "test": "jest",
12 | "watch": "jest --watchAll",
13 | "coverage": "jest --coverage"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "https://github.com/lencx/code-snippets"
18 | },
19 | "homepage": "https://github.com/lencx/code-snippets",
20 | "devDependencies": {
21 | "@vitejs/plugin-vue-jsx": "^1.1.8",
22 | "esno": "^0.9.1",
23 | "jest": "^27.0.6",
24 | "sass": "^1.38.1",
25 | "vite-plugin-pwa": "^0.11.2",
26 | "vitepress": "^0.18.0"
27 | },
28 | "dependencies": {
29 | "@giscus/vue": "^1.0.0"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/docs/js/array/map/index.md:
--------------------------------------------------------------------------------
1 | # 👉 map
2 |
3 | > map() 方法创建一个新数组,其结果是该数组中的每个元素调用一次给定函数后的返回值
4 |
5 | ## 💠 语法
6 |
7 | ```js
8 | var new_array = arr.map(function callback(currentValue[, index[, array]]) {
9 | // Return element for new_array
10 | }[, thisArg])
11 | ```
12 |
13 | - `callback` - 生成新数组元素的函数,接收一至三个参数:
14 | - `currentValue` - 数组中当前正在处理的元素
15 | - `index` [可选] - 正在处理的元素在数组中的索引
16 | - `array` [可选] - 调用 map 方法的数组本身
17 | - `thisArg` [可选] - 当执行回调函数 callback 时,用作 this 的值
18 | - 返回值 - 一个由原数组每个元素执行回调函数的结果组成的新数组
19 |
20 | ## ✍️ 实现
21 |
22 | ```js
23 | Array.prototype.myMap = function(callback) {
24 | arr = [];
25 | for (var i = 0; i < this.length; i++) {
26 | arr[i] = callback(this[i], i, this);
27 | }
28 | return arr;
29 | }
30 | ```
31 |
32 | ## 📌 测试
33 |
34 | ```js
35 | const arr = [1, 2, 3];
36 | const newVal = arr.myMap((i) => Math.pow(i, 2));
37 | console.log(newVal); // [1, 9, 16]
38 | ```
39 |
40 | ---
41 |
42 | ## 🔗 参考
43 |
44 | - [[MDN] Array.prototype.map()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
45 |
--------------------------------------------------------------------------------
/docs/js/array/forEach/index.md:
--------------------------------------------------------------------------------
1 |
2 | # 👉 forEach
3 |
4 | > forEach() 方法对数组的每个元素执行一次给定的函数
5 |
6 | ## 💠 语法
7 |
8 | ```js
9 | arr.forEach(callback(currentValue [, index [, array]])[, thisArg])
10 | ```
11 |
12 | - `callback` - 为数组中每个元素执行的函数,接收一至三个参数:
13 | - `currentValue` - 数组中当前正在处理的元素
14 | - `index` [可选] - 正在处理的元素在数组中的索引
15 | - `array` [可选] - 调用 forEach 方法的数组本身
16 | - `thisArg` [可选] - 当执行回调函数 callback 时,用作 this 的值。
17 | - 返回值 - `undefined`
18 |
19 | ## ⚠️ 注意
20 |
21 | 除了抛出异常以外,没有办法中止或跳出 forEach() 循环
22 |
23 | ## ✍️ 实现
24 |
25 | ```js
26 | Array.prototype.myEach = function(callback) {
27 | for (var i = 0; i < this.length; i++) {
28 | callback(this[i], i, this);
29 | }
30 | }
31 | ```
32 |
33 | ## 📌 测试
34 |
35 | ```js
36 | const arr = ['js', 'css', 'html'];
37 | arr.myEach((item) => console.log(item))
38 | ```
39 |
40 | ---
41 |
42 | ## 🔗 参考
43 |
44 | - [[MDN] NodeList.prototype.forEach()](https://developer.mozilla.org/zh-CN/docs/Web/API/NodeList/forEach)
45 | - [[MDN] Array.prototype.forEach()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
46 |
--------------------------------------------------------------------------------
/docs/js/array/filter/index.md:
--------------------------------------------------------------------------------
1 | # 👉 filter
2 |
3 | > filter() 方法创建一个新数组, 返回符合函数的条件的所有元素。
4 |
5 | ## 💠 语法
6 |
7 | ```js
8 | var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])
9 | ```
10 |
11 | - `callback` - 用来检测数组的每个元素的函数,返回 `true` 表示该元素通过检测,保留元素,`false` 则舍弃,接收一至三个参数:
12 | - `element` - 数组中当前正在处理的元素
13 | - `index` [可选] - 正在处理的元素在数组中的索引
14 | - `array` [可选] - 调用 filter 方法的数组本身
15 | - `thisArg` [可选] - 当执行回调函数 callback 时,用作 this 的值
16 | - 返回值 - 一个新的、由通过检测的元素组成的数组,如果没有任何数组元素通过检测,则返回空数组。
17 |
18 | ## ✍️ 实现
19 |
20 | ```js
21 | Array.prototype.myFilter = function (callback, context) {
22 | var arr = [];
23 | for (var i = 0; i < this.length; i++) {
24 | if (callback.call(context, this[i], i, this)) {
25 | arr.push(this[i]);
26 | }
27 | }
28 | return arr;
29 | };
30 | ```
31 |
32 | ## 📌 测试
33 |
34 | ```js
35 | const arr = [1, 2, 3, 4, 5];
36 | const newVal = arr.myFilter((i) => i > 3);
37 | console.log(newVal); // [4, 5]
38 | ```
39 |
40 | ---
41 |
42 | ## 🔗 参考
43 |
44 | - [[MDN] Array.prototype.filter()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
45 |
--------------------------------------------------------------------------------
/docs/js/func/call/index.md:
--------------------------------------------------------------------------------
1 |
2 | # 👉 call
3 |
4 | > call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数
5 |
6 | ## 💠 语法
7 |
8 | ```js
9 | function.call(thisArg, arg1, arg2, ...)
10 | ```
11 |
12 | ## 🟠 示例
13 |
14 | ```js
15 | function sayHello(message) {
16 | console.log(message, this.name);
17 | }
18 | const obj = {
19 | name: 'lencx'
20 | };
21 | sayHello.call(obj, 'welcome'); // welcome lencx
22 | ```
23 |
24 | 示例输出 `welcome lencx`,以上面例子分析一个调用函数的基本原理,我们就会注意到这些:
25 |
26 | 1. 调用原型函数 `call` 改变了 `this` 的指向。即调用函数变成了 `obj.sayHello`
27 |
28 | ```js
29 | function sayHello(message) {
30 | console.log(message, this.name);
31 | }
32 | const obj = {
33 | name: 'lencx',
34 | sayHello: function(message) {
35 | console.log(message, this.name);
36 | }
37 | };
38 | obj.sayHello('welcome'); // welcome lencx
39 | ```
40 |
41 | 2. 传递给 `sayHello.call` 的任意参数作为 `arg1, arg2, ...` 传递给原始 `sayHello`
42 | 3. 不会对 `obj` 和 `sayHello` 产生副作用。即调用 `call` 不会以任何方式修改原始 `obj` 或 `sayHello`
43 |
44 | ## 🤔 思考
45 |
46 | > TODO
47 |
48 | ## ✍️ 实现
49 |
50 | ```js
51 |
52 | ```
53 |
54 | ## 📌 测试
55 |
56 | ```js
57 |
58 | ```
59 |
60 | ---
61 |
62 | ## 🔗 参考
63 |
--------------------------------------------------------------------------------
/docs/vite.config.ts:
--------------------------------------------------------------------------------
1 | // https://github.com/vuejs/vitepress/issues/241#issuecomment-780167185
2 | import vueJsx from '@vitejs/plugin-vue-jsx'
3 | import { VitePWA } from 'vite-plugin-pwa'
4 |
5 | export default {
6 | plugins: [
7 | vueJsx(),
8 | VitePWA({
9 | outDir: '.vitepress/dist',
10 | registerType: 'autoUpdate',
11 | injectRegister: 'inline',
12 | manifest: {
13 | name: '✍️ >',
14 | short_name: '✍️ >',
15 | theme_color: '#3eaf7c',
16 | icons: [
17 | {
18 | src: '/pwa-128x128.png',
19 | sizes: '128x128',
20 | type: 'image/png',
21 | },
22 | {
23 | src: '/pwa-144x144.png',
24 | sizes: '144x144',
25 | type: 'image/png',
26 | },
27 | {
28 | src: '/pwa-192x192.png',
29 | sizes: '192x192',
30 | type: 'image/png',
31 | },
32 | {
33 | src: '/pwa-256x256.png',
34 | sizes: '256x256',
35 | type: 'image/png',
36 | },
37 | {
38 | src: '/pwa-512x512.png',
39 | sizes: '512x512',
40 | type: 'image/png',
41 | },
42 | ],
43 | },
44 | }),
45 | ]
46 | }
47 |
--------------------------------------------------------------------------------
/docs/js/utils/curry/index.md:
--------------------------------------------------------------------------------
1 | # 👉 curry
2 |
3 | 在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。这个技术由克里斯托弗·斯特雷奇以逻辑学家哈斯凯尔·加里命名的,尽管它是 Moses Schönfinkel 和戈特洛布·弗雷格发明的。
4 |
5 | `柯里化是将一个接受多个参数的函数分解成一系列函数,每个函数只接受一个参数。` 例如:将 `f(a,b,c)` 变换为 `f(a)(b)(c)` 。
6 |
7 | ## ✍️ 实现
8 |
9 | ```js
10 | function curry(func) {
11 | return function curried(...args) {
12 | // 如果参数的数量(args.length)大于或等于原函数中定义的参数数量(func.length),
13 | // 则直接使用 func.apply 将参数传递。
14 | if (args.length >= func.length) {
15 | return func.apply(this, args);
16 | }
17 | // 否则,我们只得到一部分参数,此时还未调用 func,
18 | // 则返回一个新的匿名函数,重新柯里化,提供之前的参数(args)和当前匿名函数参数(args2)。
19 | return function(...args2) {
20 | return curried.apply(this, args.concat(args2));
21 | };
22 | };
23 | }
24 | ```
25 |
26 | ## 📌 测试
27 |
28 | ```js
29 | function sum(a, b, c) {
30 | return a + b + c;
31 | }
32 |
33 | const currySum = curry(sum);
34 |
35 | currySum(1, 2, 3); // 6 - 未柯里
36 | currySum(1)(2)(3); // 6 - 完全柯里
37 | currySum(1)(2, 3); // 6 - 第一个参数柯里
38 | ```
39 |
40 | ---
41 |
42 | ## 🔗 参考
43 |
44 | - [[wiki] 柯里化](https://zh.wikipedia.org/wiki/%E6%9F%AF%E9%87%8C%E5%8C%96)
45 | - [What is 'Currying'?](https://stackoverflow.com/questions/36314/what-is-currying)
46 | - [[javascript.info] currying](https://javascript.info/currying-partials)
47 |
--------------------------------------------------------------------------------
/docs/js/utils/sleep/index.md:
--------------------------------------------------------------------------------
1 | # 👉 sleep
2 |
3 | 指定时间内函数暂停执行。 在 C 或 PHP 等编程语言中,可以调用 `sleep(2)` 使程序暂停 2 秒。 Java 有 `Thread.sleep(2000)`,Python 有 `time.sleep(2)`,Go 有 `time.Sleep(2 * time.Second)`。
4 |
5 | JavaScript 没有原生的休眠功能,但由于引入了 promises(以及 ES2018 中的 `async/await`),我们可以用一种优雅地方式来实现此功能。
6 |
7 | ## ✍️ 实现
8 |
9 | ```js
10 | function sleep(ms) {
11 | return new Promise(resolve => setTimeout(resolve, ms));
12 | }
13 | ```
14 |
15 | ## 📌 测试
16 |
17 | ```js
18 | async function testSleep() {
19 | console.log('Taking a break...');
20 | await sleep(2000);
21 | console.log('Two seconds later, showing sleep in a loop...');
22 |
23 | // Sleep in loop
24 | for (let i = 0; i < 5; i++) {
25 | if (i === 3) await sleep(2000);
26 | console.log(i);
27 | }
28 | }
29 |
30 | testSleep();
31 | ```
32 |
33 | ---
34 |
35 | ## 🔗 参考
36 |
37 | - [What is the JavaScript version of sleep()?](https://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep)
38 | - [[C] sleep(3) - Linux man page](https://linux.die.net/man/3/sleep)
39 | - [[PHP] sleep](https://www.php.net/manual/en/function.sleep.php)
40 | - [[Java] Pausing Execution with Sleep](https://docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html)
41 | - [[Python] time.sleep(secs)](https://docs.python.org/3/library/time.html#time.sleep)
42 | - [[Go] func Sleep](https://pkg.go.dev/time#Sleep)
43 |
--------------------------------------------------------------------------------
/docs/js/array/reduce/index.md:
--------------------------------------------------------------------------------
1 |
2 | # 👉 reduce
3 |
4 | > reduce() 方法对数组中的每个元素执行一次 reducer 函数(升序执行),将其结果汇总为单个返回值
5 |
6 | ## 💠 语法
7 |
8 | ```js
9 | arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
10 | ```
11 |
12 | - `callback` - 为数组中每个元素(如果没有提供 `initialValue` 则使用数组中第一个元素)执行的函数,包含四个参数:
13 | - `accumulator` - 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或 `initialValue`(见于下方)
14 | - `currentValue` - 数组中当前正在处理的元素
15 | - `index` [可选] - 正在处理的元素在数组中的索引,如果提供了 `initialValue`,则起始索引号为 `0`,否则从索引 `1` 起始
16 | - `array` [可选] - 调用 reduce 方法的数组本身
17 | - `initialValue` [可选] - 作为第一次调用 `callback` 函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 `reduce` 将报错。
18 | - 返回值 - 函数累计处理的结果
19 |
20 | ## ✍️ 实现
21 |
22 | ```js
23 | Array.prototype.myReduce = function(callback, initialVal) {
24 | // 初始值是一个可选参数
25 | var accumulator = initialVal || undefined;
26 | // TODO: 未处理边界情况,详情可查看 MDN 文档
27 | // https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#polyfill
28 | // 1. 如果 callback 为 null 或非 function,则报错
29 | // 2. 如果数组为空,并且不存在初始值,则报错
30 | for (var i = 0; i < this.length; i++) {
31 | if (accumulator) {
32 | accumulator = callback.call(accumulator, accumulator, this[i], i, this);
33 | } else {
34 | accumulator = this[i];
35 | }
36 | }
37 | return accumulator;
38 | }
39 | ```
40 |
41 | ## 📌 测试
42 |
43 | ```js
44 | const arr = [1, 2, 3, 4];
45 | const val = arr.myReduce((acc, cur) => acc + cur);
46 | console.log(val) // 10
47 | ```
48 |
49 | ---
50 |
51 | ## 🔗 参考
52 |
53 | - [[MDN] NodeList.prototype.reduce()](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce)
54 |
--------------------------------------------------------------------------------
/docs/react/send_code/index.md:
--------------------------------------------------------------------------------
1 | # 发送验证码
2 |
3 | ## ✍️ 实现
4 |
5 | `SendCode.tsx`
6 |
7 | ```tsx
8 | import React, { FC, useEffect, useRef, useState } from "react";
9 |
10 | function useInterval(callback: () => void, delay: number) {
11 | const savedCallback = useRef(null);
12 | savedCallback.current = callback;
13 |
14 | useEffect(() => {
15 | function tick() {
16 | savedCallback.current();
17 | }
18 | if (delay !== null) {
19 | const id = setInterval(tick, delay);
20 | return () => clearInterval(id);
21 | }
22 | }, [delay]);
23 | }
24 |
25 | export interface SendCodeProps {
26 | time?: number;
27 | onSend?: () => void;
28 | initText?: string;
29 | runText?: (v: string) => string;
30 | endText?: string;
31 | }
32 |
33 | const SendCode: FC = ({ time, onSend, initText, runText, endText }) => {
34 | const [text, setText] = useState(initText);
35 | const [second, setSecond] = useState(0);
36 | const [isRunning, setRunning] = useState(false);
37 |
38 | const handleSend = () => {
39 | setRunning(true);
40 | setText(runText(time));
41 | onSend && onSend();
42 | };
43 |
44 | useInterval(
45 | () => {
46 | const val = second + 1;
47 | if (time === val) {
48 | setSecond(0);
49 | setRunning(false);
50 | setText(endText);
51 | } else {
52 | setSecond(val);
53 | setText(runText(time - val));
54 | }
55 | },
56 | isRunning ? 1000 : null
57 | );
58 |
59 | return (
60 |
63 | );
64 | };
65 |
66 | SendCode.defaultProps = {
67 | time: 60,
68 | initText: '获取验证码',
69 | runText: (v: string) => `${v}秒后重发`,
70 | endText: '重新获取验证码',
71 | };
72 |
73 | export default SendCode;
74 | ```
75 |
76 | ---
77 |
78 | ## 🔗 参考
79 |
80 | - [Making setInterval Declarative with React Hooks](https://overreacted.io/making-setinterval-declarative-with-react-hooks/)
81 |
--------------------------------------------------------------------------------
/docs/.vitepress/components/ScrollProgress.vue:
--------------------------------------------------------------------------------
1 |
89 |
90 |
91 |
92 |
93 |
94 |
101 |
--------------------------------------------------------------------------------
/docs/.vitepress/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | title: '✍️ >',
3 | base: '/',
4 |
5 | head: [
6 | ['link', { rel: 'icon', href: '/logo.svg' }],
7 | // https://stackoverflow.com/questions/49568333/pwa-icons-are-not-used-in-ios-11-3
8 | ['link', { rel: 'apple-touch-icon', size: '180x180', href: '/ios-180x180.png' }],
9 | ['meta', { name: 'apple-mobile-web-app-capable', content: 'yes' }],
10 | ['meta', { name: 'apple-mobile-web-app-status-bar-style', content: 'black' }],
11 | ['meta', { name: 'msapplication-TileColor', content: '#3eaf7c' }],
12 | ['meta', { name: 'viewport', content: 'width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover' }],
13 | ['meta', { name: 'author', content: 'lencx' }],
14 | ['meta', { property: 'og:title', content: 'Code Snippets' }],
15 | ['meta', { property: 'og:image', content: 'https://code.lencx.tech/logo.png' }],
16 | ['meta', { property: 'og:description', content: '✍️ code snippets - 手写系列' }],
17 | ['meta', { name: 'twitter:card', content: 'summary_large_image' }],
18 | ['meta', { name: 'twitter:image', content: 'https://code.lencx.tech/logo.png' }],
19 | ],
20 |
21 | themeConfig: {
22 | docsDir: 'docs',
23 | repo: 'lencx/code-snippets',
24 | repoLabel: '点 ⭐️ 不迷路',
25 | docsBranch: 'main',
26 | editLinks: true,
27 | editLinkText: 'Edit this page',
28 | lastUpdated: 'Last Updated',
29 |
30 | nav: [
31 | { text: 'Article', link: '/posts/guide/', activeMatch: '^/posts/' },
32 | { text: 'JavaScript', link: '/js/array/forEach/', activeMatch: '^/js/' },
33 | { text: 'React', link: '/react/send_code/', activeMatch: '^/react/' },
34 | { text: 'Vue', link: '/vue/scroll_progress_bar/', activeMatch: '^/vue/' },
35 | { text: 'CSS', link: '/scss/mixin/', activeMatch: '^/s?css/' },
36 | ],
37 |
38 | sidebar: {
39 | '/posts/': getPosts(),
40 | '/js/': getJS(),
41 | '/react/': getReact(),
42 | '/vue/': getVue(),
43 | '/css/': getCss(),
44 | '/scss/': getCss(),
45 | }
46 | }
47 | }
48 |
49 | function getPosts() {
50 | return [
51 | { text: 'Guide', link: '/posts/guide/' },
52 | {
53 | text: 'Article',
54 | // collapsable: true,
55 | children: [
56 | { text: 'This 关键字详解', link: '/posts/this/' },
57 | ],
58 | }
59 | ]
60 | }
61 |
62 | function getJS() {
63 | return [
64 | {
65 | text: 'Array',
66 | children: [
67 | { text: 'forEach', link: '/js/array/forEach/' },
68 | { text: 'map', link: '/js/array/map/' },
69 | { text: 'filter', link: '/js/array/filter/' },
70 | { text: 'reduce', link: '/js/array/reduce/' },
71 | ],
72 | },
73 | {
74 | text: 'Function',
75 | children: [
76 | { text: 'call', link: '/js/func/call/' },
77 | { text: 'apply', link: '/js/func/apply/' },
78 | ],
79 | },
80 | {
81 | text: 'Node.js',
82 | children: [
83 | { text: 'Event Emitter', link: '/js/node/eventemitter/' },
84 | ],
85 | },
86 | {
87 | text: 'Utils',
88 | children: [
89 | { text: 'curry', link: '/js/utils/curry/' },
90 | { text: 'sleep', link: '/js/utils/sleep/' },
91 | ],
92 | },
93 | {
94 | text: 'Browser',
95 | children: [
96 | { text: 'getURLParameters', link: '/js/browser/getURLParameters/' },
97 | ],
98 | }
99 | ]
100 | }
101 |
102 | function getReact() {
103 | return [
104 | {
105 | text: 'React',
106 | children: [
107 | { text: 'SendCode', link: '/react/send_code/' },
108 | ],
109 | },
110 | ]
111 | }
112 |
113 | function getVue() {
114 | return [
115 | {
116 | text: 'Vue3',
117 | children: [
118 | { text: 'ScrollProgress', link: '/vue/scroll_progress_bar/' },
119 | ],
120 | },
121 | ]
122 | }
123 |
124 | function getCss() {
125 | return [
126 | // {
127 | // text: 'CSS',
128 | // children: [],
129 | // },
130 | {
131 | text: 'SCSS',
132 | children: [
133 | { text: 'Mixin', link: '/scss/mixin/' },
134 | ],
135 | },
136 | ]
137 | }
--------------------------------------------------------------------------------
/docs/public/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/vue/scroll_progress_bar/index.md:
--------------------------------------------------------------------------------
1 | # 滚动进度条
2 |
3 | 创建一个进度条,用来指示页面滚动百分比,主要有两点注意事项及一个思考:
4 |
5 | - 使用 `position: fixed` 将滚动进度条置于页面顶部,`z-index` 设置一个较大的值是为了保证元素在页面内容的最上层。
6 | - 使用 `EventTarget.addEventListener()` 和 `Element.scrollTop` 来确定文档的滚动百分比并将其设置为滚动进度条的宽度。
7 | - 思考 - 如果页面容器高度发生变化,会发生什么?
8 |
9 | ## 💠 核心
10 |
11 | ```html
12 |
13 | ```
14 |
15 | ```css
16 | #scroll_progress_bar {
17 | position: fixed;
18 | top: 0;
19 | width: 0%;
20 | height: 4px;
21 | background: #7983ff;
22 | z-index: 10000;
23 | }
24 | ```
25 |
26 | ```js
27 | const scrollProgress = document.getElementById('scroll_progress_bar');
28 | // 滚动条高度
29 | const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
30 |
31 | window.addEventListener('scroll', () => {
32 | const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
33 | // 当前进度条进度 = 当前滚动条位置 / 滚动条高度
34 | scrollProgress.style.width = `${(scrollTop / height) * 100}%`;
35 | });
36 | ```
37 |
38 | ## ✍️ 实现
39 |
40 | `ScrollProgress.vue`
41 |
42 | ```vue
43 |
140 |
141 |
142 |
143 |
144 |
145 |
152 | ```
153 |
154 | ---
155 |
156 | ## 🔗 参考
157 |
158 | - [[MDN] Document: scroll event](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/scroll_event) - 文档视图或者一个元素在滚动时,会触发元素的scroll事件。
159 | - [[MDN] MutationObserver](https://developer.mozilla.org/zh-CN/docs/Web/API/MutationObserver) - 接口提供了监视对 `DOM树` 所做更改的能力。它被设计为旧的 `Mutation Events` 功能的替代品,该功能是 `DOM3 Events` 规范的一部分。
160 | - [Vue3 API](https://v3.vuejs.org/)
161 | - [props](https://v3.vuejs.org/api/options-data.html#props)
162 | - [\